Skip to content

Commit 25592e5

Browse files
committed
port AudioAnalyzeFFT256 to F32
It's about twice as slow as the I16 version but produces cleaner output
1 parent 93a3732 commit 25592e5

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed

OpenAudio_ArduinoLibrary.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "AudioMixer_F32.h"
1717
#include "AudioMultiply_F32.h"
1818
#include "AudioSettings_F32.h"
19+
#include "analyze_fft256_f32.h"
1920
#include "input_i2s_f32.h"
2021
#include "output_i2s_f32.h"
2122
#include "play_queue_f32.h"

analyze_fft256_f32.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/* Audio Library for Teensy 3.X
2+
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
3+
*
4+
* Development of this audio library was funded by PJRC.COM, LLC by sales of
5+
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
6+
* open source software by purchasing Teensy or other PJRC products.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice, development funding notice, and this permission
16+
* notice shall be included in all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <Arduino.h>
28+
#include "analyze_fft256_f32.h"
29+
#include "utility/dspinst.h"
30+
31+
32+
static void copy_to_fft_buffer(void *destination, const void *source)
33+
{
34+
const float32_t *src = (const float32_t *)source;
35+
float32_t *dst = (float32_t *)destination;
36+
37+
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
38+
*dst++ = *src++; // real sample plus a zero for imaginary
39+
*dst++ = 0;
40+
}
41+
}
42+
43+
static void apply_window_to_fft_buffer(void *buffer, const void *window)
44+
{
45+
float32_t *buf = (float32_t *)buffer;
46+
const int16_t *win = (int16_t *)window;;
47+
48+
for (int i=0; i < 256; i++) {
49+
*buf *= *win++;
50+
*buf /= 32768;
51+
buf += 2;
52+
}
53+
}
54+
55+
void AudioAnalyzeFFT256_F32::update(void)
56+
{
57+
audio_block_f32_t *block;
58+
59+
block = receiveReadOnly_f32();
60+
if (!block) return;
61+
#if AUDIO_BLOCK_SAMPLES == 128
62+
if (!prevblock) {
63+
prevblock = block;
64+
return;
65+
}
66+
copy_to_fft_buffer(buffer, prevblock->data);
67+
copy_to_fft_buffer(buffer+256, block->data);
68+
//window = AudioWindowBlackmanNuttall256;
69+
//window = NULL;
70+
if (window) apply_window_to_fft_buffer(buffer, window);
71+
arm_cfft_radix4_f32(&fft_inst, buffer);
72+
// G. Heinzel's paper says we're supposed to average the magnitude
73+
// squared, then do the square root at the end.
74+
if (count == 0) {
75+
for (int i=0; i < 128; i++) {
76+
sum[i] = (buffer[i * 2] * buffer[i * 2] + buffer[i * 2 + 1] * buffer[i * 2 + 1]);
77+
}
78+
} else {
79+
for (int i=0; i < 128; i++) {
80+
sum[i] += (buffer[i * 2] * buffer[i * 2] + buffer[i * 2 + 1] * buffer[i * 2 + 1]);
81+
}
82+
}
83+
if (++count == naverage) {
84+
count = 0;
85+
for (int i=0; i < 128; i++) {
86+
output[i] = sqrtf(sum[i] / naverage) / 64; // I don't know why 64, but a full scale sine wave is 64.
87+
}
88+
outputflag = true;
89+
}
90+
release(prevblock);
91+
prevblock = block;
92+
#elif AUDIO_BLOCK_SAMPLES == 64
93+
if (prevblocks[2] == NULL) {
94+
prevblocks[2] = prevblocks[1];
95+
prevblocks[1] = prevblocks[0];
96+
prevblocks[0] = block;
97+
return;
98+
}
99+
if (count == 0) {
100+
count = 1;
101+
copy_to_fft_buffer(buffer, prevblocks[2]->data);
102+
copy_to_fft_buffer(buffer+128, prevblocks[1]->data);
103+
copy_to_fft_buffer(buffer+256, prevblocks[1]->data);
104+
copy_to_fft_buffer(buffer+384, block->data);
105+
if (window) apply_window_to_fft_buffer(buffer, window);
106+
arm_cfft_radix4_q15(&fft_inst, buffer);
107+
} else {
108+
count = 2;
109+
const uint32_t *p = (uint32_t *)buffer;
110+
for (int i=0; i < 128; i++) {
111+
uint32_t tmp = *p++;
112+
int16_t v1 = tmp & 0xFFFF;
113+
int16_t v2 = tmp >> 16;
114+
output[i] = sqrt_uint32_approx(v1 * v1 + v2 * v2);
115+
}
116+
}
117+
release(prevblocks[2]);
118+
prevblocks[2] = prevblocks[1];
119+
prevblocks[1] = prevblocks[0];
120+
prevblocks[0] = block;
121+
#endif
122+
}
123+
124+

analyze_fft256_f32.h

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* Audio Library for Teensy 3.X
2+
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
3+
*
4+
* Development of this audio library was funded by PJRC.COM, LLC by sales of
5+
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
6+
* open source software by purchasing Teensy or other PJRC products.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice, development funding notice, and this permission
16+
* notice shall be included in all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef analyze_fft256_f32_h_
28+
#define analyze_fft256_f32_h_
29+
30+
#include "Arduino.h"
31+
#include "AudioStream_F32.h"
32+
#include "arm_math.h"
33+
34+
// windows.c
35+
extern "C" {
36+
extern const int16_t AudioWindowHanning256[];
37+
extern const int16_t AudioWindowBartlett256[];
38+
extern const int16_t AudioWindowBlackman256[];
39+
extern const int16_t AudioWindowFlattop256[];
40+
extern const int16_t AudioWindowBlackmanHarris256[];
41+
extern const int16_t AudioWindowNuttall256[];
42+
extern const int16_t AudioWindowBlackmanNuttall256[];
43+
extern const int16_t AudioWindowWelch256[];
44+
extern const int16_t AudioWindowHamming256[];
45+
extern const int16_t AudioWindowCosine256[];
46+
extern const int16_t AudioWindowTukey256[];
47+
}
48+
49+
class AudioAnalyzeFFT256_F32 : public AudioStream_F32
50+
{
51+
public:
52+
AudioAnalyzeFFT256_F32() : AudioStream_F32(1, inputQueueArray),
53+
window(AudioWindowHanning256), count(0), outputflag(false) {
54+
arm_cfft_radix4_init_f32(&fft_inst, 256, 0, 1);
55+
#if AUDIO_BLOCK_SAMPLES == 128
56+
prevblock = NULL;
57+
naverage = 1;
58+
#elif AUDIO_BLOCK_SAMPLES == 64
59+
prevblocks[0] = NULL;
60+
prevblocks[1] = NULL;
61+
prevblocks[2] = NULL;
62+
#endif
63+
}
64+
bool available() {
65+
if (outputflag == true) {
66+
outputflag = false;
67+
return true;
68+
}
69+
return false;
70+
}
71+
float read(unsigned int binNumber) {
72+
if (binNumber > 127) return 0.0;
73+
return output[binNumber];
74+
}
75+
float read(unsigned int binFirst, unsigned int binLast) {
76+
if (binFirst > binLast) {
77+
unsigned int tmp = binLast;
78+
binLast = binFirst;
79+
binFirst = tmp;
80+
}
81+
if (binFirst > 127) return 0.0;
82+
if (binLast > 127) binLast = 127;
83+
uint32_t sum = 0;
84+
do {
85+
sum += output[binFirst++];
86+
} while (binFirst <= binLast);
87+
return sum;
88+
}
89+
void averageTogether(uint8_t n) {
90+
#if AUDIO_BLOCK_SAMPLES == 128
91+
if (n == 0) n = 1;
92+
naverage = n;
93+
#endif
94+
}
95+
void windowFunction(const int16_t *w) {
96+
window = w;
97+
}
98+
virtual void update(void);
99+
float32_t output[128] __attribute__ ((aligned (4)));
100+
private:
101+
const int16_t *window;
102+
#if AUDIO_BLOCK_SAMPLES == 128
103+
audio_block_f32_t *prevblock;
104+
#elif AUDIO_BLOCK_SAMPLES == 64
105+
audio_block_f32_t *prevblocks[3];
106+
#endif
107+
float32_t buffer[512] __attribute__ ((aligned (4)));
108+
#if AUDIO_BLOCK_SAMPLES == 128
109+
float32_t sum[128];
110+
uint8_t naverage;
111+
#endif
112+
uint8_t count;
113+
volatile bool outputflag;
114+
audio_block_f32_t *inputQueueArray[1];
115+
arm_cfft_radix4_instance_f32 fft_inst;
116+
};
117+
118+
#endif

0 commit comments

Comments
 (0)