4

I am trying to make a program in python which will take in sound frequencies with pyaudio and show ranges of frequencies as bars going up and down using turtle. I want it to look something like this:

Equalizer

I followed this tutorial for getting and graphing the sound data in an fft format: https://www.youtube.com/watch?v=aQKX3mrDFoY

My code is formatted to have 32 eq bands. To split the frequencies into 32 groups, I loop through the frequency list created by pyaudio and add all of the values of the list in groups of 32, then I make each value in the list a percentage of the largest value (so that the input volume hopefully doesn't matter). There are 1024 different frequencies in the list before it is split. Here is the function I use to split these values:

def split_freq(freq): # splits given sound frequencies into groups of frequencies to feed into turtle
    freq_ranges = []
    for i in range(len(freq)-1): # split the frequencies into 32 groups
        if i % abs((len(freq)//32)) == 0:
            if len(freq_ranges) > 0:
                freq_ranges[len(freq_ranges)-2] = freq_ranges[len(freq_ranges)-2]
            freq_ranges.append(0)
        freq_ranges[len(freq_ranges)-1] = freq_ranges[len(freq_ranges)-1] + freq[i]
    for i in range(len(freq_ranges)):
        freq_ranges[i] = (freq_ranges[i] / np.array(freq_ranges).max())
    return [i * 400 for i in freq_ranges]

I multiply each value by 400 at the end so that turtle will draw over a large part of the screen.

When I run the code one line is usually much higher than all of the other lines (which is to be expected because each one is a percent of the largest one). The problem is that it doesn't change at all when I play music or even certain frequencies. It always looks somewhat like this (with the bars moving at random):

Turtle Eq

Does anyone have any idea what the problem is? Here is my full code:

import pyaudio
import struct
import numpy as np
from scipy.fftpack import fft
import turtle
import time

def update_graph(frequencies):
    for i in range(len(eq_bars)):

        eq_bars[i].penup()
        eq_bars[i].sety(-200)
        eq_bars[i].setx(-230+(i*15))
        eq_bars[i].setheading(90)
        eq_bars[i].pendown()
        eq_bars[i].fd(frequencies[i]) # go up by the amount of the current frequency
        eq_bars[i].penup()
        eq_bars[i].setx(1+(i*20))
    for eq_bar in eq_bars:
        eq_bar.clear()


def split_freq(freq): # splits given sound frequencies into groups of frequencies to feed into turtle
    freq_ranges = []
    for i in range(len(freq)-1): # split the frequencies into 32 groups
        if i % abs((len(freq)//32)) == 0:
            if len(freq_ranges) > 0:
                freq_ranges[len(freq_ranges)-2] = freq_ranges[len(freq_ranges)-2]
            freq_ranges.append(0)
        freq_ranges[len(freq_ranges)-1] = freq_ranges[len(freq_ranges)-1] + freq[i]
    for i in range(len(freq_ranges)):
        freq_ranges[i] = (freq_ranges[i] / np.array(freq_ranges).max())
    return [i * 400 for i in freq_ranges]


CHUNK = 2**10
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

p = pyaudio.PyAudio()
stream=p.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,
              output=True, frames_per_buffer=CHUNK)

wn = turtle.Screen()
wn.bgcolor("black")
wn.setup(width = 600, height = 600)
wn.title("Audio Visualizer")
wn.delay(0)

eq_bars = []

for i in range(32):
    eq_bars.append(turtle.Turtle())

    eq_bars[i].hideturtle()

    eq_bars[i].speed(0)
    eq_bars[i].pensize(5)
    eq_bars[i].color("white")
    eq_bars[i].penup()
    eq_bars[i].sety(-200)
    eq_bars[i].setx(-230+(i*15))
    eq_bars[i].setheading(90)
    eq_bars[i].pendown()
    eq_bars[i].fd(100)
    eq_bars[i].penup()
    eq_bars[i].setx(1+(i*20))



x = np.arange(0, 2*CHUNK, 2)
x_fft = np.linspace(0, RATE, CHUNK)

while True:

    data = struct.unpack(str(CHUNK*CHANNELS) + 'h', stream.read(CHUNK))
    data = stream.read(CHUNK)
    data = np.array(struct.unpack(str(2*CHUNK) + 'B', data), dtype='b')[::2] + 127

    y_fft = fft(data)
    y_fft = np.abs(y_fft[:CHUNK]) * 2 / (256 * CHUNK)
    print(len(y_fft))
    turtle_data = split_freq(y_fft)
    update_graph(turtle_data)
Ethan Posner
  • 343
  • 1
  • 2
  • 14
  • You should use a smooth window function before taking the FFT. – Nils Werner Dec 08 '19 at 21:25
  • Amplitude is something like summed squared amplitude. The given code is not sufficient to run it all by itself. You could use a simple piece of flute music to check that everything is working together. – NoDataDumpNoContribution Dec 08 '19 at 21:38
  • I tried playing just individual frequencies into it and it changes somewhat, but doesn't change on certain bands like I want it to. I think part of the problem is that each band is a percentage of the largest band (which is why in my screenshot two of the bands are as high as they will go). Also, it should be shown logarithmically, but I am not sure how to do this. – Ethan Posner Dec 08 '19 at 23:53

0 Answers0