Reputation: 61
I am recording from a multichannel audio device using pyaudio and struggle saving each channel in a separate file. I use pyaudio since I am playing back audio simultaneously with the recording, and both use different audio devices. It works fine saving to one file, which is then a multichannel wave file. As a second step, but this is probably a smaller problem, I want to save using Float32, which is not supported by the wave module, so currently I use Int24 instead. Seems for Float32 I should use soundfile. I guess this would not influence the way I split up my recording before saving, or does it?
Here my relevant code parts:
import pyaudio
import wave
sample_format = pyaudio.paInt24 # will need to change later to Float32
fs = 48000
chunk = 1024
rec_stream = p.open(format=sample_format,
channels=channels_in, # usually 6
rate=fs,
frames_per_buffer=chunk,
input=True,
input_device_index=recdevice)
# recording and playback simultaneously from different devices
while len(playdata := wf_play.readframes(chunk)):
play_stream.write(playdata)
data = rec_stream.read(chunk)
frames.append(data)
# saving as multichannel file
wf_rec = wave.open(filename, 'wb')
wf_rec.setnchannels(channels_in)
wf_rec.setsampwidth(p.get_sample_size(sample_format))
wf_rec.setframerate(fs)
wf_rec.writeframes(b''.join(frames))
wf_rec.close()
My test recording is 6s long, and from this I see the following: My frames variable is a list of byte object, each the size of chunkchannel_in3. 3 bytes is for Int24 format (for Float32 it would be 4). In the list are duration*fs/chunk elements.
So, how do I unfold frames correctly to one channel each? I tried unfolding it using np.reshape, but didn't figure it out how the channels are interleaved.
Upvotes: 0
Views: 488
Reputation: 61
Figured it out by myself, to insert after the recording while-loop and replacing the saving with wave by soundfile:
import soundfile as sf
all_channels = np.frombuffer(b''.join(frames), dtype=np.float32)
all_channels = all_channels.reshape(-1, channels_in)
for i in range(channels_in):
filename = str(i+1)
sf.write(filename, all_channels[:,i], fs, 'FLOAT')
Upvotes: 0