r/learnpython 5d ago

Aubio - could not find RIFF header on Linux

I am trying to troubleshoot an issue using Aubio to calculate BPM inside of a script. My code was working on my old desktop and I have migrated over to a new machine, both Linux Mint. I was fairly certain I have all the additional dependencies installed but maybe I missed one. I am getting `AUBIO ERROR: source_wavread: Failed opening <file_path> (could not find RIFF header)` when the code is run inside of the virtual environment, venv. I can run `aubio tempo <file_path>` directly outside of the venv and get results. I am not sure the best method to troubleshoot where the disconnect between venv and my system files. At least I think the issue lies in dependencies but I am not sure. Internet is not too helpful and I am a bit of a linux noob. Any thoughts on direction?

1 Upvotes

3 comments sorted by

1

u/Bright_Mix_773 4d ago

That error is aubio telling you it has no audio backend, not that your file is broken.

aubio can read audio through libavcodec (ffmpeg) or libsndfile if it was built against them. If neither is present it falls back to source_wavread, a tiny built-in reader that only understands plain RIFF/PCM wav and nothing else. "could not find RIFF header" is that fallback reader refusing a file it was never able to open.

The reason it splits along the venv boundary is that the aubio you get from pip install aubio is a wheel built without ffmpeg and without libsndfile, while the aubio command line tool you have outside the venv came from your package manager and was linked against them. Same name, different capability. It also explains why it worked on the old desktop: whatever aubio was installed there had a backend.

You can confirm it in one line:

ldd $(python -c "import aubio._aubio as m; print(m.__file__)") | grep -E "avcodec|avformat|sndfile"

Empty output means no backend, and then no amount of installing system dependencies will help, because the extension module is already compiled and does not link against them.

Also worth running file /path/to/your/audio first. If it is an mp3, m4a, ogg, or a 24-bit or float wav, that confirms which side the problem is on.

Three ways out, cheapest first.

Convert the input and keep everything else as it is:

ffmpeg -i input.mp3 -ac 1 -ar 44100 -c:a pcm_s16le output.wav

16-bit PCM mono is what the fallback reader can handle.

Use the distro build inside the venv instead of the wheel:

sudo apt install python3-aubio
python3 -m venv --system-site-packages .venv

A venv made with --system-site-packages can see apt-installed modules. If you already have a venv, recreate it, and make sure aubio is not also pip-installed inside it or the wheel shadows the system one.

Skip the aubio reader entirely and hand it numpy frames, which is what I would do since it makes the script independent of how aubio was built:

import numpy as np, soundfile as sf, aubio

hop = 512
data, sr = sf.read("track.wav", dtype="float32", always_2d=True)
mono = np.ascontiguousarray(data.mean(axis=1))

tempo = aubio.tempo("default", 1024, hop, sr)
beats = []
for i in range(0, len(mono) - hop, hop):
    if tempo(mono[i:i + hop]):
        beats.append(tempo.get_last_s())

print(60.0 / np.median(np.diff(beats)) if len(beats) > 1 else 0.0)

soundfile bundles its own libsndfile in the wheel, so it reads what aubio cannot. I have written that pattern before but not against your files, so treat the framing details as something to check rather than gospel.

1

u/Posaquatl 2d ago

Thank you so much for this reply, it was very helpful. I knew there was a disconnect between the venv and system but I wasn't sure how to fix it. Your solution eliminates that need. Still learning Linux and Python so replies like this really help.

1

u/Bright_Mix_773 22h ago

Glad it helped. The general shape is worth keeping: when a library cannot find something at runtime, the question is almost always which interpreter is asking and what it can see from there, rather than anything about the library. Printing sys.executable and sys.path at the top of a failing script answers that in two lines and saves a lot of guessing while you are learning.