3 * @author Copyright(C) 2012 Shinichiro Nakamura
4 * @author Copyright(C) 2012 Maduki Kanazawa
5 * @brief BlueTank ACB-BF592 Application Sample Codes.
9 * ===============================================================
11 * ===============================================================
12 * Copyright (c) 2012 Shinichiro Nakamura
14 * Permission is hereby granted, free of charge, to any person
15 * obtaining a copy of this software and associated documentation
16 * files (the "Software"), to deal in the Software without
17 * restriction, including without limitation the rights to use,
18 * copy, modify, merge, publish, distribute, sublicense, and/or
19 * sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following
23 * The above copyright notice and this permission notice shall be
24 * included in all copies or substantial portions of the Software.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33 * OTHER DEALINGS IN THE SOFTWARE.
34 * ===============================================================
49 * @brief FFT calculation size.
51 #define FFT_CALCSIZE (64)
54 * @brief FFT display bands.
56 #define FFT_DISPBANDS (40)
59 * @brief sampling frequency.
61 #define SAMPLE_FREQ (48000)
64 * @brief Check the band.
66 * @param N band index.
68 #define IS_VALID_BAND(N) (((SAMPLE_FREQ / FFT_CALCSIZE) * (N)) < (SAMPLE_FREQ / 2.00))
72 * FFT calculation size given by FFT_CALCSIZE.
73 * The frequency resolution (fr) of the FFT given by (fs / FFT_CALCSIZE).
75 * =================================================
77 * FFT_CALCSIZE fr[Hz] 8 bands 40 bands
78 * =================================================
79 * 16 3000.0 24,000 120,000
80 * 32 1500.0 12,000 60,000
81 * 64 750.0 6,000 30,000
82 * 128 375.0 3,000 15,000
83 * 256 187.5 1,500 7,500
84 * =================================================
86 * (Example) fs = 48000, FFT_CALCSIZE = 128
87 * The frequency resolution (fr) is fr = (fs / FFT_CALCSIZE) = 48000 / 128 = 375[Hz].
88 * The maximum display frequency in FFT_BANDS = 40 is fmax = (fr * FFT_BANDS) = 375 * 40 = 15000[Hz].
92 * @brief FFT calculation data structure.
95 fract16 window[FFT_CALCSIZE];
96 fract16 input[FFT_CALCSIZE];
97 complex_fract16 output[FFT_CALCSIZE];
98 complex_fract16 twiddle[FFT_CALCSIZE / 2];
109 static void update_volmsg(work_t *w, const int vol)
111 int nnn = (vol == 100) ? 1 : 0;
112 int nn = (vol == 100) ? 0 : (vol / 10);
113 int n = (vol == 100) ? 0 : (vol - (nn * 10));
114 w->volmsg[5] = '0' + nnn;
115 w->volmsg[6] = '0' + nn;
116 w->volmsg[7] = '0' + n;
119 static fract16 lrmix(int32_t left, int32_t right, fract16 window)
122 asm("%1 >>>= 1; %2 >>>= 1; %1 = %1 + %2; %0.L = %1(RND); %0.L = %0.L * %3.L; %0 = %0.L(X);" : "=d"(val) : "d"(left), "d"(right), "d"(window));
126 static void effect_fft(
128 const int32_t *src, int32_t *des, int32_t count)
134 * Get the user data from the UZURA framework.
136 work_t *w = (work_t *)UZURA_USER_DATA(p);
137 fract16 *window = w->fft.window;
138 fract16 *input = w->fft.input;
139 complex_fract16 *output = w->fft.output;
140 complex_fract16 *twiddle = w->fft.twiddle;
143 * Copy data to the destination buffer.
145 effect_through(p, src, des, count);
148 * Combine the L/R channel data with the window function.
149 * The destination data bit width is 16bit.
151 for (lc = 0, ld = 0; lc < FFT_CALCSIZE; lc++, ld += 2) {
152 input[lc] = lrmix(src[ld], src[ld + 1], window[lc]);
158 rfft_fr16(input, output, twiddle, 1, FFT_CALCSIZE, &block_exp, 1);
161 static void system_speana(UZURA *p)
166 static uint32_t refresh_target = 0;
169 * Get the user data from the UZURA framework.
171 work_t *w = (work_t *)UZURA_USER_DATA(p);
172 complex_fract16 *output = w->fft.output;
175 * Calculate the FFT in floating point.
176 * We need to convert it to fixed point if we need to keep a performance.
180 * Calculate the power spectrum.
182 lc = refresh_target % FFT_DISPBANDS;
183 re = (float)output[lc].re / (float)32768;
184 im = (float)output[lc].im / (float)32768;
185 ps = sqrtf(re * re + im * im);
188 * Round out the result.
190 ps = fmax(ps, 0.000030517578125);
193 * Convert it to dB range.
194 * Normalize it to -10.4 to 0.35.
196 ps = (float)(20.0 / 8.7) * log10f(ps);
199 * Clipping in 0 to 7.
201 level = (int32_t)ps + 8;
210 * Update the LCD fonts.
213 lcd_font_init(&(w->fontset));
215 if (IS_VALID_BAND(lc)) {
217 &(w->fontset), (UserFont)lc / LCD_FONT_WIDTH,
218 lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1) - level,
219 lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1),
223 &(w->fontset), (UserFont)lc / LCD_FONT_WIDTH,
224 lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1),
225 lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1),
228 if (((lc + 1) % LCD_FONT_WIDTH) == 0) {
229 lcd_font_setup_single(&(w->fontset), (UserFont)lc / LCD_FONT_WIDTH);
233 * Update the volume display.
235 static int prev_volume = 0;
236 if (prev_volume != w->volume) {
237 update_volmsg(w, w->volume);
240 prev_volume = w->volume;
246 static void rotenc_callback(RotencAction action, void *extobj)
248 work_t *w = (work_t *)extobj;
249 if (RotencActionPush == action) {
252 if (RotencActionLeft == action) {
255 effect_param_volume(w->volume / 100.0, w->volume / 100.0);
258 if (RotencActionRight == action) {
259 if (w->volume < 100) {
261 effect_param_volume(w->volume / 100.0, w->volume / 100.0);
271 strcpy(w.volmsg, "VOL: 100");
273 lcd_puts("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F");
280 * Select window function from the three types of the window.
282 gen_hamming_fr16(w.fft.window, 1, FFT_CALCSIZE);
283 gen_rectangular_fr16(w.fft.window, 1, FFT_CALCSIZE);
284 gen_hanning_fr16(w.fft.window, 1, FFT_CALCSIZE);
286 gen_hanning_fr16(w.fft.window, 1, FFT_CALCSIZE);
290 * Generate twiddle factor table.
292 twidfftrad2_fr16(w.fft.twiddle, FFT_CALCSIZE);
295 uzura_init(&w.uzura, &w);
296 uzura_set_effect(&w.uzura, effect_fft);
297 uzura_set_system(&w.uzura, system_speana);
298 led_write(LedTargetR, 1);
299 led_write(LedTargetG, 1);
300 rotenc_init(rotenc_callback, &w);
301 uzura_execute(&w.uzura);