SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 6:12 pm

All done.

Image

Video of it in action below:
http://www.youtube.com/watch?v=Du0zp7AjlBY

The code:

Code: Select all

#!/usr/bin/env python

# 8 bar Audio equaliser using MCP2307
 
import alsaaudio as aa
import smbus
from time import sleep
from struct import unpack
import numpy as np

bus=smbus.SMBus(0)  	#Use '1' for newer Pi boards;

ADDR   = 0x20			#The I2C address of MCP23017
DIRA   = 0x00			#PortA I/O direction, by pin. 0=output, 1=input
DIRB   = 0x01			#PortB I/O direction, by pin. 0=output, 1=input
BANKA  = 0x12			#Register address for Bank A
BANKB  = 0x13			#Register address for Bank B

#Set up the 23017 for 16 output pins
bus.write_byte_data(ADDR, DIRA, 0);  #all zeros = all outputs on Bank A
bus.write_byte_data(ADDR, DIRB, 0);  #all zeros = all outputs on Bank B

def TurnOffLEDS ():
	bus.write_byte_data(ADDR, BANKA, 0xFF)  #set all columns high
	bus.write_byte_data(ADDR, BANKB, 0x00)  #set all rows low

def Set_Column(row, col):
	TurnOffLEDS()
	bus.write_byte_data(ADDR, BANKA, col)
	bus.write_byte_data(ADDR, BANKB, row)
			
# Initialise matrix
TurnOffLEDS()

# Set up audio
sample_rate = 44100
no_channels = 2
chunk = 512 # Use a multiple of 8
data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NORMAL)
data_in.setchannels(no_channels)
data_in.setrate(sample_rate)
data_in.setformat(aa.PCM_FORMAT_S16_LE)
data_in.setperiodsize(chunk)

def calculate_levels(data, chunk,sample_rate):
	# Convert raw data to numpy array
	data = unpack("%dh"%(len(data)/2),data)
	data = np.array(data, dtype='h')
	# Apply FFT - real data so rfft used
	fourier=np.fft.rfft(data)
	# Remove last element in array to make it the same size as chunk
	fourier=np.delete(fourier,len(fourier)-1)
	# Find amplitude
	power = np.log10(np.abs(fourier))**2
	# Araange array into 8 rows for the 8 bars on LED matrix
	power = np.reshape(power,(8,chunk/8))
	matrix= np.int_(np.average(power,axis=1)/4)
	return matrix

print "Processing....."

while True:
	TurnOffLEDS()
	# Read data from device	
	l,data = data_in.read()
	data_in.pause(1) # Pause capture whilst RPi processes data
	if l:
		# catch frame error
		try:
			matrix=calculate_levels(data, chunk,sample_rate)
			for i in range (0,8):
				Set_Column((1<<matrix[i])-1,0xFF^(1<<i))

		except audioop.error, e:
			if e.message !="not a whole number of frames":
				raise e
	sleep(0.001)
	data_in.pause(0) # Resume capture
I got over the remaining problems for use with numpy. It is important that you capture in NORMAL (block) mode to always have the same set size of data. It has been running for 5 hours today with no lock ups/underruns/overflows.

The i2c part of the code is well documented so I'll just explain a few bits I didn't comment in the code. The original code referenced by yamanoorsai did not make good use of the powerful numpy routines. For starters the audio data is real (integers) and rfft is approriate for these arrays.
As I was using 8 columns for the equaliser, I arranged the array into 8 rows (each with 64 elements (chunk/8)). These numbers represent the 'amplitudes' for the first 64 frequencies in jumps of (0.5*sample_rate/chunk) (0.5*44100/512= 43 Hz) i.e row 1 is the amplitudes for the following frequencies:

0, 43, 86,.......,2713
2756, 2799..............
.
.
19294,...........,22007 (row 8)

I then took the mean for each row (very crude I know) to return 8 values for the LED matrix.

There are too many areas for improvement to talk about. The most obvious one is to focus on the frequencies more applicable to music/speech etc. (maybe just 60-5000 Hz) and ignore the rest.
I hope some of you have a laugh with this - it is very cool when hooked up to an iPod or the radio.

