From b65fa14f5e53494d43a9956acd520279f58b37ea Mon Sep 17 00:00:00 2001 From: Jono Targett Date: Mon, 27 May 2024 13:11:27 +0930 Subject: [PATCH] Added live detector graph --- scripts/.gitignore | 3 +- scripts/audio-capture.sh | 8 ++++ scripts/audio-pipe.sh | 9 ++++ scripts/live.py | 93 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100755 scripts/audio-capture.sh create mode 100755 scripts/audio-pipe.sh create mode 100755 scripts/live.py diff --git a/scripts/.gitignore b/scripts/.gitignore index 4b67193..9323043 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,2 +1,3 @@ *.wav -__pycache__/ \ No newline at end of file +__pycache__/ +junk/ \ No newline at end of file diff --git a/scripts/audio-capture.sh b/scripts/audio-capture.sh new file mode 100755 index 0000000..b4dfec3 --- /dev/null +++ b/scripts/audio-capture.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +set -eux + +sample_rate="44100" +channels="2" + +arecord -t raw -c ${channels} -f S16_LE -r ${sample_rate} \ No newline at end of file diff --git a/scripts/audio-pipe.sh b/scripts/audio-pipe.sh new file mode 100755 index 0000000..f8ae9e4 --- /dev/null +++ b/scripts/audio-pipe.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +set -eux + +audio_file=$1 +sample_rate="44100" +channels="2" + +ffmpeg -i ${audio_file} -f s16le -ac ${channels} -ar ${sample_rate} - \ No newline at end of file diff --git a/scripts/live.py b/scripts/live.py new file mode 100755 index 0000000..b541363 --- /dev/null +++ b/scripts/live.py @@ -0,0 +1,93 @@ +#! /usr/bin/env python3 + +import sys +import threading +import numpy as np +import signal +import pyqtgraph as pg + +data1 = np.random.normal(size=300) +ptr1 = 0 + +win = pg.GraphicsLayoutWidget(show=True) +win.setWindowTitle('pyqtgraph example: Scrolling Plots') + +plot = win.addPlot() +curve = plot.plot(data1) + + + +keep_running = True +def signal_handler(sig, frame): + global keep_running + print('SIGINT received. Stopping...') + keep_running = False + +def read_audio_from_stdin(chunk_size, process_chunk): + global keep_running + + while keep_running: + # 2 bytes per sample for int16 + read_size = chunk_size * 2 + data = sys.stdin.buffer.read(read_size) + + # Break the loop if no more data is available + if not data: + break + + # Convert the binary data to a numpy array of int16 + audio_chunk = np.frombuffer(data, dtype=np.int16) + process_chunk(audio_chunk) + +def process_audio_chunk(audio_chunk): + # Example processing: simply print the chunk + global data1, ptr1, curve + print(f"Read chunk: {len(audio_chunk)}") + + data1[:-1] = data1[1:] # shift data in the array one sample left + # (see also: np.roll) + data1[-1] = len(audio_chunk) + + ptr1 += 1 + curve.setData(data1) + curve.setPos(ptr1, 0) + + +if __name__ == '__main__': + signal.signal(signal.SIGINT, signal_handler) + + chunk_duration = 0.1 # seconds + sample_rate = 44100 + channels = 2 + chunk_size = int(sample_rate * chunk_duration) * channels + + reader_thread = threading.Thread(target=read_audio_from_stdin, args=(chunk_size, process_audio_chunk)) + reader_thread.daemon = True + reader_thread.start() + + pg.exec() + + # Wait... + reader_thread.join() + + +''' +# 1) Simplest approach -- update data in the array such that plot appears to scroll +# In these examples, the array size is fixed. +p1 = win.addPlot() +p2 = win.addPlot() +data1 = np.random.normal(size=300) +curve1 = p1.plot(data1) +curve2 = p2.plot(data1) +ptr1 = 0 +def update1(): + global data1, ptr1 + data1[:-1] = data1[1:] # shift data in the array one sample left + # (see also: np.roll) + data1[-1] = np.random.normal() + curve1.setData(data1) + + ptr1 += 1 + curve2.setData(data1) + curve2.setPos(ptr1, 0) +''' \ No newline at end of file