Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (revision 22470) +++ apps/plugins/CATEGORIES (working copy) @@ -58,6 +58,7 @@ pdbox,viewers pegbox,games pictureflow,demos +pitch_detector,apps plasma,demos png,viewers pong,games Index: apps/plugins/pitch_detector.c =================================================================== --- apps/plugins/pitch_detector.c (revision 0) +++ apps/plugins/pitch_detector.c (revision 0) @@ -0,0 +1,742 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2008 Lechner Michael / smoking gnu + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * ---------------------------------------------------------------------------- + * + * INTRODUCTION: + * OK, this is an attempt to write an instrument tuner for rockbox. + * It uses a Schmitt trigger algorithm, which I copied from + * tuneit [ (c) 2004 Mario Lang ], for detecting the + * fundamental freqency of a sound. A FFT algorithm would be more accurate + * but also much slower. + * + * TODO: + * - Find someone who knows how recording actually works, and rewrite the + * recording code to use proper, gapless recording with a callback function + * that provides new buffer, instead of stopping and restarting recording + * everytime the buffer is full + * - Convert all floating point operations to fixed-point + * - Adapt the Yin FFT algorithm, which would reduce complexity from O(n^2) + * to O(nlogn), theoretically reducing latency by a factor of ~10. -David + * + * MAJOR CHANGES: + * 08.03.2008 Started coding + * 21.03.2008 Pitch detection works more or less + * Button definitions for most targets added + * 02.04.2008 Proper GUI added + * Todo, Major Changes and Current Limitations added + * 08.19.2009 Brought the code up to date with current plugin standards + * Made it work more nicely with color, BW and grayscale + * Changed pitch detection to use the Yin algorithm (better + * detection, but slower -- would be ~4x faster with + * fixed point math, I think). Code was poached from the + * Aubio sound processing library (aubio.org). -David + * + * CURRENT LIMITATIONS: + * - Everything is hard-coded: buttons, input type (mic, line), + * buffer size , Yin threshold -- nothing can be changed at runtime + * - No gapless recording (I think I know how to fix this but it would + * only save ~1/40th of a second per sample period -David) + * - Due to how the Yin algorithm works, there's high latency if there's no + * pitch being recorded or if the pitch is outside the algorithm's range. + * - Due to how the Yin algorithm works, latency is higher for lower + * frequencies. + * - In order to keep latency to a reasonable level I set the buffer + * size to 1024 samples, meaning the lowest detectable frequency is + * about SAMPLE_RATE / 512, or about 86Hz on devices with a 44.1k sample + * rate. In reality, it should properly detect a the pitch of a + * frequency of half that value if the signal includes any harmonics. + * - Untested on devices other than h120 -David + */ + +#include "plugin.h" + +PLUGIN_HEADER + +/* Button definitions and Samplerate defining*/ +#if CONFIG_KEYPAD == RECORDER_PAD /* Recorder */ +#define TUNER_QUIT BUTTON_OFF + +#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD +#define TUNER_QUIT BUTTON_OFF + +#elif CONFIG_KEYPAD == ONDIO_PAD /* Ondio */ +#define TUNER_QUIT BUTTON_OFF + +#elif CONFIG_KEYPAD == PLAYER_PAD /* Player */ +#define TUNER_QUIT BUTTON_STOP + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) /* iRiver H1x0 && H3x0 */ +#define TUNER_QUIT BUTTON_OFF +#define SAMPLE_RATE 44100 +#define BW + +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ + (CONFIG_KEYPAD == IPOD_3G_PAD) || \ + (CONFIG_KEYPAD == IPOD_1G2G_PAD) /* iPods */ +#define TUNER_QUIT BUTTON_SELECT +#define SAMPLE_RATE 44100 +ifdecCL +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD /* iAudio X5/M5 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#elif CONFIG_KEYPAD == GIGABEAT_PAD /* GIGABEAT */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#elif CONFIG_KEYPAD == SANSA_E200_PAD /* Sansa E200 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 22050 + +#elif CONFIG_KEYPAD == SANSA_C200_PAD /* Sansa C200 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 22050 + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD /* iriver H10 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#elif CONFIG_KEYPAD == MROBE500_PAD /* M:robe 500 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#elif CONFIG_KEYPAD == GIGABEAT_S_PAD /* Gigabeat S */ +#define TUNER_QUIT BUTTON_BACK +#define SAMPLE_RATE 44100 + +#elif CONFIG_KEYPAD == MROBE100_PAD /* M:robe 100 */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#else /* Everything else */ +#define TUNER_QUIT BUTTON_POWER +#define SAMPLE_RATE 44100 + +#endif + +/* Some fixed point calculation stuff */ +typedef int32_t fixed_data; +struct _fixed +{ + fixed_data a; +}; +typedef struct _fixed fixed; +#define FIXED_PRECISION 20 +#define FIXED_MAX ((fixed) {0x7fffffff}) +#define FIXED_MIN ((fixed) {-0x80000000}) +#define int2fixed(x) ((fixed){(x) << FIXED_PRECISION}) +#define int2mantissa(x) ((fixed){x}) +#define fixed2int(x) ((int)((x).a >> FIXED_PRECISION)) +#define fixed2float(x) (((float)(x).a) / ((float)(1 << FIXED_PRECISION))) +#define float2fixed(x) ((fixed){(fixed_data)(x * (float)(1 << FIXED_PRECISION))}) +#ifdef ROCKBOX_HAS_LOGF +unsigned overflow_index; +unsigned overflow_tally[10] = {0,0,0,0,0,0,0,0,0,0}; +fixed fp_mul(fixed x, fixed y) +{ + int64_t retval = (((int64_t)x.a) * ((int64_t)y.a)) >> (FIXED_PRECISION); + /*if(retval > FIXED_MAX || retval < FIXED_MIN) + { + overflow_tally[overflow_index]++; + LOGF("%u,%u,%u,%u,%u,%u,%u", overflow_tally[0], + overflow_tally[1], + overflow_tally[2], + overflow_tally[3], + overflow_tally[4], + overflow_tally[5], + overflow_tally[6]); + LOGF("%d*%d", (int)(x >> FIXED_PRECISION), (int)(y >> FIXED_PRECISION)); + }*/ + return (fixed){(int32_t)retval}; +} +#else +/* I adapted these ones from the Rockbox fixed point library */ +#define fp_mul(x, y) ((fixed){(((int64_t)((x).a)) * ((int64_t)((y).a))) >> (FIXED_PRECISION)}) +#endif +#define fp_div(x, y) ((fixed){(((int64_t)((x).a)) << (FIXED_PRECISION)) / ((int64_t)((y).a))}) +#define fp_add(x, y) ((fixed){(x).a + (y).a}) +#define fp_sub(x, y) ((fixed){(x).a - (y).a}) +#define fp_shl(x, y) ((fixed){(x).a << y}) +#define fp_shr(x, y) ((fixed){(x).a >> y}) +#define fp_gt(x, y) ((x).a > (y).a) +#define fp_lt(x, y) ((x).a < (y).a) +#define fp_equal(x, y) ((x).a == (y).a) + +/* Some constants for tuning */ +#define A_FREQ 440.0f +#define D_NOTE 1.059463094359f +#define LOG_D_NOTE 0.057762265047f +#define D_NOTE_SQRT 1.029302236643f +#define LOG_2 0.693147180559f + +/* The recording buffer size */ +/* This is how much is sampled at a time. */ +/* It also determines latency -- if BUFFER_SIZE == SAMPLE_RATE then */ +/* there'll be one sample per second, or a latency of one second. */ +/* Furthermore, the lowest detectable frequency will be about twice */ +/* the number of reads per second */ +/* For the Yin FFT algorithm this needs to be a power of 2 */ +#define BUFFER_SIZE 1024 +#define YIN_BUFFER_SIZE (BUFFER_SIZE / 2) + +#define LCD_FACTOR ((float)LCD_WIDTH / (float)100.0f) +/* The threshold for the YIN algorithm */ +#define YIN_THRESHOLD float2fixed(0.05f) + +/* How loud the audio has to be to start displaying pitch */ +/* Must be between 0 and 0x3fff0000 */ +/* The actual volume threshold will be the sq root of this */ +#define VOLUME_THRESHOLD (0x1000000) +/* Change to AUDIO_SRC_LINE if you want to record from line-in */ +#define INPUT_TYPE AUDIO_SRC_MIC + +static signed short audio_data[BUFFER_SIZE]; +fixed yin_buffer[BUFFER_SIZE / 2]; +static int recording=0; + +/* Frequencies of all the notes of the scale */ +static const float freqs[12] = +{ + 440.0f, /* A */ + 466.1637615f, /* A# */ + 493.8833013f, /* etc... */ + 523.2511306f, + 554.3652620f, + 587.3295358f, + 622.2539674f, + 659.2551138f, + 698.4564629f, + 739.9888454f, + 783.9908720f, + 830.6093952f +}; +/* logarithm of all the notes of the scale */ +static const float lfreqs[12] = +{ + 6.086774727f, + 6.144536992f, + 6.202299257f, + 6.260061522f, + 6.317823787f, + 6.375586052f, + 6.433348317f, + 6.491110582f, + 6.548872847f, + 6.606635112f, + 6.664397377f, + 6.722159642f +}; + +/* GUI */ +static unsigned back_color, front_color; +static int xx,yy; +static int bar_x_minus_50, bar_x_minus_20, bar_x_0, bar_x_20, bar_x_50; + +static const char *english_notes[12] = {"A","A#","B","C","C#","D","D#","E", +"F","F#", "G", "G#"}; +static const char gui_letters[8] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', '#'}; +static const char **notes = english_notes; + +/* Fixed-point Natural log */ +float log(float inp) +{ + int x; + long t,y; + + x = (int) ( inp * ( 1 << 16 ) ); + + y=0xa65af; + if(x<0x00008000) x<<=16, y-=0xb1721; + if(x<0x00800000) x<<= 8, y-=0x58b91; + if(x<0x08000000) x<<= 4, y-=0x2c5c8; + if(x<0x20000000) x<<= 2, y-=0x162e4; + if(x<0x40000000) x<<= 1, y-=0x0b172; + t=x+(x>>1); if((t&0x80000000)==0) x=t,y-=0x067cd; + t=x+(x>>2); if((t&0x80000000)==0) x=t,y-=0x03920; + t=x+(x>>3); if((t&0x80000000)==0) x=t,y-=0x01e27; + t=x+(x>>4); if((t&0x80000000)==0) x=t,y-=0x00f85; + t=x+(x>>5); if((t&0x80000000)==0) x=t,y-=0x007e1; + t=x+(x>>6); if((t&0x80000000)==0) x=t,y-=0x003f8; + t=x+(x>>7); if((t&0x80000000)==0) x=t,y-=0x001fe; + x=0x80000000-x; + y-=x>>15; + + return (float)y / (float)0x10000; +} + +/* The function name is pretty self-explaining ;) */ +void print_int_xy(int x, int y, int v) +{ + char temp[20]; + + rb->lcd_set_foreground(front_color); + rb->snprintf(temp,20,"%d",v); + rb->lcd_putsxy(x,y,temp); + rb->lcd_update(); +} + +/* Print out the frequency etc - will be removed later on */ +void print_str(char* s) +{ + rb->lcd_set_foreground(front_color); + rb->lcd_putsxy(0, 50, s); + rb->lcd_update(); +} + +/* What can I say? Read the function name... */ +void print_char_xy(int x, int y, char c) +{ + char temp[2]; + + temp[0]=c; + temp[1]=0; + rb->lcd_set_foreground(front_color); + + rb->lcd_putsxy(x, y, temp); +} + +/* Draw the red bar and the white lines */ +void draw_bar(float wrong_by_cents) +{ +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); /* Color screens */ +#elif LCD_DEPTH > 1 + rb->lcd_set_foreground(LCD_DARKGRAY); /* Greyscale screens */ +#else + rb->lcd_set_foreground(LCD_BLACK); /* Black and white screens */ +#endif + + if (wrong_by_cents > 0) + { + rb->lcd_fillrect(bar_x_0,90, (int)(wrong_by_cents * LCD_FACTOR), 20); + } + else + { + rb->lcd_fillrect(bar_x_0 + (int)(wrong_by_cents * LCD_FACTOR),90, + (int)(wrong_by_cents * LCD_FACTOR) * -1, 20); + } +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_RGBPACK(255,255,255)); /* Color screens */ +#elif LCD_DEPTH > 1 + rb->lcd_set_foreground(LCD_BLACK); /* Greyscale screens */ +#else + rb->lcd_set_foreground(LCD_BLACK); /* Black and white screens */ +#endif + + rb->lcd_hline(0,LCD_WIDTH-1, 85); + rb->lcd_hline(0,LCD_WIDTH-1, 115); + rb->lcd_vline(LCD_WIDTH / 2, 85, 115); + + print_int_xy(bar_x_minus_50 ,70, -50); + print_int_xy(bar_x_minus_20 ,70, -20); + print_int_xy(bar_x_0 ,70, 0); + print_int_xy(bar_x_20 ,70, 20); + print_int_xy(bar_x_50 ,70, 50); + + + + rb->lcd_update(); + +} + +/* Print the letters A-G and the # on the screen */ +void draw_letters(void) +{ + int i; + + rb->lcd_set_foreground(front_color); + + for (i=0; i<8; i++) + { + print_char_xy(i*(LCD_WIDTH / 8 ) + xx, 10, gui_letters[i]); + } +} + +/* Draw the yellow point(s) below the letters and the '#' */ +void draw_points(const char *s) +{ + int i; + + i = s[0]-'A'; +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_RGBPACK(255,255,0)); /* Color screens */ +#elif LCD_DEPTH > 1 + rb->lcd_set_foreground(LCD_DARKGRAY); /* Grey screens */ +#else + rb->lcd_set_foreground(LCD_BLACK); /* Black and White screens */ +#endif + + rb->lcd_fillrect(i*(LCD_WIDTH / 8 ) + xx, 25, yy, yy); + + if (s[1] == '#') + rb->lcd_fillrect(7*(LCD_WIDTH / 8 ) + xx, 25, yy, yy); + + rb->lcd_update(); +} + +/* Calculate how wrong the note is and draw the GUI */ +void display_frequency (float freq) +{ + float ldf, mldf; + float lfreq, nfreq; + int i, note = 0; + char str_buf[30]; + + if (freq < 1E-15) freq = 1E-15; + lfreq = log(freq); + while (lfreq < lfreqs[0]-LOG_D_NOTE/2.0f) lfreq += LOG_2; + while (lfreq >= lfreqs[0]+LOG_2-LOG_D_NOTE/2.0f) lfreq -= LOG_2; + mldf = LOG_D_NOTE; + for (i=0; i<12; i++) + { + ldf = ((lfreq-lfreqs[i]>0) ? lfreq-lfreqs[i] : -(lfreq-lfreqs[i])); + if (ldf < mldf) + { + mldf = ldf; + note = i; + } + } + nfreq = freqs[note]; + while (nfreq/freq > D_NOTE_SQRT) nfreq /= 2.0f; + while (freq/nfreq > D_NOTE_SQRT) nfreq *= 2.0f; + + ldf=1200*(log(freq/nfreq)/LOG_2); + + if ((int)freq == 0) /* prevents red bar at -32 cents when freq= 0*/ + { + ldf = 0; + } + + rb->snprintf(str_buf,30, "%s : %d cents (%dHz)", + notes[note], (int)(ldf + 0.5f) ,(int)(freq + 0.5f)); + + rb->lcd_clear_display(); + + draw_bar(ldf); /* The red bar */ + draw_letters(); /* The A-G letters and the # */ + draw_points(notes[note]); /* The yellow point(s) */ + print_str(str_buf); +} + +/*----------------------------------------------------------------------- + * Functions for the Yin algorithm + * + * These were all adapted from the versions in Aubio v0.3.2 + * Here's what the Aubio documentation has to say: + * + * This algorithm was developped by A. de Cheveigne and H. Kawahara and + * published in: + * + * de Cheveign?, A., Kawahara, H. (2002) "YIN, a fundamental frequency + * estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930. + * + * see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html +-------------------------------------------------------------------------*/ + +/* Find the index of the minimum element of an array of floats */ +unsigned vec_min_elem(fixed *s, unsigned buflen) +{ + unsigned j, pos=0.0f; + fixed tmp = s[0]; + for (j=0; j < buflen; j++) + { + if(fp_gt(tmp, s[j])) + { + pos = j; + tmp = s[j]; + } + } + tmp = fp_add(tmp, tmp); + tmp = fp_sub(tmp, tmp); + tmp = fp_mul(tmp, tmp); + tmp = fp_div(tmp, tmp); + return pos; +} + + +fixed aubio_quadfrac(fixed s0, fixed s1, fixed s2, fixed pf) +{ + /* Original floating point version: */ + /* tmp = s0 + (pf/2.0f) * (pf * ( s0 - 2.0f*s1 + s2 ) - 3.0f*s0 + 4.0f*s1 - s2);*/ + /* Converted to explicit operator precedence: */ + /* tmp = s0 + ((pf/2.0f) * ((((pf * ((s0 - (2*s1)) + s2)) - (3*s0)) + (4*s1)) - s2)); */ + + /* I made it look like this so I could easily track the precedence and */ + /* make sure it matched the original expression */ + /* Oy, this is when I really wish I could do C++ operator overloading */ + fixed tmp = fp_add + ( + s0, + fp_mul + ( + fp_shr(pf, 1), + fp_sub + ( + fp_add + ( + fp_sub + ( + fp_mul + ( + pf, + fp_add + ( + fp_sub + ( + s0, + fp_shl(s1, 1) + ), + s2 + ) + ), + fp_mul + ( + float2fixed(3.0f), + s0 + ) + ), + fp_shl(s1, 2) + ), + s2 + ) + ) + ); + return tmp; +} + +#define QUADINT_STEP float2fixed(1.0f/200.0f) + +fixed vec_quadint_min(fixed *x, unsigned bufsize, unsigned pos, unsigned span) +{ + fixed res, frac, s0, s1, s2; + fixed exactpos = int2fixed(pos); + /* init resold to something big (in case x[pos+-span]<0)) */ + fixed resold = FIXED_MAX; + + if ((pos > span) && (pos < bufsize-span)) + { + s0 = x[pos-span]; + s1 = x[pos] ; + s2 = x[pos+span]; + /* increase frac */ + for (frac = float2fixed(0.0f); + fp_lt(frac, float2fixed(2.0f)); + frac = fp_add(frac, QUADINT_STEP)) + { + res = aubio_quadfrac(s0, s1, s2, frac); + if (fp_lt(res, resold)) + { + resold = res; + } + else + { + /* exactpos += (frac-QUADINT_STEP)*span - span/2.0f; */ + exactpos = fp_add(exactpos, + fp_sub( + fp_mul( + fp_sub(frac, QUADINT_STEP), + int2fixed(span) + ), + fp_shr(int2fixed(span), 1) + ) + ); + break; + } + } + } + return exactpos; +} + + +/* Calculate the period of the note in the + buffer using the YIN algorithm */ +/* The yin pointer is just a buffer that the algorithm uses as a work + space. It needs to be half the length of the input buffer. */ + +float pitchyin(int16_t *input, fixed *yin) +{ + fixed retval; + unsigned j,tau = 0; + int period; + fixed tmp = int2fixed(0), tmp2 = int2fixed(0); + yin[0] = int2fixed(1); + for (tau = 1; tau < YIN_BUFFER_SIZE; tau++) + { + yin[tau] = int2fixed(0); + for (j=0;j 4 && fp_lt(yin[period], YIN_THRESHOLD) && + fp_lt(yin[period], yin[period+1])) + { + retval = vec_quadint_min(yin, YIN_BUFFER_SIZE, period, 1); + return fixed2float(retval); + } + } + /*return vec_quadint_min(yin, YIN_BUFFER_SIZE, vec_min_elem(yin, yin_bufsize), 1);*/ + return 0.0f; +} + +/*-----------------------------------------------------------------*/ + +uint32_t buffer_magnitude(int16_t *input) +{ + int n; + uint64_t tally = 0; + for(n = 0; n < BUFFER_SIZE; n++) + { + tally += (uint64_t)input[n] * (uint64_t)input[n]; + } + + tally /= BUFFER_SIZE; + + /* now tally holds the average of the squares of all the samples */ + /* It must be between 0 and 0x7fff^2, so it fits in 32 bits */ + return (uint32_t)tally; +} + +/* Stop the recording when the buffer is full */ +int recording_callback(int status) +{ + (void) status; + + rb->pcm_stop_recording(); + recording=0; + return -1; +} + +/* The main program loop */ +void record_and_get_pitch(void) +{ + int quit=0, button; + long timer; + char time_string[20]; + float period; + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + + while(!quit) + { + /* Start recording */ + rb->pcm_record_data(recording_callback, (void *) audio_data, + (size_t) BUFFER_SIZE*sizeof(signed short)); + recording=1; + + while (recording && !quit) /* wait for the buffer to be filled */ + { + rb->backlight_on(); + rb->yield(); + button=rb->button_get(false); + switch(button) + { + case TUNER_QUIT: + quit=true; + rb->yield(); + break; + + default: + rb->yield(); + + break; + } + } + + /*rec_peaks(audio_data, BUFFER_SIZE);*/ + /*schmitt_algorithm (BUFFER_SIZE, audio_data);*/ /* get the pitch */ + + /* Let's keep track of how long this takes */ + timer = *(rb->current_tick); + + /* Only do the heavy lifting if the volume is high enough */ + if(buffer_magnitude(audio_data) > VOLUME_THRESHOLD) + { + /* This returns the period of the detected pitch in samples */ + period = pitchyin(audio_data, yin_buffer); + /* Hz = sample rate / period */ + if(period != 0) + { + display_frequency((float)SAMPLE_RATE / period); + } + else + { + display_frequency(0); + } + } + + /* Print out how long it took to find the pitch */ + rb->snprintf(time_string, 20, "latency: %ld", *(rb->current_tick) - timer); + rb->lcd_putsxy(0, 40, time_string); + rb->lcd_update(); + } + rb->pcm_close_recording(); +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif +} + +/* Init recording, tuning, and GUI */ +void init_everything(void) +{ + /* --------- Init the audio recording ----------------- */ + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); + rb->audio_set_input_source(INPUT_TYPE, SRCF_RECORDING); + + /* This should really be wrapped in platform-specific #ifdefs */ + /* set to maximum gain as in as3514.c */ + rb->audio_set_recording_gain(39,39, AUDIO_GAIN_MIC); + + rb->pcm_set_frequency(SAMPLE_RATE); + rb->pcm_apply_settings(); + + rb->pcm_init_recording(); + + back_color = rb->lcd_get_background(); /* GUI */ + front_color = rb->lcd_get_foreground(); + rb->lcd_getstringsize("X", &xx, &yy); + + bar_x_minus_50=0; + bar_x_minus_20 = (LCD_WIDTH / 2) - + (int)(LCD_FACTOR * 20.0f) - xx; + bar_x_0 = LCD_WIDTH / 2; + bar_x_20 = (LCD_WIDTH / 2) + + (int)(LCD_FACTOR * 20.0f) - xx; + bar_x_50 = LCD_WIDTH - 2 * xx; + + /* print_int_xy(0,100,(int) *rb->rec_freq_sampr); + print_int_xy(0,110,(int) SAMPLE_RATE); */ +} + + +enum plugin_status plugin_start(const void* parameter) NO_PROF_ATTR +{ + (void)parameter; + + init_everything(); + record_and_get_pitch(); + + return 0; +} Index: apps/plugins/SOURCES =================================================================== --- apps/plugins/SOURCES (revision 22470) +++ apps/plugins/SOURCES (working copy) @@ -29,6 +29,9 @@ rockbox_flash.c #endif /* CONFIG_CPU */ +#ifdef HAVE_RECORDING +pitch_detector.c +#endif #if (CONFIG_CODEC == SWCODEC) || !defined(SIMULATOR) metronome.c