diff --git a/apps/plugin.c b/apps/plugin.c index 53a05bf527..5101ceeb20 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -721,6 +721,8 @@ static const struct plugin_api rockbox_api = { /* new stuff at the end, sort into place next time the API gets incompatible */ + + lcd_putsf, }; int plugin_load(const char* plugin, const void* parameter) diff --git a/apps/plugin.h b/apps/plugin.h index 17c36fa8b1..2bcd93e3ad 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -894,6 +894,8 @@ struct plugin_api { /* new stuff at the end, sort into place next time the API gets incompatible */ + + void (*lcd_putsf)(int x, int y, const unsigned char *fmt, ...); }; /* plugin header */ diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c index 36e7059c1f..92ba6e53ac 100644 --- a/apps/plugins/pitch_detector.c +++ b/apps/plugins/pitch_detector.c @@ -5,7 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ - * $Id$ + * $Id$ * * Copyright (C) 2008 Lechner Michael / smoking gnu * @@ -19,15 +19,15 @@ * * 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 + * 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: * - 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 @@ -42,7 +42,7 @@ * Aubio sound processing library (aubio.org). -David * 08.31.2009 Lots of changes: * Added a menu to tweak settings - * Converted everything to fixed point (greatly improving + * Converted everything to fixed point (greatly improving * latency) * Improved the display * Improved efficiency with judicious use of cpu_boost, the @@ -51,17 +51,17 @@ * Fixed a problem that caused an octave-off error * -David * 05.14.2010 Multibuffer continuous recording with two buffers - * - * + * + * * CURRENT LIMITATIONS: * - No gapless recording. Strictly speaking true gappless isn't possible, * since the algorithm takes longer to calculate than the length of the * sample, but latency could be improved a bit with proper use of the DMA * recording functions. - * - Due to how the Yin algorithm works, latency is higher for lower + * - Due to how the Yin algorithm works, latency is higher for lower * frequencies. */ - + #include "plugin.h" #include "lib/pluginlib_actions.h" #include "lib/picture.h" @@ -140,7 +140,7 @@ typedef struct _fixed fixed; /* 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 */ -/* If we ever switch to Yin FFT algorithm then this needs to be +/* If we ever switch to Yin FFT algorithm then this needs to be a power of 2 */ #define BUFFER_SIZE 4096 #define SAMPLE_SIZE 4096 @@ -150,7 +150,7 @@ typedef struct _fixed fixed; #define LCD_FACTOR (fp_div(int2fixed(LCD_WIDTH), int2fixed(100))) /* The threshold for the YIN algorithm */ #define DEFAULT_YIN_THRESHOLD 5 /* 0.10 */ -const fixed yin_threshold_table[] IDATA_ATTR = +static const fixed yin_threshold_table[] IDATA_ATTR = { float2fixed(0.01), float2fixed(0.02), @@ -173,14 +173,12 @@ const fixed yin_threshold_table[] IDATA_ATTR = * the note. The frequency is scaled in a way that the main * algorithm can assume the frequency of A to be 440 Hz. */ -struct freq_A_entry +static const struct { const int frequency; /* Frequency in Hz */ const fixed ratio; /* 440/frequency */ const fixed logratio; /* log2(factor) */ -}; - -const struct freq_A_entry freq_A[] = +} freq_A[] = { {435, float2fixed(1.011363636), float2fixed( 0.016301812)}, {436, float2fixed(1.009090909), float2fixed( 0.013056153)}, @@ -214,8 +212,8 @@ const struct freq_A_entry freq_A[] = #define DISPLAY_HZ_PRECISION 100 /* Where to put the various GUI elements */ -int note_y; -int bar_grad_y; +static int note_y; +static int bar_grad_y; #define LCD_RES_MIN (LCD_HEIGHT < LCD_WIDTH ? LCD_HEIGHT : LCD_WIDTH) #define BAR_PADDING (LCD_RES_MIN / 32) #define BAR_Y (LCD_HEIGHT * 3 / 4) @@ -225,7 +223,7 @@ int bar_grad_y; #define HZ_Y 0 #define GRADUATION 10 /* Subdivisions of the whole 100-cent scale */ -/* Bitmaps for drawing the note names. These need to have height +/* Bitmaps for drawing the note names. These need to have height <= (bar_grad_y - note_y), or 15/32 * LCD_HEIGHT */ #define NUM_NOTE_IMAGES 9 @@ -238,7 +236,8 @@ int bar_grad_y; #define NOTE_INDEX_G 6 #define NOTE_INDEX_SHARP 7 #define NOTE_INDEX_FLAT 8 -const struct picture note_bitmaps = + +static const struct picture note_bitmaps = { pitch_notes, BMPWIDTH_pitch_notes, @@ -261,16 +260,13 @@ static int16_t iram_audio_data[BUFFER_SIZE] IBSS_ATTR; #endif #endif -/* Description of a note of scale */ -struct note_entry +/* Notes within one (reference) scale */ +static const struct { const char *name; /* Name of the note, e.g. "A#" */ const fixed freq; /* Note frequency, Hz */ const fixed logfreq; /* log2(frequency) */ -}; - -/* Notes within one (reference) scale */ -static const struct note_entry notes[] = +} notes[] = { {"A" , float2fixed(440.0000000f), float2fixed(8.781359714f)}, {"A#", float2fixed(466.1637615f), float2fixed(8.864693047f)}, @@ -295,7 +291,7 @@ static int bar_x_0; static int lbl_x_minus_50, lbl_x_minus_20, lbl_x_0, lbl_x_20, lbl_x_50; /* Settings for the plugin */ -struct tuner_settings +static struct tuner_settings { unsigned volume_threshold; unsigned record_gain; @@ -305,7 +301,7 @@ struct tuner_settings int freq_A; /* Index of the frequency of A */ bool use_sharps; bool display_hz; -} tuner_settings; +} settings; /*=================================================================*/ /* Settings loading and saving(adapted from the clock plugin) */ @@ -313,98 +309,68 @@ struct tuner_settings #define SETTINGS_FILENAME PLUGIN_APPS_DIR "/.pitch_settings" -enum message -{ - MESSAGE_LOADING, - MESSAGE_LOADED, - MESSAGE_ERRLOAD, - MESSAGE_SAVING, - MESSAGE_SAVED, - MESSAGE_ERRSAVE -}; - -enum settings_file_status -{ - LOADED, ERRLOAD, - SAVED, ERRSAVE -}; - -/* The settings as they exist on the hard disk, so that +/* The settings as they exist on the hard disk, so that * we can know at saving time if changes have been made */ -struct tuner_settings hdd_tuner_settings; +static struct tuner_settings hdd_settings; /*---------------------------------------------------------------------*/ -bool settings_needs_saving(struct tuner_settings* settings) +static bool settings_needs_saving(void) { - return(rb->memcmp(settings, &hdd_tuner_settings, sizeof(*settings))); + return(rb->memcmp(&settings, &hdd_settings, sizeof(settings))); } /*---------------------------------------------------------------------*/ -void tuner_settings_reset(struct tuner_settings* settings) +static void tuner_settings_reset(void) { - settings->volume_threshold = VOLUME_THRESHOLD; - settings->record_gain = rb->global_settings->rec_mic_gain; - settings->sample_size = BUFFER_SIZE; - settings->lowest_freq = period2freq(BUFFER_SIZE / 4); - settings->yin_threshold = DEFAULT_YIN_THRESHOLD; - settings->freq_A = DEFAULT_FREQ_A; - settings->use_sharps = true; - settings->display_hz = false; + settings = (struct tuner_settings) { + .volume_threshold = VOLUME_THRESHOLD, + .record_gain = rb->global_settings->rec_mic_gain, + .sample_size = BUFFER_SIZE, + .lowest_freq = period2freq(BUFFER_SIZE / 4), + .yin_threshold = DEFAULT_YIN_THRESHOLD, + .freq_A = DEFAULT_FREQ_A, + .use_sharps = true, + .display_hz = false, + }; } /*---------------------------------------------------------------------*/ -enum settings_file_status tuner_settings_load(struct tuner_settings* settings, - char* filename) +static void load_settings(void) { - int fd = rb->open(filename, O_RDONLY); - if(fd >= 0){ /* does file exist? */ - /* basic consistency check */ - if(rb->filesize(fd) == sizeof(*settings)){ - rb->read(fd, settings, sizeof(*settings)); - rb->close(fd); - rb->memcpy(&hdd_tuner_settings, settings, sizeof(*settings)); - return(LOADED); - } + int fd = rb->open(SETTINGS_FILENAME, O_RDONLY); + if(fd < 0){ /* file doesn't exist */ + /* Initializes the settings with default values at least */ + tuner_settings_reset(); + return; } - /* Initializes the settings with default values at least */ - tuner_settings_reset(settings); - return(ERRLOAD); -} -/*---------------------------------------------------------------------*/ - -enum settings_file_status tuner_settings_save(struct tuner_settings* settings, - char* filename) -{ - int fd = rb->creat(filename, 0666); - if(fd >= 0){ /* does file exist? */ - rb->write (fd, settings, sizeof(*settings)); - rb->close(fd); - return(SAVED); + /* basic consistency check */ + if(rb->filesize(fd) == sizeof(settings)){ + rb->read(fd, &settings, sizeof(settings)); + rb->memcpy(&hdd_settings, &settings, sizeof(settings)); } - return(ERRSAVE); + else{ + tuner_settings_reset(); + } + + rb->close(fd); } /*---------------------------------------------------------------------*/ -void load_settings(void) +static void save_settings(void) { - tuner_settings_load(&tuner_settings, SETTINGS_FILENAME); - - rb->storage_sleep(); -} - -/*---------------------------------------------------------------------*/ - -void save_settings(void) -{ - if(!settings_needs_saving(&tuner_settings)) + if(!settings_needs_saving()) return; - tuner_settings_save(&tuner_settings, SETTINGS_FILENAME); + int fd = rb->creat(SETTINGS_FILENAME, 0666); + if(fd >= 0){ /* does file exist? */ + rb->write (fd, &settings, sizeof(settings)); + rb->close(fd); + } } /*=================================================================*/ @@ -423,7 +389,7 @@ const struct button_mapping* plugin_contexts[]={ /* Option strings */ /* This has to match yin_threshold_table */ -static const struct opt_items yin_threshold_text[] = +static const struct opt_items yin_threshold_text[] = { { "0.01", -1 }, { "0.02", -1 }, @@ -441,27 +407,27 @@ static const struct opt_items yin_threshold_text[] = { "0.50", -1 }, }; -static const struct opt_items accidental_text[] = +static const struct opt_items accidental_text[] = { { "Flat", -1 }, { "Sharp", -1 }, }; -void set_min_freq(int new_freq) +static void set_min_freq(int new_freq) { - tuner_settings.sample_size = freq2period(new_freq) * 4; + settings.sample_size = freq2period(new_freq) * 4; /* clamp the sample size between min and max */ - if(tuner_settings.sample_size <= SAMPLE_SIZE_MIN) - tuner_settings.sample_size = SAMPLE_SIZE_MIN; - else if(tuner_settings.sample_size >= BUFFER_SIZE) - tuner_settings.sample_size = BUFFER_SIZE; + if(settings.sample_size <= SAMPLE_SIZE_MIN) + settings.sample_size = SAMPLE_SIZE_MIN; + else if(settings.sample_size >= BUFFER_SIZE) + settings.sample_size = BUFFER_SIZE; /* sample size must be divisible by 4 - round up */ - tuner_settings.sample_size = (tuner_settings.sample_size + 3) & ~3; + settings.sample_size = (settings.sample_size + 3) & ~3; } -bool main_menu(void) +static bool main_menu(void) { int selection = 0; bool done = false; @@ -494,58 +460,58 @@ bool main_menu(void) { case 1: rb->set_int("Volume Threshold", "%", UNIT_INT, - &tuner_settings.volume_threshold, + &settings.volume_threshold, NULL, 5, 5, 95, NULL); break; case 2: rb->set_int("Listening Volume", "%", UNIT_INT, - &tuner_settings.record_gain, - NULL, 1, rb->sound_min(SOUND_MIC_GAIN), + &settings.record_gain, + NULL, 1, rb->sound_min(SOUND_MIC_GAIN), rb->sound_max(SOUND_MIC_GAIN), NULL); break; case 3: rb->set_int("Lowest Frequency", "Hz", UNIT_INT, - &tuner_settings.lowest_freq, set_min_freq, 1, + &settings.lowest_freq, set_min_freq, 1, /* Range depends on the size of the buffer */ - sample_rate / (BUFFER_SIZE / 4), + sample_rate / (BUFFER_SIZE / 4), sample_rate / (SAMPLE_SIZE_MIN / 4), NULL); break; case 4: rb->set_option( "Algorithm Pickiness (Lower -> more discriminating)", - &tuner_settings.yin_threshold, + &settings.yin_threshold, INT, yin_threshold_text, sizeof(yin_threshold_text) / sizeof(yin_threshold_text[0]), NULL); break; case 5: rb->set_option("Display Accidentals As", - &tuner_settings.use_sharps, + &settings.use_sharps, BOOL, accidental_text, 2, NULL); break; case 6: rb->set_bool("Display Frequency (Hz)", - &tuner_settings.display_hz); + &settings.display_hz); break; case 7: - freq_val = freq_A[tuner_settings.freq_A].frequency; + freq_val = freq_A[settings.freq_A].frequency; rb->set_int("Frequency of A (Hz)", "Hz", UNIT_INT, &freq_val, NULL, 1, freq_A[0].frequency, freq_A[NUM_FREQ_A-1].frequency, NULL); - tuner_settings.freq_A = freq_val - freq_A[0].frequency; + settings.freq_A = freq_val - freq_A[0].frequency; break; case 8: reset = false; rb->set_bool("Reset Tuner Settings?", &reset); if (reset) - tuner_settings_reset(&tuner_settings); + tuner_settings_reset(); break; case 9: exit_tuner = true; done = true; break; - case 0: + case 0: default: /* Return to the tuner */ done = true; @@ -562,15 +528,15 @@ bool main_menu(void) /*=================================================================*/ /* Fixed-point log base 2*/ -/* Adapted from python code at +/* Adapted from python code at http://en.wikipedia.org/wiki/Binary_logarithm#Algorithm */ -fixed log(fixed inp) +static fixed log(fixed inp) { fixed x = inp; fixed fp = int2fixed(1); fixed res = int2fixed(0); - + if(fp_lte(x, FP_ZERO)) { return FP_MIN; @@ -611,59 +577,25 @@ fixed log(fixed inp) /* GUI Stuff */ /*=================================================================*/ -/* The function name is pretty self-explaining ;) */ -void print_int_xy(int x, int y, int v) -{ - char temp[20]; -#if LCD_DEPTH > 1 - rb->lcd_set_foreground(front_color); -#endif - rb->snprintf(temp,20,"%d",v); - rb->lcd_putsxy(x,y,temp); -} - -/* Print out the frequency etc */ -void print_str(char* s) -{ -#if LCD_DEPTH > 1 - rb->lcd_set_foreground(front_color); -#endif - rb->lcd_putsxy(0, HZ_Y, s); -} - -/* 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; -#if LCD_DEPTH > 1 - rb->lcd_set_foreground(front_color); -#endif - - rb->lcd_putsxy(x, y, temp); -} - /* Draw the note bitmap */ -void draw_note(const char *note) +static void draw_note(const char *note) { int i; int note_x = (LCD_WIDTH - BMPWIDTH_pitch_notes) / 2; int accidental_index = NOTE_INDEX_SHARP; - + i = note[0]-'A'; if(note[1] == '#') { - if(!(tuner_settings.use_sharps)) + if(!(settings.use_sharps)) { i = (i + 1) % 7; accidental_index = NOTE_INDEX_FLAT; } - vertical_picture_draw_sprite(rb->screens[0], - ¬e_bitmaps, + vertical_picture_draw_sprite(rb->screens[0], + ¬e_bitmaps, accidental_index, LCD_WIDTH / 2, note_y); @@ -674,9 +606,10 @@ void draw_note(const char *note) note_x, note_y); } + /* Draw the red bar and the white lines */ -void draw_bar(fixed wrong_by_cents) -{ +static void draw_bar(fixed wrong_by_cents) +{ unsigned n; int x; @@ -698,11 +631,14 @@ void draw_bar(fixed wrong_by_cents) rb->lcd_vline(x, BAR_HLINE_Y, BAR_HLINE_Y2); } - print_int_xy(lbl_x_minus_50 ,bar_grad_y, -50); - print_int_xy(lbl_x_minus_20 ,bar_grad_y, -20); - print_int_xy(lbl_x_0 ,bar_grad_y, 0); - print_int_xy(lbl_x_20 ,bar_grad_y, 20); - print_int_xy(lbl_x_50 ,bar_grad_y, 50); +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(front_color); +#endif + rb->lcd_putsf(lbl_x_minus_50 ,bar_grad_y, "%d", -50); + rb->lcd_putsf(lbl_x_minus_20 ,bar_grad_y, "%d", -20); + rb->lcd_putsf(lbl_x_0 ,bar_grad_y, "%d", 0); + rb->lcd_putsf(lbl_x_20 ,bar_grad_y, "%d", 20); + rb->lcd_putsf(lbl_x_50 ,bar_grad_y, "%d", 50); #ifdef HAVE_LCD_COLOR rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); /* Color screens */ @@ -712,26 +648,25 @@ void draw_bar(fixed wrong_by_cents) if (fp_gt(wrong_by_cents, FP_ZERO)) { - rb->lcd_fillrect(bar_x_0, BAR_Y, + rb->lcd_fillrect(bar_x_0, BAR_Y, fixed2int(fp_mul(wrong_by_cents, LCD_FACTOR)), BAR_HEIGHT); } else { rb->lcd_fillrect(bar_x_0 + fixed2int(fp_mul(wrong_by_cents,LCD_FACTOR)), BAR_Y, - fixed2int(fp_mul(wrong_by_cents, LCD_FACTOR)) * -1, + fixed2int(fp_mul(wrong_by_cents, LCD_FACTOR)) * -1, BAR_HEIGHT); } } /* Calculate how wrong the note is and draw the GUI */ -void display_frequency (fixed freq) +static void display_frequency (fixed freq) { fixed ldf, mldf; fixed lfreq, nfreq; fixed orig_freq; int i, note = 0; - char str_buf[30]; if (fp_lt(freq, FP_LOW)) freq = FP_LOW; @@ -739,8 +674,8 @@ void display_frequency (fixed freq) /* We calculate the frequency and its log as if */ /* the reference frequency of A were 440 Hz. */ orig_freq = freq; - lfreq = fp_add(log(freq), freq_A[tuner_settings.freq_A].logratio); - freq = fp_mul(freq, freq_A[tuner_settings.freq_A].ratio); + lfreq = fp_add(log(freq), freq_A[settings.freq_A].logratio); + freq = fp_mul(freq, freq_A[settings.freq_A].ratio); /* This calculates a log freq offset for note A */ /* Get the frequency to within the range of our reference table, */ @@ -775,39 +710,41 @@ void display_frequency (fixed freq) if(fp_round(freq) != 0) { draw_note(notes[note].name); - if(tuner_settings.display_hz) + if(settings.display_hz) { - rb->snprintf(str_buf,30, "%s : %d cents (%d.%02dHz)", +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(front_color); +#endif + rb->lcd_putsf(0, HZ_Y, "%s : %d cents (%d.%02dHz)", notes[note].name, fp_round(ldf) ,fixed2int(orig_freq), fp_round(fp_mul(fp_frac(orig_freq), int2fixed(DISPLAY_HZ_PRECISION)))); - print_str(str_buf); } } rb->lcd_update(); } /*----------------------------------------------------------------------- - * Functions for the Yin algorithm - * - * These were all adapted from the versions in Aubio v0.3.2 + * 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. + * 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) +static unsigned vec_min_elem(fixed *s, unsigned buflen) { unsigned j, pos=0.0f; fixed tmp = s[0]; - for (j=0; j < buflen; j++) + for (j=0; j < buflen; j++) { if(fp_gt(tmp, s[j])) { @@ -819,13 +756,13 @@ unsigned vec_min_elem(fixed *s, unsigned buflen) } -static inline fixed aubio_quadfrac(fixed s0, fixed s1, fixed s2, fixed pf) +static inline 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 ) - + /* 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)) - + /* 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 */ @@ -853,7 +790,7 @@ static inline fixed aubio_quadfrac(fixed s0, fixed s1, fixed s2, fixed pf) s0, fp_shl(s1, 1) ), - s2 + s2 ) ), fp_mul @@ -873,32 +810,32 @@ static inline fixed aubio_quadfrac(fixed s0, fixed s1, fixed s2, fixed pf) #define QUADINT_STEP float2fixed(1.0f/200.0f) -fixed ICODE_ATTR vec_quadint_min(fixed *x, unsigned bufsize, unsigned pos, unsigned span) +static fixed ICODE_ATTR 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 = FP_MAX; - if ((pos > span) && (pos < bufsize-span)) + 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)) + 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)) + if (fp_lt(res, resold)) { resold = res; - } - else + } + else { /* exactpos += (frac-QUADINT_STEP)*span - span/2.0f; */ - exactpos = fp_add(exactpos, + exactpos = fp_add(exactpos, fp_sub( fp_mul( fp_sub(frac, QUADINT_STEP), @@ -915,17 +852,17 @@ fixed ICODE_ATTR vec_quadint_min(fixed *x, unsigned bufsize, unsigned pos, unsig } -/* Calculate the period of the note in the +/* 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. */ -fixed ICODE_ATTR pitchyin(int16_t *input, fixed *yin) +static fixed ICODE_ATTR pitchyin(int16_t *input, fixed *yin) { fixed retval; unsigned j,tau = 0; int period; - unsigned yin_size = tuner_settings.sample_size / 4; + unsigned yin_size = settings.sample_size / 4; fixed tmp = FP_ZERO, tmp2 = FP_ZERO; yin[0] = int2fixed(1); @@ -934,7 +871,7 @@ fixed ICODE_ATTR pitchyin(int16_t *input, fixed *yin) yin[tau] = FP_ZERO; for (j = 0; j < yin_size; j++) { - tmp = fp_sub(int2mantissa(input[2 * j]), + tmp = fp_sub(int2mantissa(input[2 * j]), int2mantissa(input[2 * (j + tau)])); yin[tau] = fp_add(yin[tau], fp_mul(tmp, tmp)); } @@ -944,15 +881,15 @@ fixed ICODE_ATTR pitchyin(int16_t *input, fixed *yin) yin[tau] = fp_mul(yin[tau], fp_div(int2fixed(tau), tmp2)); } period = tau - 3; - if(tau > 4 && fp_lt(yin[period], - yin_threshold_table[tuner_settings.yin_threshold]) + if(tau > 4 && fp_lt(yin[period], + yin_threshold_table[settings.yin_threshold]) && fp_lt(yin[period], yin[period+1])) { retval = vec_quadint_min(yin, yin_size, period, 1); return retval; } } - retval = vec_quadint_min(yin, yin_size, + retval = vec_quadint_min(yin, yin_size, vec_min_elem(yin, yin_size), 1); return retval; /*return FP_ZERO;*/ @@ -960,11 +897,11 @@ fixed ICODE_ATTR pitchyin(int16_t *input, fixed *yin) /*-----------------------------------------------------------------*/ -uint32_t ICODE_ATTR buffer_magnitude(int16_t *input) +static uint32_t ICODE_ATTR buffer_magnitude(int16_t *input) { unsigned n; uint64_t tally = 0; - const unsigned size = tuner_settings.sample_size; + const unsigned size = settings.sample_size; /* Operate on only one channel of the stereo signal */ for(n = 0; n < size; n+=2) @@ -982,7 +919,7 @@ uint32_t ICODE_ATTR buffer_magnitude(int16_t *input) /* Stop the recording when the buffer is full */ #ifndef SIMULATOR -void recording_callback(int status, void **start, size_t *size) +static void recording_callback(int status, void **start, size_t *size) { int tail = audio_tail ^ 1; @@ -1003,13 +940,13 @@ static void record_data(void) { #ifndef SIMULATOR /* Always record full buffer, even if not required */ - rb->pcm_record_data(recording_callback, audio_data[audio_tail], + rb->pcm_record_data(recording_callback, audio_data[audio_tail], BUFFER_SIZE * sizeof (int16_t)); #endif } /* The main program loop */ -void record_and_get_pitch(void) +static void record_and_get_pitch(void) { int quit=0, button; bool redraw = true; @@ -1029,18 +966,18 @@ void record_and_get_pitch(void) record_data(); - while(!quit) + while(!quit) { while (audio_head == audio_tail && !quit) /* wait for the buffer to be filled */ - { + { button=pluginlib_getaction(HZ/100, plugin_contexts, PLA_ARRAY_COUNT); - switch(button) + switch(button) { case PLA_EXIT: quit=true; break; - + case PLA_CANCEL: rb->pcm_stop_recording(); quit = main_menu() != 0; @@ -1050,17 +987,17 @@ void record_and_get_pitch(void) record_data(); } break; - + break; } - } - + } + if(!quit) { #ifndef SIMULATOR /* Only do the heavy lifting if the volume is high enough */ - if(buffer_magnitude(audio_data[audio_head]) > - sqr(tuner_settings.volume_threshold * + if(buffer_magnitude(audio_data[audio_head]) > + sqr(settings.volume_threshold * rb->sound_max(SOUND_MIC_GAIN))) { waiting = false; @@ -1071,7 +1008,7 @@ void record_and_get_pitch(void) #endif #ifdef PLUGIN_USE_IRAM rb->memcpy(iram_audio_data, audio_data[audio_head], - tuner_settings.sample_size * sizeof (int16_t)); + settings.sample_size * sizeof (int16_t)); #endif /* This returns the period of the detected pitch in samples */ period = pitchyin(iram_audio_data, yin_buffer); @@ -1080,7 +1017,7 @@ void record_and_get_pitch(void) { display_frequency(fp_period2freq(period)); } - else + else { display_frequency(FP_ZERO); } @@ -1115,7 +1052,7 @@ void record_and_get_pitch(void) } /* Init recording, tuning, and GUI */ -void init_everything(void) +static void init_everything(void) { /* Disable all talking before initializing IRAM */ rb->talk_disable(true); @@ -1123,17 +1060,18 @@ void init_everything(void) PLUGIN_IRAM_INIT(rb); load_settings(); + rb->storage_sleep(); /* Stop all playback (if no IRAM, otherwise IRAM_INIT would have) */ rb->plugin_get_audio_buffer(NULL); /* --------- Init the audio recording ----------------- */ - rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); - rb->audio_set_input_source(INPUT_TYPE, SRCF_RECORDING); + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); + rb->audio_set_input_source(INPUT_TYPE, SRCF_RECORDING); /* set to maximum gain */ - rb->audio_set_recording_gain(tuner_settings.record_gain, - tuner_settings.record_gain, + rb->audio_set_recording_gain(settings.record_gain, + settings.record_gain, AUDIO_GAIN_MIC); /* Highest C on piano is approx 4.186 kHz, so we need just over @@ -1145,15 +1083,15 @@ void init_everything(void) rb->pcm_init_recording(); /* avoid divsion by zero */ - if(tuner_settings.lowest_freq == 0) - tuner_settings.lowest_freq = period2freq(BUFFER_SIZE / 4); + if(settings.lowest_freq == 0) + settings.lowest_freq = period2freq(BUFFER_SIZE / 4); /* GUI */ #if LCD_DEPTH > 1 front_color = rb->lcd_get_foreground(); #endif rb->lcd_getstringsize("X", &font_w, &font_h); - + bar_x_0 = LCD_WIDTH / 2; lbl_x_minus_50 = 0; lbl_x_minus_20 = (LCD_WIDTH / 2) - @@ -1174,10 +1112,10 @@ void init_everything(void) enum plugin_status plugin_start(const void* parameter) NO_PROF_ATTR { (void)parameter; - + init_everything(); record_and_get_pitch(); save_settings(); - return 0; + return PLUGIN_OK; }