If some audiophiles could post their successes or suggestions for improvement, I would be grateful (so that I can use it in my lessons!)
Last edited by SpaceGerbil on Wed Mar 20, 2013 6:34 pm, edited 1 time in total.

texy
Forum Moderator
Forum Moderator
Posts: 5174
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 6:19 pm

Cool and really impressive. Let us know when you have it working without a usb soundcard ;)

Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 6:33 pm

The only possibility is the PCM pin, which apparently does not work on my version.

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 7:15 pm

texy wrote:Cool and really impressive. Let us know when you have it working without a usb soundcard ;)

Texy
Sorry - I was being dumb. I've actually done this on my laptop (running an audio file on the hard drive). The same code did not work on the RPi. Actually it did, but with blips as the FFTs were processed and the pins written to.
What I did was to read a chunk of audio and then write the chunk (play) whilst simultaneously processing it. No problems on my I7 PC and my I5 laptop. A different matter on the Pi.

texy
Forum Moderator
Forum Moderator
Posts: 5174
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 8:09 pm

SpaceGerbil wrote:
texy wrote:Cool and really impressive. Let us know when you have it working without a usb soundcard ;)

Texy
Sorry - I was being dumb. I've actually done this on my laptop (running an audio file on the hard drive). The same code did not work on the RPi. Actually it did, but with blips as the FFTs were processed and the pins written to.
...any chance you could share the code?

Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Wed Mar 20, 2013 8:25 pm

Will do. I'll get it off the laptop tomorrow. I might have another look at the RPi code - it has been on the backburner.

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Fri Mar 22, 2013 5:38 pm

2 channel volume analyser.
No USB audio card used for either input or output (in case you do not have one).
The file is on the SD card in wav form. Audio through HDMI.

Video here:
http://www.youtube.com/watch?v=xh6_4zVYLok

Code: Select all

#!/usr/bin/env python
#
# Audio 2 channel volume analyser using MCP2307
#
# Audio from wav file on SD card
#
import alsaaudio as aa
import audioop
from time import sleep
import smbus
import struct
import numpy as np
import wave

bus=smbus.SMBus(0)  	#Use '1' for newer Pi boards;
ADDR   = 0x20			#The I2C address of MCP23017
DIRA   = 0x00			#PortA I/O direction, by pin. 0=output, 1=input
DIRB   = 0x01			#PortB I/O direction, by pin. 0=output, 1=input
BANKA  = 0x12			#Register address for Bank A
BANKB  = 0x13			#Register address for Bank B

#Set up the 23017 for 16 output pins
bus.write_byte_data(ADDR, DIRA, 0);  #all zeros = all outputs on Bank A
bus.write_byte_data(ADDR, DIRB, 0);  #all zeros = all outputs on Bank B

def TurnOffLEDS ():
	bus.write_byte_data(ADDR, BANKA, 0xFF)  #set all columns high
	bus.write_byte_data(ADDR, BANKB, 0x00)  #set all rows low

def Set_Column(row, col):
	bus.write_byte_data(ADDR, BANKA, col)
	bus.write_byte_data(ADDR, BANKB, row)
			
# Initialise matrix
TurnOffLEDS()
matrix=[0,0,0,0,0,0,0,0]

# Set up audio
wavfile = wave.open('/home/pi/python_programs/NorwegianWood.wav','r')
sample_rate = wavfile.getframerate()
no_channels = wavfile.getnchannels()
chunk = 1024
output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
output.setchannels(no_channels)
output.setrate(sample_rate)
output.setformat(aa.PCM_FORMAT_S16_LE)
output.setperiodsize(chunk)

print "Processing....."

data = wavfile.readframes(chunk)
while data!='':
	output.write(data)
	# Split channel data and find maximum volume	
	channel_l=audioop.tomono(data, 2, 1.0, 0.0)
	channel_r=audioop.tomono(data, 2, 0.0, 1.0)
	max_vol_factor =5000
	max_l = audioop.max(channel_l,2)/max_vol_factor
	max_r = audioop.max(channel_r,2)/max_vol_factor
	# Write to 8x8 LED
	for i in range (0,4):
		Set_Column((1<<max_l)-1,0xFF^(1<<i))
	TurnOffLEDS()
	for i in range (4,8):
		Set_Column((1<<max_r)-1,0xFF^(1<<i))
	data = wavfile.readframes(chunk)
	TurnOffLEDS()
