Bokeh plot Pyaudio livestream

Just starting with bokeh… I try to plot realtime audio data using Pyaudio and Bokehs periodic_callback, but am a bit stuck right know… (I also couldn’t get the spectrogram example to work, the OHLC example works after solving an issue in line 97 in main.py (“width” replaced with “plot_width”))

—code—

import pyaudio
import numpy as np
import queue
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource
from bokeh.driving import count

que = queue.Queue()

p = pyaudio.PyAudio()

def callback(in_data, frame_count, time_info, status):
    data = np.fromstring(in_data, dtype=np.int16)
    que.put(data)
    return (None, pyaudio.paContinue)

stream = p.open(
    format=pyaudio.paInt16,
    channels=1,
    rate=44100,
    input=True,
    output=False,
    frames_per_buffer=8000,
    stream_callback=callback,
)

stream.start_stream()

source = ColumnDataSource(
    dict(
        samples=[x],
        data=[],
    )
)

plot = figure(plot_width=1200, plot_height=800)
plot.line(x="samples", y="data", source=source)

@count()
def update(counter):
    print(counter)
    data = que.get()
    newData = dict(
        samples=[np.arange(len(data))],
        data=[data],
    )

    source.stream(newData, 4000)

curdoc().add_root(plot)
# Add a periodic callback to be run every 50 milliseconds
curdoc().add_periodic_callback(update, 50)

stream.stop_stream()
stream.close()
p.terminate()

Hi @musicus please edit your post to use code formatting so that the code is intelligible (either with the </> icon on the editing toolbar, or triple backtick ``` fences around the code blocks)

“width” replaced with “plot_width”

Your installed version of Bokeh is too old for the version of the example

Thanks for the tip with code formatting… first post here
Old Bokeh version is correct, I had 2.3.1 (pip install) and used 2.4 branch

@musicus Are you able to get pyaudio to work outside Bokeh? As one data point, pyaudio no longer works for me since updating OSX the other day. Previously it had flashed warnings about deprecated OSX APIs for some time, perhaps Apple finally removed those APIs and broke things.

Regardless of what OS you are using, I would suggest making sure you can use pyaudio successfully at all, without Bokeh, as a first step. If not, there are probably better forums dedicated to pyaudio/portaudio to ask this question.

Yes, Pyaudio is working (pip install pyaudio is not supported after python 3.6, for later versions you need to download a separate wheel for example here Python Extension Packages for Windows - Christoph Gohlke)

I am trying to get something similar to following code (using pyqtgraph), which should work (atleast it does for me on Windows)… live plotting of mic signal

import numpy as np
import pyaudio
import queue
import pyqtgraph as pg

RATE = 44100
BUFFER = 10000

que = queue.Queue()

### pyqtGraph ###
plotWidget = pg.plot()
plot = plotWidget.plot()

def callback(in_data, frame_count, time_info, status):
    data = np.fromstring(in_data, dtype=np.float32)
    que.put(data)
    return (None, pyaudio.paContinue)

p = pyaudio.PyAudio()
stream = p.open(
    format=pyaudio.paFloat32,
    channels=1,
    rate=RATE,
    input=True,
    output=False,
    frames_per_buffer=BUFFER,
    stream_callback=callback,
)

stream.start_stream()

while stream.is_active():
    data = que.get()
    plot.setData(np.arange(len(data)), data)
    pg.QtGui.QApplication.processEvents()

stream.stop_stream()
stream.close()
p.terminate()

@musicus Unfortunately I don’t know that I can offer much/any help at the moment, since all I have immediate access too is OSX and portaudio appears to be broken on latest OSX. It’s possible there are clues if you provide more information. You have said things “don’t work” but not actually given any details of what means. Are there exceptions or log messages in the program console? Or in the browser JS console? Does any part of the page render, or no part, or?

I rewrote my example code using Sounddevice (instead of Pyaudio) and PyQTGraph, which atleast does run on my system (Win10, Python 3.9.2).
The basic concept:
continous audio callback stream → put data in queue → get data from queue and update plot

With Bokeh I struggle with the two parallel callback functions…I try to get more information about it

import numpy as np
import sounddevice as sd
import queue
import pyqtgraph as pg

### settings ###
RATE = 44100
plot_seconds = 1
plot_xPoints = plot_seconds * RATE

### synchonizing audio and plotting
que = queue.Queue()
plot_data = []

### pyqtGraph ###
plotWidget = pg.plot()
plotWidget.setYRange(-1,1)
plotWidget.setXRange(0,plot_seconds)
plot = plotWidget.plot()

### Sounddevice ###
def callback(in_data, frame_count, time_info, status):
    que.put(in_data)

stream = sd.InputStream(channels=1, samplerate=RATE, callback=callback)
stream.start()

with stream:
    while True:
        # get data from queue and append to plot data
        data = np.ravel(que.get()).tolist()
        plot_data += data

        # trim data to plotting time
        if len(plot_data) > plot_xPoints:
            trim_index = len(plot_data) - plot_xPoints - 1
            del plot_data[:trim_index]
        
        # prepare data for plotting
        plot_array = np.ravel(np.array(plot_data))
        x_values = np.arange(len(plot_array))
        x_values_in_seconds = x_values / RATE

        # update plot
        plot.setData(x_values_in_seconds, plot_array)
        pg.QtGui.QApplication.processEvents()

stream.stop()
stream.close()