I'm writing a Python app to record audio as a WAV file until a user presses pause or stop. After pausing the audio, the user should also be able to resume recording. Additionally:
- The app can't know how long the recording will be beforehand
- The app should avoid running out of memory (since the recording could be very long). For example, it could write to the WAV file in real-time to prevent storing the growing recording in memory.
What's a good approach for this problem? Can you please provide some code snippets for your solution?
With python-sounddevice, I could stop()
and start()
the stream to mimic a 'pause' features. And I can specify a numpy array as an output for the recording. But:
- I don't know how big to make the array (since I don't know the recording duration)
- What would I do when the array fills up?
python-sounddevice and sound-file can support recordings without know the size beforehand. But:
- How would I incorporate 'pause' and 'resume' features? Sound-file has only
read
andwrite
methods. - Is there a better way to stop the stream than using a
KeyBoardInterrupt
? - Could I create different recording after every 'pause' and combine the WAV files after the user clicks 'stop'?
- I tried using
Threading.Event()
to block the recording thread to mimic a pause feature, but the recording kept writing to the file
My attempt at sound-device
approach
paused = False
def record():
self.recording = ? # create numpy.ndarray of the correct size
# (not sure the best way to do this without
# knowing the recording duration)
with sd.InputStream(samplerate=44100, device=mic, channels=1,
callback=self.callback):
while self.paused:
sd.stop()
sd.rec(out=recording) # but what happens if
# recording is very long
# or numpy array fills up?
def stop_and_save():
sd.stop()
scipy.io.wavfile.write("recording.wav", 44100, self.recording)
The sound-device
and sound-file
approach:
with sf.SoundFile(args.filename, mode='x', samplerate=args.samplerate,
channels=args.channels, subtype=args.subtype) as file:
with sd.InputStream(samplerate=args.samplerate, device=args.device,
channels=args.channels, callback=callback):
print('press Ctrl+C to stop the recording')
while True:
file.write(q.get()) # but how do you stop writing when 'paused'?
except KeyboardInterrupt:
print('\nRecording finished: ' + repr(args.filename))
parser.exit(0)
except Exception as e:
parser.exit(type(e).__name__ + ': ' + str(e))