NB The equivalent for the FFT is working (over 95% CPU usage! and I'm overclocking..), but doesn't look anywhere near as cool yet. Working on an appropriate power spectrum for the frequencies.

Watch this space.

Were you after something like this texy?

stulevine
Posts: 7
Joined: Sun Jan 13, 2013 7:39 pm

Re: Reading Audio stream for FFT

Sat Mar 23, 2013 1:08 pm

I just purchased a bicolor 8x8 LED Sq and an Electret Microphone Amplifier - MAX4466 with Adjustable Gain. I have an MCP2308 hooked up to the SPI port on the RPi that I use for a few other analog sensors (Photo resistor, pressure sensor, etc). However, after purchasing the former items I want to use the mic and the LED panel as a spectrum analyzer. I've got the LED panel all set and the mic is connected to the ADC port 4. I did some google searches on how to process the data from the mic using FTT so I can output the frequencies to the LED panel. Your code below is the closest thing I've found so far. I was wondering how hard it would be to take the output from the MCP2308 ADC port 4 and mod your code to receive the input from the mic? I have all the tools spidev python and what you use in your code, but I'm having trouble figuring out where the pieces fit together. Thanks in advance.

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Sat Mar 23, 2013 3:14 pm

When you say the LED matrix is set up, have you tested it?

Are you using one or two MCP2308 I/O expanders?

The MCP23017 I/O has 16 outputs - I use 8 for the rows and 8 for the columns; this allows me to multiplex the columns. It is 16 bit, but only 8 bits are needed for the LED matrix.

If you are grounding all of the columns, then all of the LEDS for a given row will light when it is switched on.

stulevine
Posts: 7
Joined: Sun Jan 13, 2013 7:39 pm

Re: Reading Audio stream for FFT

Sun Mar 24, 2013 12:39 pm

Actually, I don't need an IO expander for the LED 8x8 bicolor matrix since it has an i2c backpack that lets me hook it up to the i2c bus on the RPi. However, what I'm most interested in doing is taking the analog microphone input connected to one of the channels of the MCP3008 10bit ADC (hooked up to the SPI interface of the RPi) and doing some spectrum analysis on it via FFT on the RPi and graphing said analysis on that LED 8x8 Matrix. I already know how to read the input from the microphone using spidev.

Here's the matrix in action via a python script that randomly set's the pixels to one of 3 colors:
Image

So with all that said, I was just wondering if you had any tips on taking the microphone input, as apposed to reading an audio stream (as in your examples), and graphing the spectral analysis on that 8x8 LED matrix above.

Thanks again.

Stuart

BTW, I did get the ADC part number wrong in the original post. sorry bout that.

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Sun Mar 24, 2013 1:23 pm

OK, that is much clearer.

Am I correct that the output is unsigned 10-bit (2 channels?).

If that is the case, the audio will be low quality (for instance wav files are signed 16 bit). You should still be able to extract maximum volumes easily enough using a numpy array, but frequency analysis will be spurious.

Is this link helpful?

http://learn.adafruit.com/reading-a-ana ... -pi/script

stulevine
Posts: 7
Joined: Sun Jan 13, 2013 7:39 pm

Re: Reading Audio stream for FFT

Sun Mar 24, 2013 1:38 pm

Actually the microphone I'm using is the Electret Microphone Amplifier - MAX4466 with Adjustable Gain from Adafruit and has only one channel of output and hence I only use one input on the MCP3008. It's supposed to have a very quiet (low noise) amplifier based on the description. And they do something in a tutorial with an Arduino board that I what to replicate on the RPi.

Anyway, I'll take a look at the url and let you know if that helps.

BTW, here are the specs for the MCP3008 ADC I'm using.

stulevine
Posts: 7
Joined: Sun Jan 13, 2013 7:39 pm

Re: Reading Audio stream for FFT

Sun Mar 24, 2013 1:48 pm

Oh, regarding that link, that's where I originally started with the MCP3008 IC and decided to pursue using the IC with the hardware SPI of the Raspberry Pi.

So, with that said, my problem is not reading the analog input as I am already able to do that via spidev (Installed now under Raspian Wheezy) using a much simpler approach with less GPIO pins utilized. Here's the python code if you are interested.

So, I want to take what I read from analog pin 4 and process it with FTT and graph it on the 8x8 matrix like they do on the Arduino Music visualizer tutorial :) I'm just not quite understanding how to take that voltage and process it via FTT like you do in your scripts.

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Sun Mar 24, 2013 3:39 pm

