aboutsummaryrefslogtreecommitdiffstats
path: root/solo-tool-project/src/solo_tool/recorder.py
diff options
context:
space:
mode:
Diffstat (limited to 'solo-tool-project/src/solo_tool/recorder.py')
-rw-r--r--solo-tool-project/src/solo_tool/recorder.py72
1 files changed, 72 insertions, 0 deletions
diff --git a/solo-tool-project/src/solo_tool/recorder.py b/solo-tool-project/src/solo_tool/recorder.py
new file mode 100644
index 0000000..71c8ac8
--- /dev/null
+++ b/solo-tool-project/src/solo_tool/recorder.py
@@ -0,0 +1,72 @@
+from pathlib import Path
+
+import pyaudio as pa
+from pydub import AudioSegment, effects
+
+class Recording:
+ def __init__(self, frames: list, channels: int, samplingRate: int, sampleFormat: int):
+ self._segment = AudioSegment(
+ data=b''.join(frames),
+ sample_width=sampleFormat,
+ frame_rate=samplingRate,
+ channels=channels
+ )
+ self._postProcess()
+
+ def _postProcess(self) -> None:
+ self._segment = effects.normalize(self._segment)
+
+ def writeWav(self, file: Path) -> None:
+ self._segment.export(str(file), format="wav")
+
+ def writeMp3(self, file: Path) -> None:
+ self._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 and statusFlags != pa.paInputOverflowed:
+ print(f"Recorder callback got status {hex(statusFlags)}, aborting")
+ # TODO figure out what status code is being received and if it's a problem or not
+ #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
+