How to Record, Save and Play audio in Python?
Libraries
The following are the required libraries.
- PortAudio is a free, cross-platform, open-source, audio I/O library. It lets you write simple audio programs in ‘C’ or C++ that will compile and run on many platforms including Windows, Macintosh OS X, and Unix (OSS/ALSA).
- PyAudio provides Python bindings for PortAudio. Following is the
pip
command.pip install pyaudio
- wave module of Python3.
simpleaudio
to play the saved wave audio file. Following is thepip
command:pip install simpleaudio
Check mic check
Check if you have a working microphone on your system. Following is the code snippet you can use.
import pyaudio
import pprint
p = pyaudio.PyAudio()
pp = pprint.PrettyPrinter(indent=4)
try:
pp.pprint(p.get_default_input_device_info())
except:
print("No mics availiable")
Example output:
Record the audio
Following is the code snippet to record the audio.
import pyaudio
import wave
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK) #buffer
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data) # 2 bytes(16 bits) per channel
stream.stop_stream()
stream.close()
p.terminate()
pyaudio.PyAudio()
method acquires system resources for PortAudio. pyaudio.PyAudio.open()
sets up a pyaudio.PyAudio.Stream
to play or record audio. pyaudio.PyAudio.Stream.read()
is used to read audio data from the stream. In the above code, all the audio frames have been collected in the frames list frames []
. These frames will be used for saving the audio file in the later part of the code.
Meaning of parameters to the function open
:
- FORMAT: PortAudio provides samples in raw PCM (Pulse-Code Modulation) format. That means each sample is an amplitude to be given to the DAC (digital-to-analog converter) in your sound card. For
paInt16
, this is a value from -32768 to 32767. ForpaFloat32
, this is a floating-point value from -1.0 to 1.0. The sound card converts this values to a proportional voltage that then drives your audio equipment.paFloat32
,paInt32
,paInt24
,paInt16
,paInt8
,paUInt8
,paCustomFormat
- CHANNELS means how many samples will be there for each frame.
- RATE is the sampling rate (the number of frames per second)
- CHUNK is the number of frames the signals are split into. This is arbitrarily chosen.
In the last, the stream should be closed and all the resources acquired must be released.
Saving the audio
Following is the code snippet to save the audio.
# Save the recorded audio file
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
wave
module of Python3 is used for this purpose. Parameters are set as the same values that were used while recording the audio.
Play the audio
Following is the code snippet to play the audio. simpleaudio
library I have used for this purpose. There are other libraries available that can be tried. simpleaudio
I found to be simple enough.
# Play the recorded audio file
wave_obj = sa.WaveObject.from_wave_file("pyaudio-output.wav")
play_obj = wave_obj.play()
play_obj.wait_done()
Complete Code
import pyaudio
import wave
import simpleaudio as sa
CHUNK = 512
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "myaudio.wav"
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK) #buffer
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data) # 2 bytes(16 bits) per channel
stream.stop_stream()
stream.close()
p.terminate()
# Save the recorded audio file
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
# Play the recorded audio file
wave_obj = sa.WaveObject.from_wave_file("myaudio.wav")
play_obj = wave_obj.play()
play_obj.wait_done()