import pyaudio as pa from pathlib import Path class Recording: def __init__(self, frames: [], channels: int, samplingRate: int, sampleFormat: int): self._frames = frames self._channels = channels self._samplingRate = samplingRate self._sampleFormat = sampleFormat def writeWav(self, file: Path) -> None: import wave with wave.open(str(file), "wb") as wf: wf.setnchannels(self._channels) wf.setsampwidth(self._sampleFormat) wf.setframerate(self._samplingRate) wf.writeframes(b''.join(self._frames)) def writeMp3(self, file: Path) -> None: from pydub import AudioSegment segment = AudioSegment( data=b''.join(self._frames), sample_width=self._sampleFormat, frame_rate=self._samplingRate, channels=self._channels ) segment.export(str(file), format="mp3", bitrate="320k") class Recorder: def __init__(self, bufferSize: int, samplingRate: int): self._bufferSize = bufferSize self._samplingRate = samplingRate self._sampleFormat = pa.paInt16 self._channels = 2 self._pa = pa.PyAudio() self._stream = None self._frames = [] def __del__(self): if self.recording: self._stream.stop_stream() self._stream.close() def _callback(self, inData, frameCount, timeInfo, statusFlags): if statusFlags != pa.paNoError: print(f"Recorder callback got status {hex(statusFlags)}, aborting") return (None, pa.paAbort) self._frames.append(inData) return (None, pa.paContinue) def startRecording(self) -> None: if self.recording: return self._frames.clear() self._stream = self._pa.open(format=self._sampleFormat, channels=self._channels, rate=self._samplingRate, frames_per_buffer=self._bufferSize, input=True, stream_callback=self._callback) def stopRecording(self) -> Recording: if not self.recording: return None self._stream.stop_stream() self._stream.close() self._stream = None return Recording(self._frames, self._channels, self._samplingRate, self._pa.get_sample_size(self._sampleFormat)) @property def recording(self) -> bool: return self._stream is not None