Take a look at the 'piccolo' code for the Tiny Arduino Music Visualizer:

https://github.com/adafruit/piccolo/blo ... iccolo.pde

The important bit is the capture at the end:

Code: Select all

ISR(ADC_vect) { // Audio-sampling interrupt
  static const int16_t noiseThreshold = 4;
  int16_t              sample         = ADC; // 0-1023

  capture[samplePos] =
    ((sample > (512-noiseThreshold)) &&
     (sample < (512+noiseThreshold))) ? 0 :
    sample - 512; // Sign-convert for FFT; -512 to +511

  if(++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE); // Buffer full, interrupt off
}
The capture array (or buffer as they call it) is equivalent to the 'data' array I use (after the raw audio data is processed). The key difference is that your data will have values from -512 to 511 (signed 10 bit) rather than the processed audio which has values from -32768 to 32767 (signed 16 bit). The rest of the code should pretty much work as it is in the 'calculate_level' function with a few tweaks.

texy
Forum Moderator
Forum Moderator
Posts: 5174
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Reading Audio stream for FFT

Mon Mar 25, 2013 11:34 am

SpaceGerbil wrote:2 channel volume analyser.
No USB audio card used for either input or output (in case you do not have one).
The file is on the SD card in wav form. Audio through HDMI.

Video here:
http://www.youtube.com/watch?v=xh6_4zVYLok

Code: Select all

#!/usr/bin/env python
#
# Audio 2 channel volume analyser using MCP2307
#
# Audio from wav file on SD card
#
import alsaaudio as aa
import audioop
from time import sleep
import smbus
import struct
import numpy as np
import wave

bus=smbus.SMBus(0)  	#Use '1' for newer Pi boards;
ADDR   = 0x20			#The I2C address of MCP23017
DIRA   = 0x00			#PortA I/O direction, by pin. 0=output, 1=input
DIRB   = 0x01			#PortB I/O direction, by pin. 0=output, 1=input
BANKA  = 0x12			#Register address for Bank A
BANKB  = 0x13			#Register address for Bank B

#Set up the 23017 for 16 output pins
bus.write_byte_data(ADDR, DIRA, 0);  #all zeros = all outputs on Bank A
bus.write_byte_data(ADDR, DIRB, 0);  #all zeros = all outputs on Bank B

def TurnOffLEDS ():
	bus.write_byte_data(ADDR, BANKA, 0xFF)  #set all columns high
	bus.write_byte_data(ADDR, BANKB, 0x00)  #set all rows low

def Set_Column(row, col):
	bus.write_byte_data(ADDR, BANKA, col)
	bus.write_byte_data(ADDR, BANKB, row)
			
# Initialise matrix
TurnOffLEDS()
matrix=[0,0,0,0,0,0,0,0]

# Set up audio
wavfile = wave.open('/home/pi/python_programs/NorwegianWood.wav','r')
sample_rate = wavfile.getframerate()
no_channels = wavfile.getnchannels()
chunk = 1024
output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
output.setchannels(no_channels)
output.setrate(sample_rate)
output.setformat(aa.PCM_FORMAT_S16_LE)
output.setperiodsize(chunk)

print "Processing....."

