I need to create moving waveform using Python and pyaudio. I thought about creating a buffer and filling it with data from audio stream. It sorta works but it's too slow. I tried changing the size of chunk to something smaller, but i always get an "Input overflowed" error.
This is the code i came up with
import numpy as np
import pyaudio as pa
import matplotlib.pyplot as plt
CHUNK = 1024
FORMAT = pa.paInt16
CHANNELS = 1
RATE = 44100
p = pa.PyAudio()
stream = p.open(
format = FORMAT,
channels = CHANNELS,
rate = RATE,
input=True,
output=True,
frames_per_buffer=CHUNK
)
buffer = [0]*CHUNK
fig, ax = plt.subplots()
x = np.arange(0,2*CHUNK,2)
line, = ax.plot(x, np.random.rand(CHUNK),'r')
ax.set_ylim(-32000,32000)
ax.ser_xlim = (0,CHUNK)
fig.show()
while True:
data = stream.read(CHUNK)
dataInt = np.frombuffer(data, dtype=np.int16)
for i in range(len(dataInt)):
buffer.insert(0, dataInt[i])
del buffer[-1]
line.set_ydata(buffer)
fig.canvas.draw()
fig.canvas.flush_events()
The main problem is that the update in the for loop is too frequent and we know each update in the data and redrawing the canvas is time-consuming. I suggest making the update once every few datapoints. You can control update frequency using a variable like UPDATE_SIZE
:
UPDATE_SIZE = 32
while True:
data = stream.read(CHUNK)
dataInt = np.frombuffer(data, dtype=np.int16)
for i in range(0, len(dataInt), UPDATE_SIZE):
buffer = dataInt[i:i+UPDATE_SIZE].tolist()[::-1] + buffer[:-UPDATE_SIZE]
line.set_ydata(buffer)
fig.canvas.draw()
fig.canvas.flush_events()