void processSound() { uint8_t i, x, L, *data, nBins, binNum; uint16_t minLvl, maxLvl; int level, sum; fft_input(capture, bfly_buff); // Samples -> complex #s samplePos = 0; // Reset sample counter ADCSRA |= _BV(ADIE); // Resume sampling interrupt fft_execute(bfly_buff); // Process complex data fft_output(bfly_buff, spectrum); // Complex -> spectrum // Remove noise and apply EQ levels for (x=0; x < FFT_N / 2; x++) { L = pgm_read_byte(&noise[x]); spectrum[x] = (spectrum[x] <= L) ? 0 : (((spectrum[x] - L) * (256L - pgm_read_byte(&eq[x]))) >> 8); } colCount = (colCount + 1) % 10; // Downsample spectrum output to 8 columns: for(x = 0; x < NUM_COLUMNS; x++) { data = (uint8_t *)pgm_read_word(&colData[x]); nBins = pgm_read_byte(&data[0]); binNum = pgm_read_byte(&data[1]); for(sum = 0, i = 0; i < nBins; i++) sum += spectrum[binNum++] * pgm_read_byte(&data[i + 2]); // Weighted col[x][colCount] = sum / colDiv[x]; // Average minLvl = maxLvl = col[x][0]; for(i = 1; i < 10; i++) { // Get range of prior 10 frames if(col[x][i] < minLvl) minLvl = col[x][i]; else if(col[x][i] > maxLvl) maxLvl = col[x][i]; } // minLvl and maxLvl indicate the extents of the FFT output, used // for vertically scaling the output graph (so it looks interesting // regardless of volume level). If they're too close together though // (e.g. at very low volume levels) the graph becomes super coarse // and 'jumpy'...so keep some minimum distance between them (this // also lets the graph go to zero when no sound is playing): if((maxLvl - minLvl) < 8) maxLvl = minLvl + 8; minLvlAvg[x] = (minLvlAvg[x] * 7 + minLvl) >> 3; // Dampen min/max levels maxLvlAvg[x] = (maxLvlAvg[x] * 7 + maxLvl) >> 3; // (fake rolling average) // Second fixed-point scale based on dynamic min/max levels: level = 10L * (col[x][colCount] - minLvlAvg[x]) / (long)(maxLvlAvg[x] - minLvlAvg[x]); // Clip output and convert to byte: if(level < 0L) colLeveled[x] = 0; else if(level > 10) colLeveled[x] = 10; // Allow dot to go a couple pixels off top else colLeveled[x] = (uint8_t)level; // XXX - The leveled columns could probably be improved } }
int main (void) { char *cp; uint16_t m, n, s; uint16_t t1,t2,t3; DDRE = 0b00000010; /* PE1:<conout>, PE0:<conin> in N81 38.4kbps */ TCCR1B = 3; /* clk/64 */ xmitstr(PSTR("\r\nFFT sample program\r\n")); for(;;) { xmitstr(PSTR("\r\n>")); /* Prompt */ rcvrstr(pool, sizeof(pool)); /* Console input */ cp = pool; switch (*cp++) { /* Pick a header char (command) */ case '\0' : /* Blank line */ break; case 'w' : /* w: show waveform */ capture_wave(capture, FFT_N); for (n = 0; n < FFT_N; n++) { s = capture[n]; xmitf(PSTR("\r\n%4u:%6d "), n, s); s = (s + 32768) / 1024; for (m = 0; m < s; m++) xmit(' '); xmit('*'); } break; case 's' : /* s: show spectrum */ capture_wave(capture, FFT_N); TCNT1 = 0; /* performance counter */ fft_input(capture, bfly_buff); t1 = TCNT1; TCNT1 = 0; fft_execute(bfly_buff); t2 = TCNT1; TCNT1 = 0; fft_output(bfly_buff, spektrum); t3 = TCNT1; for (n = 0; n < FFT_N / 2; n++) { s = spektrum[n]; xmitf(PSTR("\r\n%4u:%5u "), n, s); s /= 512; for (m = 0; m < s; m++) xmit('*'); } xmitf(PSTR("\r\ninput=%u, execute=%u, output=%u (x64clk)"), t1,t2,t3); break; default : /* Unknown command */ xmitstr(PSTR("\n???")); } } }
int main (void) { initTimer(); initLeds(); loggerInit(); loggerWriteToMarker((LogMesT)"\r\nFFT sample program\r\n*", '*'); loggerWriteToMarker((LogMesT)"\r\n>*", '*'); /* Prompt */ for(;;) { capture_wave(capture, FFT_N); fft_input(capture, bfly_buff); fft_execute(bfly_buff); fft_output(bfly_buff, spektrum); _delay_ms(50); } }
int main(void) { memset( spectrum, 0, sizeof(spectrum) ); memset( spectrum_history, 0, sizeof(spectrum) ); init(); uint16_t cycles_till_reset_x = LCD_RESET_ADDR_CYCLES; while(1) { if( sleeping ) { sleepcycles++; if( backlight_task_scaler++ >= 75 ) { backlight_task(-1); backlight_task_scaler = 0; } if( sleeping == 3 ) go_to_sleep(); else if( sleeping == 2 ) wake_up(); else // sleeping == 1 { SMCR = _BV(SM0) | _BV(SE); asm volatile( "sleep\n\t" ); } } else { backlight_task_scaler = 0; backlight_task(-1); // Apply window function and store in butterfly array fft_input( capture, bfly ); // Execute forier transform fft_execute( bfly ); // Bit reversal algorithm from butterfly array to output array fft_output( bfly, spectrum ); // Do exponential/FIR filtering with history data exp_average( spectrum, spectrum_history ); #ifdef DISPLAY_TEST_PATTERN uint8_t *sp = spectrum; uint8_t v = 5; uint8_t k = sizeof(spectrum)/sizeof(uint8_t); while( k-- ) { *sp = v; v++; if( v > 38 ) v = 5; sp++; } long t = 100000; while(t--) { asm volatile("nop"); } #else #ifdef BLANK_LEFT_TWO_BARS spectrum[0] = spectrum[1] = 0; #endif #endif avc_task( spectrum ); if( --cycles_till_reset_x <= 0 ) { cycles_till_reset_x = LCD_RESET_ADDR_CYCLES; lcd_write_instruction( LCD_ADDR | 0, CHIP1 ); lcd_write_instruction( LCD_ADDR | 0, CHIP2 ); } fastlcd( spectrum ); loopnum++; } }