| #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> |