X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=firm%2Fbare_metal%2Ffft_graphics_speana%2Fmain.c;fp=firm%2Fbare_metal%2Ffft_graphics_speana%2Fmain.c;h=a0b580e5cb5d92f367a9bda27869a0c0cd58d044;hb=3866c1923d8d7f554ce810dfa452a86e33e3d51a;hp=0000000000000000000000000000000000000000;hpb=bed1f19c497e6921832e20c791c3dc4f8cb4db7b;p=bluetank%2Fbluetank.git diff --git a/firm/bare_metal/fft_graphics_speana/main.c b/firm/bare_metal/fft_graphics_speana/main.c new file mode 100644 index 0000000..a0b580e --- /dev/null +++ b/firm/bare_metal/fft_graphics_speana/main.c @@ -0,0 +1,305 @@ +/** + * @file main.c + * @author Copyright(C) 2012 Shinichiro Nakamura + * @author Copyright(C) 2012 Maduki Kanazawa + * @brief BlueTank ACB-BF592 Application Sample Codes. + */ + +/* + * =============================================================== + * BlueTank + * =============================================================== + * Copyright (c) 2012 Shinichiro Nakamura + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * =============================================================== + */ + +#include +#include "uzura.h" +#include "effect.h" +#include "system.h" +#include "lcd.h" +#include "led.h" +#include "rotenc.h" +#include +#include +#include + +/** + * @brief FFT calculation size. + */ +#define FFT_CALCSIZE (64) + +/** + * @brief FFT display bands. + */ +#define FFT_DISPBANDS (40) + +/** + * @brief sampling frequency. + */ +#define SAMPLE_FREQ (48000) + +/** + * @brief Check the band. + * + * @param N band index. + */ +#define IS_VALID_BAND(N) (((SAMPLE_FREQ / FFT_CALCSIZE) * (N)) < (SAMPLE_FREQ / 2.00)) + +/** + * @note + * FFT calculation size given by FFT_CALCSIZE. + * The frequency resolution (fr) of the FFT given by (fs / FFT_CALCSIZE). + * + * ================================================= + * fmax[Hz] fmax[Hz] + * FFT_CALCSIZE fr[Hz] 8 bands 40 bands + * ================================================= + * 16 3000.0 24,000 120,000 + * 32 1500.0 12,000 60,000 + * 64 750.0 6,000 30,000 + * 128 375.0 3,000 15,000 + * 256 187.5 1,500 7,500 + * ================================================= + * + * (Example) fs = 48000, FFT_CALCSIZE = 128 + * The frequency resolution (fr) is fr = (fs / FFT_CALCSIZE) = 48000 / 128 = 375[Hz]. + * The maximum display frequency in FFT_BANDS = 40 is fmax = (fr * FFT_BANDS) = 375 * 40 = 15000[Hz]. + */ + +/** + * @brief FFT calculation data structure. + */ +typedef struct { + fract16 window[FFT_CALCSIZE]; + fract16 input[FFT_CALCSIZE]; + complex_fract16 output[FFT_CALCSIZE]; + complex_fract16 twiddle[FFT_CALCSIZE / 2]; +} fft_t; + +typedef struct { + UZURA uzura; + int volume; + char volmsg[9]; + fft_t fft; + FontSet fontset; +} work_t; + +static void update_volmsg(work_t *w, const int vol) +{ + int nnn = (vol == 100) ? 1 : 0; + int nn = (vol == 100) ? 0 : (vol / 10); + int n = (vol == 100) ? 0 : (vol - (nn * 10)); + w->volmsg[5] = '0' + nnn; + w->volmsg[6] = '0' + nn; + w->volmsg[7] = '0' + n; +} + +static fract16 lrmix(int32_t left, int32_t right, fract16 window) +{ + int32_t val; + 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)); + return (fract16)val; +} + +static void effect_fft( + UZURA *p, + const int32_t *src, int32_t *des, int32_t count) +{ + int32_t lc, ld; + int block_exp; + + /* + * Get the user data from the UZURA framework. + */ + work_t *w = (work_t *)UZURA_USER_DATA(p); + fract16 *window = w->fft.window; + fract16 *input = w->fft.input; + complex_fract16 *output = w->fft.output; + complex_fract16 *twiddle = w->fft.twiddle; + + /* + * Copy data to the destination buffer. + */ + effect_through(p, src, des, count); + + /* + * Combine the L/R channel data with the window function. + * The destination data bit width is 16bit. + */ + for (lc = 0, ld = 0; lc < FFT_CALCSIZE; lc++, ld += 2) { + input[lc] = lrmix(src[ld], src[ld + 1], window[lc]); + } + + /* + * 16bit real FFT + */ + rfft_fr16(input, output, twiddle, 1, FFT_CALCSIZE, &block_exp, 1); +} + +static void system_speana(UZURA *p) +{ + int32_t lc; + float re, im, ps; + int32_t level; + static uint32_t refresh_target = 0; + + /* + * Get the user data from the UZURA framework. + */ + work_t *w = (work_t *)UZURA_USER_DATA(p); + complex_fract16 *output = w->fft.output; + + /* + * Calculate the FFT in floating point. + * We need to convert it to fixed point if we need to keep a performance. + */ + + /* + * Calculate the power spectrum. + */ + lc = refresh_target % FFT_DISPBANDS; + re = (float)output[lc].re / (float)32768; + im = (float)output[lc].im / (float)32768; + ps = sqrtf(re * re + im * im); + + /* + * Round out the result. + */ + ps = fmax(ps, 0.000030517578125); + + /* + * Convert it to dB range. + * Normalize it to -10.4 to 0.35. + */ + ps = (float)(20.0 / 8.7) * log10f(ps); + + /* + * Clipping in 0 to 7. + */ + level = (int32_t)ps + 8; + if (level < 0) { + level = 0; + } + if (7 < level) { + level = 7; + } + + /* + * Update the LCD fonts. + */ + if (lc == 0) { + lcd_font_init(&(w->fontset)); + } + if (IS_VALID_BAND(lc)) { + lcd_font_draw_line( + &(w->fontset), (UserFont)lc / LCD_FONT_WIDTH, + lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1) - level, + lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1), + 1); + } else { + lcd_font_draw_line( + &(w->fontset), (UserFont)lc / LCD_FONT_WIDTH, + lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1), + lc % LCD_FONT_WIDTH, (LCD_FONT_HEIGHT - 1), + 1); + } + if (((lc + 1) % LCD_FONT_WIDTH) == 0) { + lcd_font_setup_single(&(w->fontset), (UserFont)lc / LCD_FONT_WIDTH); + } + + /* + * Update the volume display. + */ + static int prev_volume = 0; + if (prev_volume != w->volume) { + update_volmsg(w, w->volume); + lcd_goto(0, 1); + lcd_puts(w->volmsg); + prev_volume = w->volume; + } + + refresh_target++; +} + +static void rotenc_callback(RotencAction action, void *extobj) +{ + work_t *w = (work_t *)extobj; + if (RotencActionPush == action) { + // Nothing to do. + } + if (RotencActionLeft == action) { + if (0 < w->volume) { + w->volume--; + effect_param_volume(w->volume / 100.0, w->volume / 100.0); + } + } + if (RotencActionRight == action) { + if (w->volume < 100) { + w->volume++; + effect_param_volume(w->volume / 100.0, w->volume / 100.0); + } + } +} + +int main(void) +{ + work_t w; + + w.volume = 100; + strcpy(w.volmsg, "VOL: 100"); + lcd_goto(0, 0); + lcd_puts("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"); + + /* + * Generate window. + */ +#if 0 + /* + * Select window function from the three types of the window. + */ + gen_hamming_fr16(w.fft.window, 1, FFT_CALCSIZE); + gen_rectangular_fr16(w.fft.window, 1, FFT_CALCSIZE); + gen_hanning_fr16(w.fft.window, 1, FFT_CALCSIZE); +#else + gen_hanning_fr16(w.fft.window, 1, FFT_CALCSIZE); +#endif + + /* + * Generate twiddle factor table. + */ + twidfftrad2_fr16(w.fft.twiddle, FFT_CALCSIZE); + + effect_param_init(); + uzura_init(&w.uzura, &w); + uzura_set_effect(&w.uzura, effect_fft); + uzura_set_system(&w.uzura, system_speana); + led_write(LedTargetR, 1); + led_write(LedTargetG, 1); + rotenc_init(rotenc_callback, &w); + uzura_execute(&w.uzura); + + return 0; +} +