spatialaudio / python-sounddevice

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

Callback stream with libpd? #215

Open jonathanpiper opened 4 years ago

jonathanpiper commented 4 years ago

Apologies in advance for what might be a very elementary sort of question! I'm trying to use Sounddevice to play audio coming from a Pure Data patch wrapped in libpd. I've been using PyAudio in Python 2.7, but am trying to bring everything up to 3.7. As of now, I get audio from Sounddevice but with a couple of caveats: the quality of audio is considerably different, and I don't seem to get any apparent changes in volume (probably causing the first issue). The patch I'm working with is a pedagogical tool on synthesis, and includes variable amplitude for waves, amplitude envelopes, and an LFO modulating amplitude - none of these have an effect. Waves are either fully on or fully off.

My callback function currently looks like this:

def pd_callback(outdata, frames, time, status):
    outp = m.process(data)
    t = np.frombuffer(outp, dtype='int16')
    outdata[:] = t.reshape(64, 1)

Admittedly that's a mashup of my callback from PyAudio and what I found in the Sounddevice examples. I'm not familiar with the ins and outs of NumPy, so I'm not sure if I'm somehow ruining the data through these various conversions.

I'm not sure what additional information would be relevant here, so please let me know what else would be needed to help diagnose any potential issues. Any input is SINCERELY appreciated. Thank you!

Playing around a bit more, I'm feeling almost like I have something like this happening: https://github.com/spatialaudio/python-sounddevice/issues/183 That is, if the total amplitude is being boosted to some incredible degree, changes in amplitude would all start to sound like on/off...

jonathanpiper commented 4 years ago

Rather than continuing to edit and hack my original post: I'm able to get my desired result by dividing t by a fairly large value, e.g. 10,000. That lets all the amplitude-related effects work. However, I have no idea WHY that's the case. Can anyone please help my understand that? Thank you!

mgeier commented 4 years ago

You should be able to directly translate your PyAudio code. But since PyAudio doesn't use NumPy arrays, you should probably use RawStream (or RawOutputStream).

If you don't need NumPy, you don't have to use it.

But either way you should be aware which data type you are using for the audio samples. You can select this when starting the stream (which you didn't show in your code above).

If you provide your old code and your new code, I can probably help finding the problems.

jonathanpiper commented 4 years ago

Thanks so much for responding Matthias. The data type definition in the OutputStream call seems to have been the issue exactly. The device was defaulting to float32. Switching to int16 throughout has the volume behaving as expected. I wish I had looked a bit more closely at the API documentation... Thank you again!!

mgeier commented 4 years ago

Good to hear that it works now!

I'm wondering why you are using int16 in the first place? I would assume that libpd supports 32-bit floats?