data = wavfile.readframes(chunk)
while data!='':
	output.write(data)
	# Split channel data and find maximum volume	
	channel_l=audioop.tomono(data, 2, 1.0, 0.0)
	channel_r=audioop.tomono(data, 2, 0.0, 1.0)
	max_vol_factor =5000
	max_l = audioop.max(channel_l,2)/max_vol_factor
	max_r = audioop.max(channel_r,2)/max_vol_factor
	# Write to 8x8 LED
	for i in range (0,4):
		Set_Column((1<<max_l)-1,0xFF^(1<<i))
	TurnOffLEDS()
	for i in range (4,8):
		Set_Column((1<<max_r)-1,0xFF^(1<<i))
	data = wavfile.readframes(chunk)
	TurnOffLEDS()
NB The equivalent for the FFT is working (over 95% CPU usage! and I'm overclocking..), but doesn't look anywhere near as cool yet. Working on an appropriate power spectrum for the frequencies.

Watch this space.

Were you after something like this texy?
Apologies for the late reply, I,ve been busy on other projects ;)
What I,d like to see is
1..the pi play music file (wav, mp3, or whatever)
2..at the same time analyse the audio and give an amplitude value stored in a variable for say 5 frequency bands
I,m not interested in any additional hardware at this time - I,m not planning on adding any LED's.

I haven't run your code, but I've seen the video and it looks like it will do what I,m looking for :D

Cheers,
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Tue Mar 26, 2013 12:04 am

What I'd like to see is:
1..the pi play music file (wav, mp3, or whatever)
2..at the same time analyse the audio and give an amplitude value stored in a variable for say 5 frequency bands
I guessed that the first one was coming....

I got the FFT working with some nice touches which I will explain after the code.

Here is the code for FFT on a wav file on the SD card:

Code: Select all

#!/usr/bin/env python

# 8 band Audio equaliser from wav file
 
import alsaaudio as aa
import smbus
from struct import unpack
import numpy as np
import wave

bus=smbus.SMBus(0)  	#Use '1' for newer Pi boards;

ADDR   = 0x20			#The I2C address of MCP23017
DIRA   = 0x00			#PortA I/O direction, by pin. 0=output, 1=input
DIRB   = 0x01			#PortB I/O direction, by pin. 0=output, 1=input
BANKA  = 0x12			#Register address for Bank A
BANKB  = 0x13			#Register address for Bank B

#Set up the 23017 for 16 output pins
bus.write_byte_data(ADDR, DIRA, 0);  #all zeros = all outputs on Bank A
bus.write_byte_data(ADDR, DIRB, 0);  #all zeros = all outputs on Bank B

def TurnOffLEDS ():
	bus.write_byte_data(ADDR, BANKA, 0xFF)  #set all columns high
	bus.write_byte_data(ADDR, BANKB, 0x00)  #set all rows low

def Set_Column(row, col):
	bus.write_byte_data(ADDR, BANKA, col)
	bus.write_byte_data(ADDR, BANKB, row)
			
# Initialise matrix
TurnOffLEDS()
matrix    = [0,0,0,0,0,0,0,0]
power     = []
weighting = [2,2,8,8,16,32,64,64] # Change these according to taste

# Set up audio
wavfile = wave.open('/home/pi/python_programs/NorwegianWood.wav','r')
sample_rate = wavfile.getframerate()
no_channels = wavfile.getnchannels()
chunk       = 4096 # Use a multiple of 8
output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
output.setchannels(no_channels)
output.setrate(sample_rate)
output.setformat(aa.PCM_FORMAT_S16_LE)
output.setperiodsize(chunk)

# Return power array index corresponding to a particular frequency
def piff(val):
	return int(2*chunk*val/sample_rate)
	
def calculate_levels(data, chunk,sample_rate):
	global matrix
	# Convert raw data (ASCII string) to numpy array
	data = unpack("%dh"%(len(data)/2),data)
	data = np.array(data, dtype='h')
	# Apply FFT - real data
	fourier=np.fft.rfft(data)
	# Remove last element in array to make it the same size as chunk
	fourier=np.delete(fourier,len(fourier)-1)
	# Find average 'amplitude' for specific frequency ranges in Hz
	power = np.abs(fourier)	
	matrix[0]= int(np.mean(power[piff(0)    :piff(156):1]))
	matrix[1]= int(np.mean(power[piff(156)  :piff(313):1]))
	matrix[2]= int(np.mean(power[piff(313)  :piff(625):1]))
	matrix[3]= int(np.mean(power[piff(625)  :piff(1250):1]))
	matrix[4]= int(np.mean(power[piff(1250) :piff(2500):1]))
	matrix[5]= int(np.mean(power[piff(2500) :piff(5000):1]))
	matrix[6]= int(np.mean(power[piff(5000) :piff(10000):1]))
	matrix[7]= int(np.mean(power[piff(10000):piff(20000):1]))
	# Tidy up column values for the LED matrix
	matrix=np.divide(np.multiply(matrix,weighting),1000000)
	# Set floor at 0 and ceiling at 8 for LED matrix
	matrix=matrix.clip(0,8) 
	return matrix

