#include "analyze_fft1024.h" | #include "analyze_fft1024.h" | ||||
#include "sqrt_integer.h" | #include "sqrt_integer.h" | ||||
#include "utility/dspinst.h" | #include "utility/dspinst.h" | ||||
#include "arm_math.h" | |||||
// TODO: this should be a class member, so more than one FFT can be used | |||||
static arm_cfft_radix4_instance_q15 fft_inst; | |||||
void AudioAnalyzeFFT1024::init(void) | |||||
{ | |||||
// TODO: replace this with static const version | |||||
arm_cfft_radix4_init_q15(&fft_inst, 1024, 0, 1); | |||||
//state = 0; | |||||
//outputflag = false; | |||||
} | |||||
// 140312 - PAH - slightly faster copy | // 140312 - PAH - slightly faster copy | ||||
static void copy_to_fft_buffer(void *destination, const void *source) | static void copy_to_fft_buffer(void *destination, const void *source) | ||||
state = 4; | state = 4; | ||||
break; | break; | ||||
} | } | ||||
/* | |||||
copy_to_fft_buffer(buffer, prevblock->data); | |||||
copy_to_fft_buffer(buffer+256, block->data); | |||||
if (window) apply_window_to_fft_buffer(buffer, window); | |||||
arm_cfft_radix4_q15(&fft_inst, buffer); | |||||
if (count == 0) { | |||||
for (int i=0; i < 128; i++) { | |||||
uint32_t tmp = *((uint32_t *)buffer + i); | |||||
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); | |||||
sum[i] = magsq / naverage; | |||||
} | |||||
} else { | |||||
for (int i=0; i < 128; i++) { | |||||
uint32_t tmp = *((uint32_t *)buffer + i); | |||||
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp); | |||||
sum[i] += magsq / naverage; | |||||
} | |||||
} | |||||
if (++count == naverage) { | |||||
count = 0; | |||||
for (int i=0; i < 128; i++) { | |||||
output[i] = sqrt_uint32_approx(sum[i]); | |||||
} | |||||
outputflag = true; | |||||
} | |||||
*/ | |||||
} | } | ||||
#define analyze_fft1024_h_ | #define analyze_fft1024_h_ | ||||
#include "AudioStream.h" | #include "AudioStream.h" | ||||
#include "arm_math.h" | |||||
// windows.c | // windows.c | ||||
extern "C" { | extern "C" { | ||||
class AudioAnalyzeFFT1024 : public AudioStream | class AudioAnalyzeFFT1024 : public AudioStream | ||||
{ | { | ||||
public: | public: | ||||
AudioAnalyzeFFT1024(uint8_t navg = 1, const int16_t *win = AudioWindowHanning1024) | |||||
: AudioStream(1, inputQueueArray), window(win), | |||||
state(0), outputflag(false) { init(); } | |||||
AudioAnalyzeFFT1024() : AudioStream(1, inputQueueArray), | |||||
window(AudioWindowHanning1024), state(0), outputflag(false) { | |||||
arm_cfft_radix4_init_q15(&fft_inst, 1024, 0, 1); | |||||
} | |||||
bool available() { | bool available() { | ||||
if (outputflag == true) { | if (outputflag == true) { | ||||
outputflag = false; | outputflag = false; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
float read(unsigned int binNumber) { | |||||
if (binNumber > 511) return 0.0; | |||||
return (float)(output[binNumber]) * (1.0 / 16384.0); | |||||
} | |||||
float read(unsigned int binFirst, unsigned int binLast) { | |||||
if (binFirst > binLast) { | |||||
unsigned int tmp = binLast; | |||||
binLast = binFirst; | |||||
binFirst = tmp; | |||||
} | |||||
if (binFirst > 511) return 0.0; | |||||
if (binLast > 511) binLast = 511; | |||||
uint32_t sum = 0; | |||||
do { | |||||
sum += output[binFirst++]; | |||||
} while (binFirst < binLast); | |||||
return (float)sum * (1.0 / 16384.0); | |||||
} | |||||
void averageTogether(uint8_t n) { | |||||
// not implemented yet (may never be, 86 Hz output rate is ok) | |||||
} | |||||
void windowFunction(const int16_t *w) { | |||||
window = w; | |||||
} | |||||
virtual void update(void); | virtual void update(void); | ||||
uint16_t output[512] __attribute__ ((aligned (4))); | uint16_t output[512] __attribute__ ((aligned (4))); | ||||
private: | private: | ||||
//uint8_t naverage; | //uint8_t naverage; | ||||
volatile bool outputflag; | volatile bool outputflag; | ||||
audio_block_t *inputQueueArray[1]; | audio_block_t *inputQueueArray[1]; | ||||
arm_cfft_radix4_instance_q15 fft_inst; | |||||
}; | }; | ||||
#endif | #endif |
#include "analyze_fft256.h" | #include "analyze_fft256.h" | ||||
#include "sqrt_integer.h" | #include "sqrt_integer.h" | ||||
#include "utility/dspinst.h" | #include "utility/dspinst.h" | ||||
#include "arm_math.h" | |||||
// TODO: this should be a class member, so more than one FFT can be used | |||||
static arm_cfft_radix4_instance_q15 fft_inst; | |||||
void AudioAnalyzeFFT256::init(void) | |||||
{ | |||||
// TODO: replace this with static const version | |||||
arm_cfft_radix4_init_q15(&fft_inst, 256, 0, 1); | |||||
//state = 0; | |||||
//outputflag = false; | |||||
} | |||||
// 140312 - PAH - slightly faster copy | // 140312 - PAH - slightly faster copy | ||||
static void copy_to_fft_buffer(void *destination, const void *source) | static void copy_to_fft_buffer(void *destination, const void *source) |
#define analyze_fft256_h_ | #define analyze_fft256_h_ | ||||
#include "AudioStream.h" | #include "AudioStream.h" | ||||
#include "arm_math.h" | |||||
// windows.c | // windows.c | ||||
extern "C" { | extern "C" { | ||||
class AudioAnalyzeFFT256 : public AudioStream | class AudioAnalyzeFFT256 : public AudioStream | ||||
{ | { | ||||
public: | public: | ||||
AudioAnalyzeFFT256(uint8_t navg = 8, const int16_t *win = AudioWindowHanning256) | |||||
: AudioStream(1, inputQueueArray), window(win), | |||||
prevblock(NULL), count(0), naverage(navg), outputflag(false) { init(); } | |||||
AudioAnalyzeFFT256() : AudioStream(1, inputQueueArray), | |||||
window(AudioWindowHanning256), prevblock(NULL), count(0), | |||||
naverage(8), outputflag(false) { | |||||
arm_cfft_radix4_init_q15(&fft_inst, 256, 0, 1); | |||||
} | |||||
bool available() { | bool available() { | ||||
if (outputflag == true) { | if (outputflag == true) { | ||||
outputflag = false; | outputflag = false; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
float read(unsigned int binNumber) { | |||||
if (binNumber > 127) return 0.0; | |||||
return (float)(output[binNumber]) * (1.0 / 16384.0); | |||||
} | |||||
float read(unsigned int binFirst, unsigned int binLast) { | |||||
if (binFirst > binLast) { | |||||
unsigned int tmp = binLast; | |||||
binLast = binFirst; | |||||
binFirst = tmp; | |||||
} | |||||
if (binFirst > 127) return 0.0; | |||||
if (binLast > 127) binLast = 127; | |||||
uint32_t sum = 0; | |||||
do { | |||||
sum += output[binFirst++]; | |||||
} while (binFirst < binLast); | |||||
return (float)sum * (1.0 / 16384.0); | |||||
} | |||||
void averageTogether(uint8_t n) { | |||||
if (n == 0) n == 1; | |||||
naverage = n; | |||||
} | |||||
void windowFunction(const int16_t *w) { | |||||
window = w; | |||||
} | |||||
virtual void update(void); | virtual void update(void); | ||||
//uint32_t cycles; | |||||
uint16_t output[128] __attribute__ ((aligned (4))); | uint16_t output[128] __attribute__ ((aligned (4))); | ||||
private: | private: | ||||
void init(void); | |||||
const int16_t *window; | const int16_t *window; | ||||
audio_block_t *prevblock; | audio_block_t *prevblock; | ||||
int16_t buffer[512] __attribute__ ((aligned (4))); | int16_t buffer[512] __attribute__ ((aligned (4))); | ||||
uint8_t naverage; | uint8_t naverage; | ||||
bool outputflag; | bool outputflag; | ||||
audio_block_t *inputQueueArray[1]; | audio_block_t *inputQueueArray[1]; | ||||
arm_cfft_radix4_instance_q15 fft_inst; | |||||
}; | }; | ||||
#endif | #endif |
// Create the Audio components. These should be created in the | // Create the Audio components. These should be created in the | ||||
// order data flows, inputs/sources -> processing -> outputs | // order data flows, inputs/sources -> processing -> outputs | ||||
// | // | ||||
AudioInputI2S audioInput; // audio shield: mic or line-in | |||||
AudioAnalyzeFFT256 myFFT(20); | |||||
AudioOutputI2S audioOutput; // audio shield: headphones & line-out | |||||
AudioInputI2S audioInput; // audio shield: mic or line-in | |||||
AudioSynthWaveformSine sinewave; | |||||
AudioAnalyzeFFT1024 myFFT; | |||||
AudioOutputI2S audioOutput; // audio shield: headphones & line-out | |||||
// Create Audio connections between the components | |||||
// | |||||
AudioConnection c1(audioInput, 0, audioOutput, 0); | |||||
AudioConnection c2(audioInput, 0, myFFT, 0); | |||||
AudioConnection c3(audioInput, 1, audioOutput, 1); | |||||
// Connect either the live input or synthesized sine wave | |||||
AudioConnection patchCord1(audioInput, 0, myFFT, 0); | |||||
//AudioConnection patchCord1(sinewave, 0, myFFT, 0); | |||||
// Create an object to control the audio shield. | |||||
// | |||||
AudioControlSGTL5000 audioShield; | AudioControlSGTL5000 audioShield; | ||||
void setup() { | void setup() { | ||||
// Audio connections require memory to work. For more | // Audio connections require memory to work. For more | ||||
// detailed information, see the MemoryAndCpuUsage example | // detailed information, see the MemoryAndCpuUsage example | ||||
audioShield.enable(); | audioShield.enable(); | ||||
audioShield.inputSelect(myInput); | audioShield.inputSelect(myInput); | ||||
audioShield.volume(0.6); | audioShield.volume(0.6); | ||||
// Configure the window algorithm to use | |||||
myFFT.windowFunction(AudioWindowHanning1024); | |||||
//myFFT.windowFunction(NULL); | |||||
// Create a synthetic sine wave, for testing | |||||
// To use this, edit the connections above | |||||
sinewave.amplitude(0.8); | |||||
sinewave.frequency(1034.007); | |||||
} | } | ||||
void loop() { | void loop() { | ||||
// each time new FFT data is available | // each time new FFT data is available | ||||
// print it all to the Arduino Serial Monitor | // print it all to the Arduino Serial Monitor | ||||
Serial.print("FFT: "); | Serial.print("FFT: "); | ||||
for (int i=0; i<128; i++) { | |||||
Serial.print(myFFT.output[i]); | |||||
Serial.print(","); | |||||
for (int i=0; i<40; i++) { | |||||
Serial.print(myFFT.read(i)); | |||||
//Serial.print(myFFT.output[i]); | |||||
Serial.print(" "); | |||||
} | } | ||||
Serial.println(); | Serial.println(); | ||||
} | } |
<tr class=top><th>Port</th><th>Purpose</th></tr> | <tr class=top><th>Port</th><th>Purpose</th></tr> | ||||
<tr class=odd><td align=center>In 0</td><td>Signal to convert to frequency bins</td></tr> | <tr class=odd><td align=center>In 0</td><td>Signal to convert to frequency bins</td></tr> | ||||
</table> | </table> | ||||
<h3>Parameters</h3> | |||||
<table class=doc align=center cellpadding=3> | |||||
<tr class=top><th>Name</th><th>Type</th><th>Function</th></tr> | |||||
<tr class=odd><td align=center>Num</td><td>Integer</td><td># FFTs to average</td></tr> | |||||
<tr class=odd><td align=center>Window</td><td>Array</td><td>Window method to use</td></tr> | |||||
</table> | |||||
<p>Extra description... Section only present if object has params</p> | |||||
<h3>Functions</h3> | <h3>Functions</h3> | ||||
<p class=func><span class=keyword>available</span>();</p> | <p class=func><span class=keyword>available</span>();</p> | ||||
<p class=desc>Returns true each time the FFT analysis produces new output data. | <p class=desc>Returns true each time the FFT analysis produces new output data. | ||||
</p> | </p> | ||||
<p class=func><span class=keyword>read</span>(binNumber);</p> | |||||
<p class=desc>Read a single frequency bin, from 0 to 127. The result is scaled | |||||
so 1.0 represents a full scale sine wave. | |||||
</p> | |||||
<p class=func><span class=keyword>read</span>(firstBin, lastBin);</p> | |||||
<p class=desc>Read several frequency bins, returning their sum. The higher | |||||
audio octaves are represented by many bins, which are typically read | |||||
as a group for audio visualization. | |||||
</p> | |||||
<p class=func><span class=keyword>averageTogether</span>(number);</p> | |||||
<p class=desc>New data is produced very radidly, approximately 344 times | |||||
per second. Multiple outputs can be averaged together, so available() | |||||
returns true at a slower rate. | |||||
</p> | |||||
<p class=func><span class=keyword>windowFunction</span>(window);</p> | |||||
<p class=desc>Set the window function to be used. AudioWindowHanning256 | |||||
is the default. Windowing may be disabled by NULL, but windowing | |||||
should be used for all non-periodic (music) signals, and all periodic | |||||
signals that are not exact integer division of the sample rate. | |||||
</p> | |||||
<h3>Notes</h3> | <h3>Notes</h3> | ||||
<p>The raw 16 bit output data bins may be access with myFFT.output[num], where | <p>The raw 16 bit output data bins may be access with myFFT.output[num], where | ||||
num is 0 to 127.</p> | num is 0 to 127.</p> | ||||
<p>TODO: caveats about spectral leakage vs frequency precision for arbitrary signals</p> | <p>TODO: caveats about spectral leakage vs frequency precision for arbitrary signals</p> | ||||
<p>Known bug in the library limits to only a single instance of this object. | |||||
This bug will be fixed someday... allowing 2 or more FFTs to run on simultaneously.</p> | |||||
<p>Window Types: | <p>Window Types: | ||||
<ul> | <ul> | ||||
<li><span class=literal>AudioWindowHanning256</span> (default)</li> | <li><span class=literal>AudioWindowHanning256</span> (default)</li> | ||||
<tr class=top><th>Port</th><th>Purpose</th></tr> | <tr class=top><th>Port</th><th>Purpose</th></tr> | ||||
<tr class=odd><td align=center>In 0</td><td>Signal to convert to frequency bins</td></tr> | <tr class=odd><td align=center>In 0</td><td>Signal to convert to frequency bins</td></tr> | ||||
</table> | </table> | ||||
<h3>Parameters</h3> | |||||
<table class=doc align=center cellpadding=3> | |||||
<tr class=top><th>Name</th><th>Type</th><th>Function</th></tr> | |||||
<tr class=odd><td align=center>Num</td><td>Integer</td><td># FFTs to average</td></tr> | |||||
<tr class=odd><td align=center>Window</td><td>Array</td><td>Window method to use</td></tr> | |||||
</table> | |||||
<p>Extra description... Section only present if object has params</p> | |||||
<h3>Functions</h3> | <h3>Functions</h3> | ||||
<p class=func><span class=keyword>available</span>();</p> | <p class=func><span class=keyword>available</span>();</p> | ||||
<p class=desc>Returns true each time the FFT analysis produces new output data. | <p class=desc>Returns true each time the FFT analysis produces new output data. | ||||
</p> | </p> | ||||
<p class=func><span class=keyword>read</span>(binNumber);</p> | |||||
<p class=desc>Read a single frequency bin, from 0 to 511. The result is scaled | |||||
so 1.0 represents a full scale sine wave. | |||||
</p> | |||||
<p class=func><span class=keyword>read</span>(firstBin, lastBin);</p> | |||||
<p class=desc>Read several frequency bins, returning their sum. The higher | |||||
audio octaves are represented by many bins, which are typically read | |||||
as a group for audio visualization. | |||||
</p> | |||||
<p class=func><span class=keyword>averageTogether</span>(number);</p> | |||||
<p class=desc>This function does nothing. The 1024 point FFT always | |||||
updates at approximately 86 times per second. | |||||
</p> | |||||
<p class=func><span class=keyword>windowFunction</span>(window);</p> | |||||
<p class=desc>Set the window function to be used. AudioWindowHanning1024 | |||||
is the default. Windowing may be disabled by NULL, but windowing | |||||
should be used for all non-periodic (music) signals, and all periodic | |||||
signals that are not exact integer division of the sample rate. | |||||
</p> | |||||
<h3>Notes</h3> | <h3>Notes</h3> | ||||
<p>1024 point FFT uses approx 50% of the CPU power on Teensy 3.1</p> | <p>1024 point FFT uses approx 50% of the CPU power on Teensy 3.1</p> | ||||
<p>The raw 16 bit output data bins may be access with myFFT.output[num], where | <p>The raw 16 bit output data bins may be access with myFFT.output[num], where | ||||
num is 0 to 511.</p> | num is 0 to 511.</p> | ||||
<p>TODO: caveats about spectral leakage vs frequency precision for arbitrary signals</p> | <p>TODO: caveats about spectral leakage vs frequency precision for arbitrary signals</p> | ||||
<p>Known bug in the library limits to only a single instance of this object. | |||||
This bug will be fixed someday... but 2 instances may not run due to CPU limitation</p> | |||||
<p>Window Types: | <p>Window Types: | ||||
<ul> | <ul> | ||||
<li><span class=literal>AudioWindowHanning1024</span> (default)</li> | <li><span class=literal>AudioWindowHanning1024</span> (default)</li> |