7.2. Visualize Sound Signals

We will extend the non blocking code for playing audio to visualize the audio signal in real time while playing it. We start with a simple display of the audio signal in matplotlib. For a mono signal we plot \(x(t)\). For each buffer (chunk) of data in the audio file we plot the amplitude as function of time. For a stereo signal we plot both the left \(x_L(t)\) signal and the right signal \(x_R(t)\).

 1import soundfile as sf
 2import pyaudio
 3import numpy as np
 4import matplotlib.pyplot as plt
 5import time
 6
 7plt.close('all')
 8plt.ion()
 9
10FILE = "../../data/sowhat.wav"
11
12chunk = 1024 * 2
13pa = pyaudio.PyAudio()
14
15f = sf.SoundFile(FILE)
16
17is_stereo = f.channels == 2
18if is_stereo:
19    fig, axs = plt.subplots(nrows=2, ncols=1, sharex=True)
20    xleftline, = axs[0].plot(np.arange(chunk), np.zeros(chunk), '-')
21    axs[0].set_ylim([-1,1])
22    xrightline, = axs[1].plot(np.arange(chunk), np.zeros(chunk), '-')
23    axs[1].set_ylim([-1,1])
24else:
25    fig, axs = plt.subplots(nrows=1, ncols=1)
26    xmonoline, = axs[0].plot(np.zeros(chunk), np.zeros(chunk), '-')
27    axs[0].set_ylim([-1,1])
28
29plt.show(block=False)
30
31
32def callback(in_data, frame_count, time_info, status):
33    fsx = f.read(chunk, dtype='float32')
34    if is_stereo:
35        xleft = fsx[:,0]
36        xright = fsx[:,1]
37        xleftline.set_ydata(xleft)
38        xrightline.set_ydata(xright)
39    else:
40        xmono = fsx
41        xmonoline.set_ydata(xmono)
42    return (fsx.tobytes(), pyaudio.paContinue)
43
44
45stream = pa.open(format=pyaudio.paFloat32,
46                 channels=f.channels,
47                 rate=f.samplerate,
48                 frames_per_buffer=chunk,
49                 output=True,
50                 stream_callback=callback)
51
52
53stream.start_stream()
54start_time = time.time()
55duration = 120    # play the first 2 minutes
56
57while stream.is_active() and time.time() - start_time < duration:
58    # time.sleep(0.1) # just waiting for the stream to finish
59    fig.canvas.draw()
60    fig.canvas.flush_events()
61
62
63stream.stop_stream()
64stream.close()
65
66pa.terminate()
67plt.close('all')
68print('done')