# Process audio file	
print "Processing....."
data = wavfile.readframes(chunk)
while data!='':
	output.write(data)	
	matrix=calculate_levels(data, chunk,sample_rate)
	for i in range (0,8):
		Set_Column((1<<matrix[i])-1,0xFF^(1<<i))	
	data = wavfile.readframes(chunk)
	TurnOffLEDS()
The clever bit is the matrix[n] statements in the calculate_levels function. You can choose whatever frequency ranges you wish and 'piff' works out the relevant indexes (indices?) in the numpy array for the 'power' for those frequencies (it's not the power/amplitude in any conventional sense, but serves its purpose).

I then get numpy to work its magic. Boy it's quick.

If you are looking at 5 frequency bands then use matrix[0-4] with frequency ranges appropriate for your application.

The things to experiment with are the factor of 1000000 I use when tidying up the column values and the weighting I chose for the 8 bands/columns on the LED matrix. The simple rule I loosely followed was that as the frequency doubles, the power halves. A check of the maximum values the matrix array throws up will give you an idea of what factor to use. Play around with the weightings to suit your taste. The numpy 'clip' catches any values above 8 which throw up an error when writing to the LEDs.

CPU usage is way down on what I had before, but the audio may still pop/stutter if you are moving the mouse. I'm just about to thread some of the processes to see if this helps (which it should).

OK to point 1......

I have installed audiotools on the RPi. WOW. Overkill in the extreme, but with it I can open wav, ogg, flac etc. I am being lazy at this stage, so I transcode the chosen audio file format to wav and run the code above. The only format I get errors with are mp3s.

There is not much info out there on audiotools and mp3, so if anyone can help me out it would be much appreciated.

I have nearly cracked a 'Darth Vader' voice changer on the RPi, so I would like to put this baby to bed...

fxmaker
Posts: 43
Joined: Fri Dec 07, 2012 6:37 pm

Re: Reading Audio stream for FFT

Fri Apr 05, 2013 3:25 pm

Hi All,

Could you tell me the number of 1024 element real FFT's per second you believe you are able to get from NumPy? Might you have a similar number of 4096 element FFT's?

Thank you

SpaceGerbil
Posts: 27
Joined: Sat Feb 02, 2013 10:03 am

Re: Reading Audio stream for FFT

Fri Apr 05, 2013 8:05 pm

fxmaker wrote: Could you tell me the number of 1024 element real FFT's per second you believe you are able to get from NumPy? Might you have a similar number of 4096 element FFT's?
Interesting question. I doubled the chunk size until I got 'smooth' audio (no clicks as the stream was interrupted) without paying too much attention to optimising the code. Have you tried timing a set number of calls to the FFT? From that it is easy to find the period of one call, then the frequency.

I'll have a look at it tomorrow.

fxmaker
Posts: 43
Joined: Fri Dec 07, 2012 6:37 pm

Re: Reading Audio stream for FFT

Fri Apr 05, 2013 8:40 pm

SpaceGerbil wrote:
fxmaker wrote: Could you tell me the number of 1024 element real FFT's per second you believe you are able to get from NumPy? Might you have a similar number of 4096 element FFT's?
Interesting question. I doubled the chunk size until I got 'smooth' audio (no clicks as the stream was interrupted) without paying too much attention to optimising the code. Have you tried timing a set number of calls to the FFT? From that it is easy to find the period of one call, then the frequency.

I'll have a look at it tomorrow.
Thank you. Unfortunately, I cannot try this myself as I'm currently flat on my back with back troubles :(

amicoleo
Posts: 4
Joined: Thu Jul 11, 2013 4:32 pm

Re: Reading Audio stream for FFT

Mon Jul 15, 2013 9:16 am

Hi everybody!

I need to resuscitate this forum because I had problem having the python code for processing audio input working (I used the code SpaceGerbil posted at the beginning of the second page of this thread).

Basically it fails saying:

Code: Select all

alsaaudio.ALSAAudioError: Capture data too large. Try decreasing period size 
Can one of those below can be the reason?

- soundcard (I'm using the webcam mic as an audio input)
- specific os distro (I have the standard Raspbian Wheezy)
- particular os tricks like overclocking or other kind of wizardry (I didn't do any)

Or there might be others?

Thanks!

togiles
Posts: 10
Joined: Fri Oct 11, 2013 2:11 am

Re: Reading Audio stream for FFT

Fri Oct 11, 2013 3:35 am

This was just what I was looking for, thanks for sharing! I'll send a link to a video of the light music sync project I've been working on for halloween once I get things wrapped up. Will post code here as well for others benefit (as I've modified it a bit for my specific setup).

Thanks again!

togiles
Posts: 10
Joined: Fri Oct 11, 2013 2:11 am

Re: Reading Audio stream for FFT

Mon Oct 14, 2013 3:20 pm

Here is a link to the final product (at least final as of right now):

https://plus.google.com/102015744723309 ... kp3qvTJCfA

Working on a blog post with all the code, details, etc... Thanks again for the great resource here as it pointed me in the right direction much quicker than I would have made it otherwise.

Explicat
Posts: 7
Joined: Tue Aug 06, 2013 3:45 pm

Re: Reading Audio stream for FFT

Fri Nov 08, 2013 11:15 pm

Wow, this is unbelievable awesome.
I'll try to post a video of what I'm using a part of your code for.

However, I'm still trying to figure out how to use a usb audio card instead of the Pi's analog output.
It's this line:

Code: Select all

output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL,card)
The alsaaudio docs http://pyalsaaudio.sourceforge.net/libalsaaudio.html state that the card paramter can be a name from the cards() method.
cards() returns [u'Dongle', u'ALSA'], aa.PWM(..., cards()[0]) leads to an error though.
Did someone manage to output the audio via usb?

frodeaux
Posts: 1
Joined: Thu Nov 14, 2013 8:35 pm

Re: Reading Audio stream for FFT

Thu Nov 14, 2013 8:37 pm

Great bit of code but running the code from SpaceGerbil often produces the following error:

/usr/lib/pymodules/python2.7/numpy/core/fromnumeric.py:2374: RuntimeWarning: invalid value encountered in double_scalars
return mean(axis, dtype, out)
Traceback (most recent call last):
File "./BASEFFT.py", line 113, in <module>
matrix=calculate_levels(data, chunk,sample_rate)
File "./BASEFFT.py", line 100, in calculate_levels
matrix[6]= int(np.mean(power[piff(5000) :piff(10000):1]))
ValueError: cannot convert float NaN to integer

any clues as to why?

togiles
Posts: 10
Joined: Fri Oct 11, 2013 2:11 am

Re: Reading Audio stream for FFT

Fri Nov 15, 2013 4:10 am

togiles wrote:Here is a link to the final product (at least final as of right now):

https://plus.google.com/102015744723309 ... kp3qvTJCfA

Working on a blog post with all the code, details, etc... Thanks again for the great resource here as it pointed me in the right direction much quicker than I would have made it otherwise.
I've just uploaded all of my code for my project here:

https://bitbucket.org/togiles/lightshowpi

Thanks for the great samples to get me started with numpy to do the FFT... it's great! Final project plays any wav / mp3 / midi / ogg / others... and synchronizes 8 channels on GPIO to 9 light channels as shown in the video. Feel free to take from anything I've done, as I drew quite a bit of inspiration from others throughout my project. I'd be interested in hearing back though of any other enhancements / changes anyone may make.

Happy coding!
Last edited by togiles on Sun Jan 05, 2014 6:30 am, edited 1 time in total.

Return to “Python”