Search code examples
pythonpyaudio

How do i create an animated (moving from left to right) waveform in Python?


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()

Solution

  • 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()