spatialaudio / python-sounddevice

:sound: Play and Record Sound with Python :snake:
https://python-sounddevice.readthedocs.io/
MIT License
980 stars 145 forks source link

Reliably avoid audio pop/glitch at start/end of stream #455

Closed timlod closed 1 year ago

timlod commented 1 year ago

Hi, thanks for this package, which I'm currently using to prototype a pet project loop machine!

One thing that I haven't been able to avoid is an audible pop whenever I start/stop an OutputStream:

stream = sd.OutputStream(
            samplerate=96000,
            device="default",
            channels=1,
            callback=self._get_callback(),
            blocksize=512
)

I'm currently playing a simple sine sweep, at the start and end of which I've put a fade-in/out of 5ms. There's no pop when looping, but often when starting, and always when stopping playback.

When stopping, I also only raise sd.CallbackStop after executing callbacks which run a fade-out of 5ms, yet there's still an audible pop. The code is a bit lengthy, but in principle the last code called inside the callback will look somewhat like this:

# Let's assume blocksize is large enough for the fade-out to be long enough to eliminate pop
# In reality, this operation is spread out over multiple callbacks
outdata[:] *= np.linspace(1, 0, blocksize)
raise sd.CallbackStop()

So the last outdata I can print before execution stops clearly shows the fade-out is applied, which makes me think that perhaps the last buffer isn't playing, or there's an extra/non-empty buffer playing after, which I don't have control over.

Any ideas what this could be?

mgeier commented 1 year ago

Did you try different host APIs and different (virtual) devices?

I have experienced clicks when starting/stopping streams on Linux, depending on the chosen device.

If that's it, I think that's a deeper problem that cannot be solved from the Python side.

It might even be a hardware issue, maybe some kind of DC offset that you hear when starting/stopping the stream?

In general, I would recommend that you decouple the start of the stream from the start of your sound playback. If you start the stream at application startup (or after device selection), the artifact might be less annoying.

If there is still a glitch when you start your playback while the stream has already been running, you should check the status flags. And if those are fine, the problem is most likely in your signal generation.

timlod commented 1 year ago

I did try different devices, and I think you're right that it probably depends on host API/device. It's definitely better with one of the audio interfaces I tried, all else being equal (although still sometimes noticeable).

I already decoupled the start of the stream from the start of the sound playback for the most important cases, which does help. I guess I'll just have to live with the general issue, or mitigate as much as possible.

Thanks!