Unable to load m4a files with librosa.load() in streamlit run

Summary

I can’t get the result when I try to load an m4a file with librosa.load().
There is no problem with the backend because I was able to load it in the Python interpreter.

Steps to reproduce

Code snippet:

import streamlit as st
import librosa as rosa
import pandas as pd
import numpy as np

uploaded_files = st.file_uploader("audio file", accept_multiple_files=True)

for uploaded_file in uploaded_files:
    st.write("filename:", uploaded_file.name)
    wave, sr = rosa.load(uploaded_file, sr=None)
    times = pd.Index(np.array(range(len(wave))) / sr, name="time(sec)")
    ts = pd.Series(wave, index=times, name=str(uploaded_file))
    st.write(ts)

I ran streamlit run app.py

Expected behavior:
I ran the code below in the python interpreter.

import librosa as rosa
import pandas as pd
import numpy as np
import pathlib

print("audio check")

cwd = pathlib.Path.cwd()
uploaded_files = sorted(cwd.glob("*.m4a"))

for uploaded_file in uploaded_files:
    print("filename:", uploaded_file.name)
    wave, sr = rosa.load(uploaded_file, sr=None)
    times = pd.Index(np.array(range(len(wave))) / sr, name="time(sec)")
    ts = pd.Series(wave, index=times, name=str(uploaded_file))
    print(ts)

And I got the audio data, although I got the warning.

(streamlit-ion-py3.10) > python m4atest.py
audio check
filename: audio.m4a
C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\m4atest.py:13: UserWarning: PySoundFile failed. Trying audioread instead.
  wave, sr = rosa.load(uploaded_file, sr=None)
C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\librosa\core\audio.py:184: FutureWarning: librosa.core.audio.__audioread_load
        Deprecated as of librosa version 0.10.0.
        It will be removed in librosa version 1.0.
  y, sr_native = __audioread_load(path, offset, duration, dtype)
time(sec)
0.000000    -0.007385
0.000063     0.001892
0.000125     0.009735
0.000188     0.009766
0.000250     0.006409
               ...
20.671688    0.000031
20.671750    0.000000
20.671813    0.000031
20.671875    0.000122
20.671937    0.000092
Name: C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\audio.m4a, Length: 330752, dtype: float32

Actual behavior:

(streamlit-ion-py3.10) > streamlit run app.py

  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.2.107:8501

2023-05-25 19:03:15.284 Uncaught app exception
Traceback (most recent call last):
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\streamlit\runtime\scriptrunner\script_runner.py", line 565, in _run_script
    exec(code, module.__dict__)
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\app.py", line 10, in <module>
    wave, sr = rosa.load(uploaded_file, sr=None)
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\librosa\core\audio.py", line 186, in load  
    raise exc
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\librosa\core\audio.py", line 176, in load  
    y, sr_native = __soundfile_load(path, offset, duration, dtype)
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\librosa\core\audio.py", line 209, in __soundfile_load
    context = sf.SoundFile(path)
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\soundfile.py", line 658, in __init__       
    self._file = self._open(file, mode_int, closefd)
  File "C:\Users\j_har\Documents\Projects\NT-100\Streamlit_ion\.venv\lib\site-packages\soundfile.py", line 1216, in _open
    raise LibsndfileError(err, prefix="Error opening {0!r}: ".format(self.name))
soundfile.LibsndfileError: Error opening UploadedFile(id=1, name='audio.m4a', type='audio/mp4', size=43820): Format not recognised.

Debug info

  • Streamlit version: 1.21.0
  • Python version: 3.10.11
  • Using Poetry (version 1.4.2)
  • OS version: Windows 10
  • Browser version: Firefox 113.0.2

Requirements file

[tool.poetry]
name = "streamlit-ion"
version = "0.1.0"
description = ""
readme = "README.md"
packages = [{include = "streamlit_ion"}]

[tool.poetry.dependencies]
python = "^3.10"
streamlit = "^1.21.0"
librosa = "^0.10.0.post2"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

Links

Instead of

try with

import streamlit as st
import librosa as rosa
import pandas as pd
import numpy as np
from tempfile import NamedTemporaryFile

st.title("異音チェッカー シミュレーション")

uploaded_files = st.file_uploader(
    "OKデータのオーディオファイルをアップロードしてください", accept_multiple_files=True
)

for uploaded_file in uploaded_files:
    st.write("filename:", uploaded_file.name)
    with NamedTemporaryFile() as f:
        f.write(uploaded_file.read())
        wave, sr = rosa.load(f.name, sr=None)
    
    times = pd.Index(np.array(range(len(wave))) / sr, name="time(sec)")
    ts = pd.Series(wave, index=times, name=str(uploaded_file))
    st.write(ts)


Details:
that looks like a problem from the librosa package on how it handles paths and file-like objects. You can replicate the exception you see on streamlit when you try passing a BytesIO object to librosa.load(), which it’s supposedly supported but leads to different behavior.

import librosa as rosa
import pandas as pd
import numpy as np
import pathlib

print("audio check")

cwd = pathlib.Path.cwd()
uploaded_files = sorted(cwd.glob("*.m4a"))

for uploaded_file in uploaded_files:
    with open(uploaded_file, 'rb') as f:
        wave, sr = rosa.load(f, sr=None)
        times = pd.Index(np.array(range(len(wave))) / sr, name="time(sec)")
        ts = pd.Series(wave, index=times, name=str(uploaded_file))
        print(ts)

The proposed fix is to write the BytesIO object obtained from st.file_uploader into a temporal file, so librosa.load() is tricked into treating that as a path.

Thank you for your response.
I tried your code, but it throws a PermissionError with NamedTemporaryFile() on Windows.
After further research, I discovered that using TemporaryDirectory() resolves the issue.
I was able to load m4a files successfully.

import streamlit as st
import librosa as rosa
import pandas as pd
import numpy as np
from tempfile import TemporaryDirectory
from pathlib import Path

st.title("異音チェッカー シミュレーション")

uploaded_files = st.file_uploader(
    "OKデータのオーディオファイルをアップロードしてください", accept_multiple_files=True
)

for uploaded_file in uploaded_files:
    st.write("filename:", uploaded_file.name)
    with TemporaryDirectory() as temp_dir:
        temp_file_path = Path(temp_dir, uploaded_file.name)
        temp_file_path.write_bytes(uploaded_file.read())
        wave, sr = rosa.load(temp_file_path, sr=None)
    times = pd.Index(np.array(range(len(wave))) / sr, name="time(sec)")
    ts = pd.Series(wave, index=times, name=uploaded_file.name)
    st.write(ts)
1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.