Compare commits
No commits in common. "7465ef13ea9ea21206abaeb8309ba6f907ba9ec0" and "0aee4d68184011d7faa962090d22a9f981659d92" have entirely different histories.
7465ef13ea
...
0aee4d6818
@ -51,13 +51,3 @@ low pass & decimate if necessary
|
|||||||
reset code detection counter (prohibit detecting codes for another 0.5 sec)
|
reset code detection counter (prohibit detecting codes for another 0.5 sec)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
|
||||||
Either
|
|
||||||
```
|
|
||||||
./audio-capture.sh | ./live.py
|
|
||||||
```
|
|
||||||
or
|
|
||||||
```
|
|
||||||
./audio-pipe.sh ./samples/MA-ZC.wav | ./live.py
|
|
||||||
```
|
|
||||||
@ -3,6 +3,6 @@
|
|||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
sample_rate="44100"
|
sample_rate="44100"
|
||||||
channels="1"
|
channels="2"
|
||||||
|
|
||||||
arecord -t raw -c ${channels} -f S16_LE -r ${sample_rate}
|
arecord -t raw -c ${channels} -f S16_LE -r ${sample_rate}
|
||||||
@ -4,6 +4,6 @@ set -eux
|
|||||||
|
|
||||||
audio_file=$1
|
audio_file=$1
|
||||||
sample_rate="44100"
|
sample_rate="44100"
|
||||||
channels="1"
|
channels="2"
|
||||||
|
|
||||||
ffmpeg -hide_banner -loglevel error -i ${audio_file} -f s16le -ac ${channels} -ar ${sample_rate} -
|
ffmpeg -i ${audio_file} -f s16le -ac ${channels} -ar ${sample_rate} -
|
||||||
129
scripts/live.py
129
scripts/live.py
@ -3,14 +3,19 @@
|
|||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import signal as sig
|
import signal
|
||||||
from tones import TONES
|
|
||||||
from filters import anti_alias, bandpass_filter, note
|
|
||||||
from scipy import signal
|
|
||||||
from scipy.signal import butter, lfilter, decimate
|
|
||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtGui, QtWidgets, mkQApp
|
|
||||||
|
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
|
keep_running = True
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
@ -18,62 +23,6 @@ def signal_handler(sig, frame):
|
|||||||
print('SIGINT received. Stopping...')
|
print('SIGINT received. Stopping...')
|
||||||
keep_running = False
|
keep_running = False
|
||||||
|
|
||||||
|
|
||||||
class DetectorGui(QtWidgets.QMainWindow):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(DetectorGui, self).__init__(*args, **kwargs)
|
|
||||||
layout = pg.GraphicsLayoutWidget(show=True)
|
|
||||||
self.setCentralWidget(layout)
|
|
||||||
self.setWindowTitle('SELCAL Detector')
|
|
||||||
self.resize(1280, 800)
|
|
||||||
|
|
||||||
self.plot = layout.addPlot()
|
|
||||||
legend_view = layout.addViewBox()
|
|
||||||
|
|
||||||
legend = pg.LegendItem(offset=(0, 0))
|
|
||||||
legend.setParentItem(legend_view)
|
|
||||||
|
|
||||||
color_map = pg.colormap.get('CET-C6s')
|
|
||||||
colors = color_map.getLookupTable(nPts=len(TONES))
|
|
||||||
|
|
||||||
t = np.linspace(0, 500, 100)
|
|
||||||
|
|
||||||
self.tone_data = {}
|
|
||||||
self.tone_lines = {}
|
|
||||||
|
|
||||||
for tone,color in zip(TONES.keys(), colors):
|
|
||||||
self.tone_data[tone] = np.zeros(int(10000), dtype=np.float64) #np.array([], dtype=np.float64)
|
|
||||||
self.tone_lines[tone] = self.plot.plot(self.tone_data[tone], pen=pg.mkPen(color=color), name=tone)
|
|
||||||
legend.addItem(self.tone_lines[tone], tone)
|
|
||||||
|
|
||||||
self.plot.setLabel('left', 'Signal Correlation')
|
|
||||||
self.plot.setLabel('bottom', 'Time (samples)')
|
|
||||||
self.plot.showGrid(x=True, y=True)
|
|
||||||
|
|
||||||
legend_view.setFixedWidth(80)
|
|
||||||
layout.ci.layout.setColumnFixedWidth(1, 80)
|
|
||||||
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def set_position(self, pos):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def push_tone(self, tone, value):
|
|
||||||
self.tone_data[tone] = np.roll(self.tone_data[tone], -1)
|
|
||||||
self.tone_data[tone][-1] = value
|
|
||||||
self.tone_lines[tone].setData(self.tone_data[tone])
|
|
||||||
|
|
||||||
def push_tones(self, tone, values):
|
|
||||||
#self.tone_data[tone] = np.append(self.tone_data[tone], values)
|
|
||||||
|
|
||||||
self.tone_data[tone] = np.roll(self.tone_data[tone], -len(values))
|
|
||||||
self.tone_data[tone][-len(values):] = values
|
|
||||||
self.tone_lines[tone].setData(self.tone_data[tone])
|
|
||||||
|
|
||||||
|
|
||||||
mkQApp("Correlation matrix display")
|
|
||||||
gui = DetectorGui()
|
|
||||||
|
|
||||||
def read_audio_from_stdin(chunk_size, process_chunk):
|
def read_audio_from_stdin(chunk_size, process_chunk):
|
||||||
global keep_running
|
global keep_running
|
||||||
|
|
||||||
@ -90,43 +39,55 @@ def read_audio_from_stdin(chunk_size, process_chunk):
|
|||||||
audio_chunk = np.frombuffer(data, dtype=np.int16)
|
audio_chunk = np.frombuffer(data, dtype=np.int16)
|
||||||
process_chunk(audio_chunk)
|
process_chunk(audio_chunk)
|
||||||
|
|
||||||
sample_rate = 44100
|
|
||||||
note_length = 0.1
|
|
||||||
N = 256
|
|
||||||
cumsum_convolution = np.ones(N)/N
|
|
||||||
|
|
||||||
|
|
||||||
def process_audio_chunk(audio_chunk):
|
def process_audio_chunk(audio_chunk):
|
||||||
global gui
|
# Example processing: simply print the chunk
|
||||||
|
global data1, ptr1, curve
|
||||||
|
print(f"Read chunk: {len(audio_chunk)}")
|
||||||
|
|
||||||
data = audio_chunk
|
data1[:-1] = data1[1:] # shift data in the array one sample left
|
||||||
sample_rate = 44100
|
# (see also: np.roll)
|
||||||
|
data1[-1] = len(audio_chunk)
|
||||||
|
|
||||||
data, sample_rate, decimation = anti_alias(data, sample_rate, 4800)
|
ptr1 += 1
|
||||||
pure_signals = {tone:note(freq, note_length, rate=sample_rate) for tone,freq in TONES.items()}
|
curve.setData(data1)
|
||||||
correlations = {tone:np.abs(signal.correlate(data, pure, mode='same')) for tone,pure in pure_signals.items()}
|
curve.setPos(ptr1, 0)
|
||||||
massaged = {tone:decimate(np.convolve(correlation, cumsum_convolution, mode='valid'), 4) for tone,correlation in correlations.items()}
|
|
||||||
|
|
||||||
print('processing done')
|
|
||||||
|
|
||||||
for tone,massage in massaged.items():
|
|
||||||
gui.push_tones(tone, massage )
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sig.signal(sig.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
chunk_duration = 0.1 # seconds
|
chunk_duration = 0.1 # seconds
|
||||||
sample_rate = 44100
|
sample_rate = 44100
|
||||||
channels = 1
|
channels = 2
|
||||||
chunk_size = int(sample_rate * chunk_duration) * channels
|
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 = threading.Thread(target=read_audio_from_stdin, args=(chunk_size, process_audio_chunk))
|
||||||
reader_thread.daemon = True
|
reader_thread.daemon = True
|
||||||
reader_thread.start()
|
reader_thread.start()
|
||||||
|
|
||||||
|
|
||||||
pg.exec()
|
pg.exec()
|
||||||
|
|
||||||
# Wait...
|
# Wait...
|
||||||
reader_thread.join()
|
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)
|
||||||
|
'''
|
||||||
Loading…
Reference in New Issue
Block a user