You are not logged in.

#1 2017-08-29 05:12:38

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,789

Waterfall Spectrum Display

Edit:  Here is a screenshot while playing Pink Floyd "Comfortably Numb"
http://i.imgur.com/HyNnSfq.png

Updated code with de-emphasis of low frequency
End of edit
----------------------------------------------
Here is some Python code I've been playing with for a couple days. (Thanks to Trilby for causing me to think about this a little)

It needs python-pyaudio, python-pyqtgraph, python-numpy (edit) and python-opengl
It listens to your audio and displays a waterfall display of the audio spectrum (0+ to 11kHz)

You can zoom in and out with the cursor wheel or two-finger touch on a touchpad.
Click and drag to change the viewing position

Anyone who knows pyqtgraph have any suggestions on how to set up a color map?

#!/usr/bin/env python

import pyaudio
import struct
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
import signal
import pyqtgraph.opengl as gl
import numpy as np

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 22050
CHUNK = 512
FORMATSTR="@%ih"%CHUNK
OFFSET=0
SCALE=50000
DECAY=1

freq=np.fft.fftfreq(CHUNK,1/RATE)[1:256]

def sigint_handler(*args):
    """sigint_Handler: Kill main loop if Ctrl-C is caught"""
    app.quit()

def update():
    """ Obtain next chunk of audio, compute FFT, update the waterfall display
          Called periodically using a timer"""
    global firstPassFlag ,FORMATSTR, freq, plotItem, z
    data = np.fft.fft(struct.unpack(FORMATSTR,stream.read(CHUNK)))
    data=abs(data[:257])*deEmphasis[:257]
    z=np.vstack((data,z[:-1]))
    plotItem.setData(z=z)
app = QtGui.QApplication([])
audio = pyaudio.PyAudio()


win = gl.GLViewWidget()
win.show()
win.setWindowTitle('Waterfall')
win.setCameraPosition(distance=50)

stream = audio.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE, input=True,
                    frames_per_buffer=CHUNK)


rows,cols =256,256

z = np.zeros((rows+1,cols+1))
x = np.linspace(-8, 8, cols+1).reshape(cols+1,1)
y = np.linspace(-8, 8, rows+1).reshape(1,rows+1)
deEmphasis= (1-np.exp(-(np.linspace(0,8,cols+1) * DECAY)))/SCALE
plotItem = gl.GLSurfacePlotItem(x=x[:,0], y = y[0,:],
                                shader='heightColor',
                                computeNormals=False, smooth=True)

#plotItem.shader()['colorMap'] = np.linspace(0.,8,100)
plotItem.shader()['colorMap'] = np.array([0.2, 2, 0.5, 0.2, 1, 1, 0.2, 0, 2])

win.addItem(plotItem)

## Add a grid to the view

gridxy = gl.GLGridItem()
gridxy.scale(1,1,1)
win.addItem(gridxy)
gridzy = gl.GLGridItem()
gridzy.scale(1,1,1)
gridzy.rotate(90, 1, 0, 0)
win.addItem(gridzy)
gridzy.translate(0,-10,10)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(10)


## Start Qt event loop unless running in interactive mode or using pyside.

if __name__ == '__main__':
    import sys
    signal.signal(signal.SIGINT, sigint_handler)
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()
    print ("\nCleaning up...")
    stream.stop_stream()
    stream.close()
    audio.terminate()

Last edited by ewaller (2017-08-30 03:54:30)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

Board footer

Powered by FluxBB