Last active
April 12, 2024 11:43
-
-
Save sloria/5693955 to your computer and use it in GitHub Desktop.
WAV recording functionality using pyaudio
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
'''recorder.py | |
Provides WAV recording functionality via two approaches: | |
Blocking mode (record for a set duration): | |
>>> rec = Recorder(channels=2) | |
>>> with rec.open('blocking.wav', 'wb') as recfile: | |
... recfile.record(duration=5.0) | |
Non-blocking mode (start and stop recording): | |
>>> rec = Recorder(channels=2) | |
>>> with rec.open('nonblocking.wav', 'wb') as recfile2: | |
... recfile2.start_recording() | |
... time.sleep(5.0) | |
... recfile2.stop_recording() | |
''' | |
import pyaudio | |
import wave | |
class Recorder(object): | |
'''A recorder class for recording audio to a WAV file. | |
Records in mono by default. | |
''' | |
def __init__(self, channels=1, rate=44100, frames_per_buffer=1024): | |
self.channels = channels | |
self.rate = rate | |
self.frames_per_buffer = frames_per_buffer | |
def open(self, fname, mode='wb'): | |
return RecordingFile(fname, mode, self.channels, self.rate, | |
self.frames_per_buffer) | |
class RecordingFile(object): | |
def __init__(self, fname, mode, channels, | |
rate, frames_per_buffer): | |
self.fname = fname | |
self.mode = mode | |
self.channels = channels | |
self.rate = rate | |
self.frames_per_buffer = frames_per_buffer | |
self._pa = pyaudio.PyAudio() | |
self.wavefile = self._prepare_file(self.fname, self.mode) | |
self._stream = None | |
def __enter__(self): | |
return self | |
def __exit__(self, exception, value, traceback): | |
self.close() | |
def record(self, duration): | |
# Use a stream with no callback function in blocking mode | |
self._stream = self._pa.open(format=pyaudio.paInt16, | |
channels=self.channels, | |
rate=self.rate, | |
input=True, | |
frames_per_buffer=self.frames_per_buffer) | |
for _ in range(int(self.rate / self.frames_per_buffer * duration)): | |
audio = self._stream.read(self.frames_per_buffer) | |
self.wavefile.writeframes(audio) | |
return None | |
def start_recording(self): | |
# Use a stream with a callback in non-blocking mode | |
self._stream = self._pa.open(format=pyaudio.paInt16, | |
channels=self.channels, | |
rate=self.rate, | |
input=True, | |
frames_per_buffer=self.frames_per_buffer, | |
stream_callback=self.get_callback()) | |
self._stream.start_stream() | |
return self | |
def stop_recording(self): | |
self._stream.stop_stream() | |
return self | |
def get_callback(self): | |
def callback(in_data, frame_count, time_info, status): | |
self.wavefile.writeframes(in_data) | |
return in_data, pyaudio.paContinue | |
return callback | |
def close(self): | |
self._stream.close() | |
self._pa.terminate() | |
self.wavefile.close() | |
def _prepare_file(self, fname, mode='wb'): | |
wavefile = wave.open(fname, mode) | |
wavefile.setnchannels(self.channels) | |
wavefile.setsampwidth(self._pa.get_sample_size(pyaudio.paInt16)) | |
wavefile.setframerate(self.rate) | |
return wavefile |
Thank you! This made it so much easier for me :) The only thing that I added is an additional argument called "device" to select the audio source.
thanks to you i made my work too easily.
thank you very much!!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am looking for record multiple channels in to multiple .WAV, I can do that with numpy, specific select the rows.
However, I am not sure if I can apply non-blocking with that. as I am not able to using stream.read for non-blocking, right?