@@ -27,18 +27,7 @@ | |||
#include "analyze_fft1024.h" | |||
#include "sqrt_integer.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 | |||
static void copy_to_fft_buffer(void *destination, const void *source) | |||
@@ -133,32 +122,6 @@ void AudioAnalyzeFFT1024::update(void) | |||
state = 4; | |||
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; | |||
} | |||
*/ | |||
} | |||
@@ -28,6 +28,7 @@ | |||
#define analyze_fft1024_h_ | |||
#include "AudioStream.h" | |||
#include "arm_math.h" | |||
// windows.c | |||
extern "C" { | |||
@@ -47,10 +48,10 @@ extern const int16_t AudioWindowTukey1024[]; | |||
class AudioAnalyzeFFT1024 : public AudioStream | |||
{ | |||
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() { | |||
if (outputflag == true) { | |||
outputflag = false; | |||
@@ -58,6 +59,30 @@ public: | |||
} | |||
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); | |||
uint16_t output[512] __attribute__ ((aligned (4))); | |||
private: | |||
@@ -71,6 +96,7 @@ private: | |||
//uint8_t naverage; | |||
volatile bool outputflag; | |||
audio_block_t *inputQueueArray[1]; | |||
arm_cfft_radix4_instance_q15 fft_inst; | |||
}; | |||
#endif |
@@ -27,18 +27,7 @@ | |||
#include "analyze_fft256.h" | |||
#include "sqrt_integer.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 | |||
static void copy_to_fft_buffer(void *destination, const void *source) |
@@ -28,6 +28,7 @@ | |||
#define analyze_fft256_h_ | |||
#include "AudioStream.h" | |||
#include "arm_math.h" | |||
// windows.c | |||
extern "C" { | |||
@@ -47,10 +48,11 @@ extern const int16_t AudioWindowTukey256[]; | |||
class AudioAnalyzeFFT256 : public AudioStream | |||
{ | |||
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() { | |||
if (outputflag == true) { | |||
outputflag = false; | |||
@@ -58,11 +60,34 @@ public: | |||
} | |||
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); | |||
//uint32_t cycles; | |||
uint16_t output[128] __attribute__ ((aligned (4))); | |||
private: | |||
void init(void); | |||
const int16_t *window; | |||
audio_block_t *prevblock; | |||
int16_t buffer[512] __attribute__ ((aligned (4))); | |||
@@ -71,6 +96,7 @@ private: | |||
uint8_t naverage; | |||
bool outputflag; | |||
audio_block_t *inputQueueArray[1]; | |||
arm_cfft_radix4_instance_q15 fft_inst; | |||
}; | |||
#endif |
@@ -9,21 +9,17 @@ const int myInput = AUDIO_INPUT_LINEIN; | |||
// Create the Audio components. These should be created in the | |||
// 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; | |||
void setup() { | |||
// Audio connections require memory to work. For more | |||
// detailed information, see the MemoryAndCpuUsage example | |||
@@ -33,6 +29,15 @@ void setup() { | |||
audioShield.enable(); | |||
audioShield.inputSelect(myInput); | |||
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() { | |||
@@ -40,9 +45,10 @@ void loop() { | |||
// each time new FFT data is available | |||
// print it all to the Arduino Serial Monitor | |||
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(); | |||
} |
@@ -1512,23 +1512,35 @@ | |||
<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> | |||
</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> | |||
<p class=func><span class=keyword>available</span>();</p> | |||
<p class=desc>Returns true each time the FFT analysis produces new output data. | |||
</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> | |||
<p>The raw 16 bit output data bins may be access with myFFT.output[num], where | |||
num is 0 to 127.</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: | |||
<ul> | |||
<li><span class=literal>AudioWindowHanning256</span> (default)</li> | |||
@@ -1574,24 +1586,34 @@ | |||
<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> | |||
</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> | |||
<p class=func><span class=keyword>available</span>();</p> | |||
<p class=desc>Returns true each time the FFT analysis produces new output data. | |||
</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> | |||
<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 | |||
num is 0 to 511.</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: | |||
<ul> | |||
<li><span class=literal>AudioWindowHanning1024</span> (default)</li> |