ERIS CORE
eris_analyze_fft1024.cpp
Go to the documentation of this file.
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 /**
28  * @file eris_analyze_fft1024.cpp
29  * @author Brian Monkaba (brian.monkaba@gmail.com)
30  * @brief
31  * @version 0.1
32  * @date 2021-08-24
33  *
34  * @copyright portions Copyright (c) 2021
35  *
36  */
37 
38 
39 #include <cmath>
40 #include <Arduino.h>
41 #include "eris_analyze_fft1024.h"
42 #include "sqrt_integer.h"
43 #include "utility/dspinst.h"
44 #include "arm_const_structs.h" //WILL BE NEEDED FOR IMPLEMENTING f32 FFT
45 
46 
47 //static name used for looking up shortname by classname
48 const char* erisAudioAnalyzeFFT1024::short_name_lookup = "fft1024";
49 
50 // Approximates atan2(y, x) normalized to the [0,4] range
51 // with a maximum error of 0.1620 degrees
52 float normalized_atan2( float y, float x )
53 {
54  //return 0;
55  static const uint32_t sign_mask = 0x80000000;
56  static const float b = 0.596227f;
57 
58  uint32_t ux;
59  uint32_t uy;
60  memcpy(&ux, &x, sizeof(x));
61  memcpy(&uy, &y, sizeof(x));
62  // Extract the sign bits
63  //uint32_t ux_s = sign_mask & (uint32_t &)x;
64  //uint32_t uy_s = sign_mask & (uint32_t &)y;
65  uint32_t ux_s = sign_mask & ux;
66  uint32_t uy_s = sign_mask & uy;
67 
68  // Determine the quadrant offset
69  float q = (float)( ( ~ux_s & uy_s ) >> 29 | ux_s >> 30 );
70 
71  // Calculate the arctangent in the first quadrant
72  float bxy_a = ::fabs( b * x * y );
73  float num = bxy_a + y * y;
74  float atan_1q = num / ( x * x + bxy_a + num );
75 
76  uint32_t uatan;
77  memcpy(&uatan, &atan_1q, sizeof(atan_1q));
78  // Translate it to the proper quadrant
79  uint32_t uatan_2q = (ux_s ^ uy_s) | uatan;
80  memcpy(&atan_1q, &uatan_2q, sizeof(uatan_2q));
81  return q + atan_1q;
82 }
83 
84 
85 
86 //Fat Audio - to add trailing zeros to fft buffer
87 /*
88 static void zero_to_fft_buffer(void *destination)
89 {
90  uint32_t *dst = (uint32_t *)destination;
91  for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
92  *dst++ = 0;
93  }
94 }
95 */
96 // 140312 - PAH - slightly faster copy
97 void erisAudioAnalyzeFFT1024::copy_to_fft_buffer(void *destination, const void *source,int subsample)
98 {
99  const uint16_t *src = (const uint16_t *)source;
100  uint16_t *dst = (uint16_t *)destination;
101  //Fat Audio - dumb downsample
102  for (; SAMPLING_INDEX < AUDIO_BLOCK_SAMPLES; ) {
103  *dst++ = src[SAMPLING_INDEX];
104  SAMPLING_INDEX+=subsample;
105  }
106  SAMPLING_INDEX -= AUDIO_BLOCK_SAMPLES;
107 }
108 
109 #ifndef ENABLE_F32_FFT
110 static void apply_window_to_fft_buffer(void *buffer, const void *window)
111 {
112  int16_t *buf = (int16_t *)buffer;
113  const int16_t *win = (int16_t *)window;;
114 
115  for (int i=0; i < 1024; i++) {
116  int32_t val = *buf * *win++;
117  //*buf = signed_saturate_rshift(val, 16, 15);
118  *buf = val >> 15;
119  buf += 2;
120  }
121 
122 }
123 #else
124 static void apply_window_to_fft_buffer_f32(float32_t *buffer, const float32_t *window)
125 {
126  float32_t *buf = (float32_t *)buffer;
127  const float32_t *win = (float32_t *)window;;
128 
129  for (int16_t i=0; i < 1024; i++) {
130  *buf++ *= *win++;
131  }
132 
133 }
134 #endif
135 
137 {
138  if (outputflag == false) return false; //no new data frame to analyze
139  is_analyzed = false;
140  return true;
141 }
142 
144 {
145  float p;
146 
147  if (is_analyzed) return;
148  //(NVIC_DISABLE_IRQ(IRQ_SOFTWARE));
149 
150  apply_window_to_fft_buffer_f32((float32_t*)tmp_buffer, window_f32);
151  arm_fill_f32(0,(float32_t*)&tmp_buffer[1024],1024);
152  arm_cfft_radix4_f32(&fft_inst, (float32_t*)tmp_buffer);
153  //extract the polar phase from the interleaved real and imag
154 
155  for(int16_t i=0;i < 1024;i+=2){
156  p = normalized_atan2(tmp_buffer[i],tmp_buffer[i+1]);
157  if (!std::isfinite(p)) p = 0;
158  phase[i/2] = (phase[i/2] + (360.0 * (p/4.0)))/2.0;
159  }
160 
161  // Process the data through the Complex Magnitude Module for calculating the magnitude at each bin
162  arm_cmplx_mag_f32((float32_t*)tmp_buffer, (float32_t*)tmp_buffer, 1024);
163  for(int16_t i=0;i < 1024;i+=2){
164  //arm_cmplx_mag_f32((float32_t*)tmp_buffer, (float32_t*)output, 1024);
165  output[i] = (output[i] + tmp_buffer[i]) / 2.0;
166  }
167 
168 
169  //(NVIC_ENABLE_IRQ(IRQ_SOFTWARE));
170 
171  //spectralFilter();
172 
173  outputflag = false; //current frame is analyzed and ready to use
174  is_analyzed = true;
175  return;
176 }
177 
179 {
180  audio_block_t *block;
181 
182  block = receiveReadOnly();
183  if (!block) return;
184 
185 
186  //FAT Audio - add the ability to turn FFT on or OFF to save CPU
187  if (!enabled){
188  release(block);
189  return;
190  };
191 
192  uint16_t ofs;
193  //calcuate active subsampling step and offset
194  if (ssr == SS_LOWFREQ){
197  }
198  else if (ssr == SS_HIGHFREQ){
201  }
202  BLOCKS_PER_FFT = ((1024 / AUDIO_BLOCK_SAMPLES) * subsample_by);
204  if (ssr == SS_LOWFREQ) BLOCK_REFRESH_SIZE = BLOCKS_PER_FFT/2;//((subsample_lowfreqrange/subsample_highfreqrange) * 2);//BLOCK_REFRESH_SIZE/(subsample_lowfreqrange/2);//BLOCKS_PER_FFT/4;
205 
206  ofs = (AUDIO_BLOCK_SAMPLES/subsample_by) * (sample_block);
207 
208  if (sample_block < BLOCKS_PER_FFT -1){
209  copy_to_fft_buffer(buffer+ofs, block->data,subsample_by);
210  release(block);
211  sample_block++;
212  } else{
213  copy_to_fft_buffer(buffer+ofs, block->data,subsample_by);
214  release(block);
215  #ifdef ENABLE_F32_FFT
216 
217  //copy buffer while casting to float and scale to the range -1 to 1
218  //(NVIC_DISABLE_IRQ(IRQ_SOFTWARE));
219  if(outputflag == false && is_analyzed){
220  for (int16_t i=0; i < 1024; i++){
221  tmp_buffer[i] = ((float32_t)buffer[i] / (float32_t)32768.0);
222  //if (SS_LOWFREQ) tmp_buffer[i] *= subsample_lowfreqrange/(float32_t)subsample_highfreqrange; //scale match the low range
223  if (!std::isfinite(tmp_buffer[i])) tmp_buffer[i] = 0.0;
224  }
225  outputflag = true;
226  }
227  //(NVIC_ENABLE_IRQ(IRQ_SOFTWARE));
228 
229  #else
230  memcpy(tmp_buffer,buffer,2048 * sizeof(int16_t));
231  apply_window_to_fft_buffer(tmp_buffer, window);
232  arm_cfft_radix4_q15(&fft_inst, tmp_buffer);
233  outputflag = false; //output flag is false while updating the fft results
234 
235  for (int i=0; i < 512; i++) {
236  uint32_t tmp = *((uint32_t *)tmp_buffer + i); // real & imag
237  uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp);
238  output[i] = sqrt_uint32_approx(magsq);
239  output_packed[i] = tmp;//normalized_atan2((float)real,(float)imag)*180/PI;//atan2(imag,real)*180/PI;
240  }
241  #endif
242 
243  if (sample_block!= 0){
245  ofs = (AUDIO_BLOCK_SAMPLES/subsample_by) * sample_block;
246  //fft overlap - restore tmp cpy of last half to first half
247  memmove(buffer,&buffer[(AUDIO_BLOCK_SAMPLES/subsample_by)*BLOCK_REFRESH_SIZE], (AUDIO_BLOCK_SAMPLES/subsample_by) * (BLOCKS_PER_FFT - BLOCK_REFRESH_SIZE) * sizeof(int16_t));
248  }
249 
250  }
251 }
const char PROGMEM p[][16]
Definition: Eris.h:247
static void release(audio_block_t *block)
audio_block_t * receiveReadOnly(unsigned int index=0)
void copy_to_fft_buffer(void *destination, const void *source, int subsample)
arm_cfft_radix4_instance_f32 fft_inst
static const char * short_name_lookup
static void apply_window_to_fft_buffer(void *buffer, const void *window)
static void apply_window_to_fft_buffer_f32(float32_t *buffer, const float32_t *window)
float normalized_atan2(float y, float x)
float phase
@ SS_LOWFREQ
@ SS_HIGHFREQ
int16_t data[AUDIO_BLOCK_SAMPLES]
Definition: AudioStream.h:78