Hi All
i have downloaded following code from web that inputs sound samples and displays spectrum, i want to print frequencies present in each second in the spectrum.i.e
when ever the spectrum is displayed i want to print those frequencies as well on the console. Below is the code i am using i initially used "print fftx". Is "fftx" present in the code is frequency. Also how can i measure the amplitude of each frequency so as next step i will print three frequencies with the top most amplitude.
Thanks in advance.

import pyaudio
import scipy
import struct
import scipy.fftpack

from Tkinter import *
import threading
import time, datetime
import wckgraph
import math

#ADJUST THIS TO CHANGE SPEED/SIZE OF FFT
bufferSize=2**11
#bufferSize=2**8

# ADJUST THIS TO CHANGE SPEED/SIZE OF FFT
sampleRate=48100
#sampleRate=64000

p = pyaudio.PyAudio()
chunks=[]
ffts=[]
def stream():
global chunks, inStream, bufferSize
while True:
chunks.append(inStream.read(bufferSize))

def record():
global w, inStream, p, bufferSize
inStream = p.open(format=pyaudio.paInt16,channels=1,\
rate=sampleRate,input=True,frames_per_buffer=bufferSize)
threading.Thread(target=stream).start()

def downSample(fftx,ffty,degree=10):
x,y=[],[]
for i in range(len(ffty)/degree-1):
x.append(fftx[i*degree+degree/2])
y.append(sum(ffty[i*degreei+1)*degree])/degree)
return [x,y]

def smoothWindow(fftx,ffty,degree=10):
lx,ly=fftx[degree:-degree],[]
for i in range(degree,len(ffty)-degree):
ly.append(sum(ffty[i-degree:i+degree]))
return [lx,ly]

def smoothMemory(ffty,degree=3):
global ffts
ffts = ffts+[ffty]
if len(ffts) <= degree:
return ffty
ffts=ffts[1:]
return scipy.average(scipy.array(ffts),0)

def detrend(fftx,ffty,degree=10):
lx,ly=fftx[degree:-degree],[]
for i in range(degree,len(ffty)-degree):
ly.append(ffty[i]-sum(ffty[i-degree:i+degree])/(degree*2))
#ly.append(fft[i]-(ffty[i-degree]+ffty[i+degree])/2)
return [lx,ly]

def graph():
global chunks, bufferSize, fftx,ffty, w
if len(chunks)>0:
data = chunks.pop(0)
data=scipy.array(struct.unpack("%dB"%(bufferSize*2),data))
#print "RECORDED",len(data)/float(sampleRate),"SEC"
ffty=scipy.fftpack.fft(data)
fftx=scipy.fftpack.rfftfreq(bufferSize*2, 1.0/sampleRate)
fftx=fftx[0:len(fftx)/4]
ffty=abs(ffty[0:len(ffty)/2])/1000
ffty1=ffty[:len(ffty)/2]
ffty2=ffty[len(ffty)/2::]+2
ffty2=ffty2[::-1]
ffty=ffty1+ffty2
ffty=scipy.log(ffty)-2
#fftx,ffty=downSample(fftx,ffty,5)
#fftx,ffty=detrend(fftx,ffty,30)
#fftx,ffty=smoothWindow(fftx,ffty,10)
ffty=smoothMemory(ffty,3)
#fftx,ffty=detrend(fftx,ffty,10)
w.clear()
#w.add(wckgraph.Axes(extent=(0, -1, fftx[-1], 3)))
w.add(wckgraph.Axes(extent=(0, -1, 6000, 3)))
w.add(wckgraph.LineGraph([fftx,ffty]))
w.update()
if len(chunks)>20:
print "falling behind...",len(chunks)

def go(x=None):
global w,fftx,ffty
print "STARTING!"
threading.Thread(target=record).start()
while True:
graph()

root = Tk()
root.title("SPECTRUM ANALYZER")
root.geometry('500x200')
w = wckgraph.GraphWidget(root)
w.pack(fill=BOTH, expand=1)
go()
mainloop()

Dani AI

Generated

Short answer: fftx is meant to be the frequency axis, and the amplitudes come from the magnitude of the FFT output (abs of the complex bins). In your code the mapping is wrong because the raw bytes are being unpacked as individual unsigned bytes instead of signed 16‑bit samples and the FFT length used for the frequency axis doesn't match the real sample count. Fix those two things first (read samples as 16-bit ints, set N = number of samples) and the frequency bins you compute will be correct.

Quick, practical recipe (illustrative):

# collect ~1 second worth of raw frames into `raw_bytes`
import numpy as np
from scipy.signal import find_peaks

samples = np.frombuffer(raw_bytes, dtype=np.int16)   # correct signed 16-bit sample array
N = len(samples)
win = np.hanning(N)
spec = np.fft.rfft(samples * win)
freqs = np.fft.rfftfreq(N, 1.0 / sample_rate)
mags = np.abs(spec) * 2.0 / N     # single-sided amplitude scaling

mags[0] = 0                       # ignore DC
peaks, _ = find_peaks(mags, height=np.max(mags)*0.05, distance=int(20 * N/sample_rate))
top_peaks = peaks[np.argsort(mags[peaks])][-3:][::-1]
for idx in top_peaks:
    print("{:.1f} Hz  {:.3f}".format(freqs[idx], mags[idx]))

Notes and gotchas:

  • Frequency resolution df = sample_rate / N. To get ~1 Hz resolution, use N ≈ sample_rate (accumulate ~1 second of samples before FFT). Smaller bufferSizes give coarser frequency bins.
  • Use a window (Hann) to reduce spectral leakage; scale magnitudes by N (and multiply by 2 for single‑sided spectra).
  • Use peak detection (scipy.signal.find_peaks) or sort bin magnitudes; ignore DC and very-low amplitudes (noise threshold) to avoid spurious picks.
  • For real signals you will often see harmonics — you might want to cluster nearby peaks (within a few bins) to pick fundamentals instead of harmonics.
  • Performance: use numpy.frombuffer (faster than struct.unpack) and real FFT (rfft).

Also: fix Python indentation as suggested; and avoid printing from the audio thread (use a GUI-safe updater or a logging queue) so the audio capture doesn't fall behind.

Until you indent you i dont think your going to get any help from here. Indent you code. I can’t compile this code as the code will never compiler. Python is strictly indent specific. I suppose you should know that by now. Indent your code and post again!

ssharish

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.