I am trying to get a stream of 24-bit audio samples from some USB audio device using Python. I already searched for some solutions and found this thread that is using PyAudio stream with a format of pyaudio.paInt24, unfortunately I still got 16-bit samples. I tried to record with PyAudio stream and save with WAVE, sample code:
def initialize(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=self.format, # pyaudio.paInt24
channels=self.channels, # 1
rate=self.fs, # 16000
input=True,
input_device_index=self.input_device_index,
frames_per_buffer=self.chunk) # 1024
def run(self):
frames = []
for _ in range(0, int(self.fs / self.chunk * self.duration)):
data = self.stream.read(self.chunk)
frames.append(data)
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
# write recording to a WAV file
wf = wave.open(self.recorded_file, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(self.p.get_sample_size(self.format))
wf.setframerate(self.fs)
wf.writeframes(b''.join(frames))
wf.close()
I also tried the same the SoundDevice, sample code:
def initialize(self):
sd.default.samplerate = self.fs # 16000
sd.default.channels = self.channels # 1
sd.default.device = self.input_device_index
def run(self):
data = sd.rec(int(self.duration * self.fs), dtype=np.int32)
sd.wait()
# Save file
wf = wave.open(self.recorded_file, 'wb')
wf.setnchannels(self.channels)
wf.setsampwidth(3)
wf.setframerate(self.fs)
wf.writeframes(b''.join(data))
In order to make sure that the problem occurs when receiving the samples and not while saving them, I made sure that a 24-bit audio file can indeed be saved with WAVE, using this sample code:
import wave
with wave.open(path_to_file_to_read, mode='rb') as rb:
white_noise = rb.readframes(rb.getframerate())
with wave.open(path_to_file_to_save+'_save_with_wave.wav', mode='wb') as wb:
wb.setnchannels(rb.getnchannels())
wb.setsampwidth(rb.getsampwidth())
wb.setnframes(rb.getnframes())
wb.setframerate(rb.getframerate())
wb.writeframesraw(white_noise)
Also, I put a break point right after the recording was finished to take a look on the recorded samples and I see that it looks like 16-bit: I will note that in order to make sure that the USB audio device does send me the 24-bit samples I did a recording using Audacity and indeed I got 24-bit, for some reason I can not do anything similar with Python.
Is there a simple way to record 24-bit samples using Python code?
Both PyAudio and SoundDevice use portaudio bindings between some windows sound architecture and python. PortAudio does not suppport full depth 24 bit, and the result is 16 bit of audio with additional 8 zero bits. SoundCard supports 24 bit - https://soundcard.readthedocs.io/en/latest/
In order to get real 24 bit samples, you can use the following:
import soundcard as sc
import soundfile as sf
FS = 16000
TIME_IN_SEC = 5
FRAMES = FS * TIME_IN_SEC
DEVICE_NAME = 'default'
FILE_PATH = 'abc.wav'
# get device
audio_device = sc.get_microphone(DEVICE_NAME)
# receive samples
data = audio_device.record(samplerate=FS, numframes=FRAMES)
# write recording to a WAV file
sf.write(FILE_PATH, data, FS, subtype='PCM_24')