Skip to content

Instantly share code, notes, and snippets.

@Factoid
Created October 1, 2019 05:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Factoid/9ff0da2da33ada40d5bc556700477489 to your computer and use it in GitHub Desktop.
Save Factoid/9ff0da2da33ada40d5bc556700477489 to your computer and use it in GitHub Desktop.
Zoom FFT with realtime audio source
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from scipy import signal
import math
import random
import cmath
import pyaudio
signalData = []
BINS = 1024
RATE = 48000
CHUNK = BINS*5
FORMAT = pyaudio.paInt16
CHANNELS = 1
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="Basic plotting examples")
win.resize(1900,1080)
win.setWindowTitle('pyqtgraph example: Plotting')
signalGraph = win.addPlot(title="Signal Graph")
sigPlot = signalGraph.plot(pen='y')
fftOutput = win.addPlot(title="FFT Output")
fftPlot = fftOutput.plot(pen='y')
zoomFFTOutput = win.addPlot(title="Zoom FFT Output")
zoomFFTPlot = zoomFFTOutput.plot(pen='y')
def gen_tone_data( sampleRate, samples ):
f1 = 200
f2 = 220
dt = 1/sampleRate
pi2dt = 2.0*math.pi*dt;
return [ 2*math.sin(pi2dt*f1*i)+1*math.sin(pi2dt*f2*i) for i in range(samples)]
#return [ 2*math.sin(pi2dt*f1*i)+1*math.sin(pi2dt*f2*i)+(random.random()-0.5) for i in range(samples)]
def myfft( signalBuf, sampleRate, nBins, offset ):
outBins = (nBins//2)
binWidth = (sampleRate/2) / outBins
# print( "sampleRate", sampleRate, "min", offset, "outbins", outBins, "binWidth", binWidth, "max", (outBins-1)*binWidth+offset )
return [ [ offset + i * binWidth for i in range(outBins) ], [abs(x) for x in np.fft.fft(signalBuf,n=nBins)[0:outBins] ] ]
def shiftFrequency( samples, sampleRate, adjustBy ):
dt = 1/sampleRate
pi2dtcf = 2*math.pi*dt*adjustBy
vals = [ cmath.exp(1j*pi2dtcf*i)*samples[i] for i in range(len(samples)) ]
return vals
def zoom_fft( samples, sampleRate, nBins, fStart, fEnd ):
bandwidth = (fEnd - fStart)
decFactor = sampleRate//bandwidth//2
shifted = shiftFrequency( samples, sampleRate, -fStart )
resampled = signal.decimate(shifted,decFactor,ftype='fir')
newSampleRate = sampleRate//decFactor
# print("decFactor",decFactor,"newSampleRate",newSampleRate)
vals = myfft( resampled, newSampleRate, nBins, fStart )
return vals
def update():
pass
def callback( in_data, frame_count, time_info, status ):
signalData = np.frombuffer(in_data,dtype=np.int16)
#signalData = gen_tone_data( RATE, frame_count )
sigPlot.setData( signalData )
fftData = myfft(signalData, RATE, BINS, 0.0)
fftPlot.setData( *fftData )
zoomFFTData = zoom_fft( signalData, RATE, BINS, 100, 500 )
zoomFFTPlot.setData( *zoomFFTData )
return (None, pyaudio.paContinue)
p = pyaudio.PyAudio()
stream = p.open( format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK, stream_callback=callback )
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1)
app.exec_()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment