diff options
author | Alexander Levin <al.le@rockbox.org> | 2009-09-20 16:16:32 +0000 |
---|---|---|
committer | Alexander Levin <al.le@rockbox.org> | 2009-09-20 16:16:32 +0000 |
commit | 46bb567ec4df041426372afaae75931636575695 (patch) | |
tree | 1f887b2212f4e8d53a950ee8637a215f94169d93 /apps/plugins/pitch_detector.c | |
parent | 2474708498dfb197ea7a06567aacde5a9fec39b7 (diff) | |
download | rockbox-46bb567ec4df041426372afaae75931636575695.tar.gz rockbox-46bb567ec4df041426372afaae75931636575695.zip |
Pitch Detector: add the possibility to set the reference frequency of A (last part of FS#8768)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22753 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pitch_detector.c')
-rw-r--r-- | apps/plugins/pitch_detector.c | 91 |
1 files changed, 72 insertions, 19 deletions
diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c index 857d74afc4..eb3b56ca92 100644 --- a/apps/plugins/pitch_detector.c +++ b/apps/plugins/pitch_detector.c | |||
@@ -178,6 +178,37 @@ const fixed yin_threshold_table[] = | |||
178 | float2fixed(0.50), | 178 | float2fixed(0.50), |
179 | }; | 179 | }; |
180 | 180 | ||
181 | /* Structure for the reference frequency (frequency of A) | ||
182 | * It's used for scaling the frequency before finding out | ||
183 | * the note. The frequency is scaled in a way that the main | ||
184 | * algorithm can assume the frequency of A to be 440 Hz. | ||
185 | */ | ||
186 | struct freq_A_entry | ||
187 | { | ||
188 | const int frequency; /* Frequency in Hz */ | ||
189 | const fixed ratio; /* 440/frequency */ | ||
190 | const fixed logratio; /* log2(factor) */ | ||
191 | }; | ||
192 | |||
193 | const struct freq_A_entry freq_A[] = | ||
194 | { | ||
195 | {435, float2fixed(1.011363636), float2fixed( 0.016301812)}, | ||
196 | {436, float2fixed(1.009090909), float2fixed( 0.013056153)}, | ||
197 | {437, float2fixed(1.006818182), float2fixed( 0.009803175)}, | ||
198 | {438, float2fixed(1.004545455), float2fixed( 0.006542846)}, | ||
199 | {439, float2fixed(1.002272727), float2fixed( 0.003275132)}, | ||
200 | {440, float2fixed(1.000000000), float2fixed( 0.000000000)}, | ||
201 | {441, float2fixed(0.997727273), float2fixed(-0.003282584)}, | ||
202 | {442, float2fixed(0.995454545), float2fixed(-0.006572654)}, | ||
203 | {443, float2fixed(0.993181818), float2fixed(-0.009870244)}, | ||
204 | {444, float2fixed(0.990909091), float2fixed(-0.013175389)}, | ||
205 | {445, float2fixed(0.988636364), float2fixed(-0.016488123)}, | ||
206 | }; | ||
207 | |||
208 | /* Index of the entry for 440 Hz in the table (default frequency for A) */ | ||
209 | #define DEFAULT_FREQ_A 5 | ||
210 | #define NUM_FREQ_A (sizeof(freq_A)/sizeof(freq_A[0])) | ||
211 | |||
181 | /* How loud the audio has to be to start displaying pitch */ | 212 | /* How loud the audio has to be to start displaying pitch */ |
182 | /* Must be between 0 and 100 */ | 213 | /* Must be between 0 and 100 */ |
183 | #define VOLUME_THRESHOLD (50) | 214 | #define VOLUME_THRESHOLD (50) |
@@ -279,8 +310,9 @@ struct tuner_settings | |||
279 | unsigned sample_size; | 310 | unsigned sample_size; |
280 | unsigned lowest_freq; | 311 | unsigned lowest_freq; |
281 | unsigned yin_threshold; | 312 | unsigned yin_threshold; |
282 | bool use_sharps; | 313 | int freq_A; /* Index of the frequency of A */ |
283 | bool display_hz; | 314 | bool use_sharps; |
315 | bool display_hz; | ||
284 | } tuner_settings; | 316 | } tuner_settings; |
285 | 317 | ||
286 | /*=================================================================*/ | 318 | /*=================================================================*/ |
@@ -325,6 +357,7 @@ void tuner_settings_reset(struct tuner_settings* settings) | |||
325 | settings->sample_size = BUFFER_SIZE; | 357 | settings->sample_size = BUFFER_SIZE; |
326 | settings->lowest_freq = period2freq(BUFFER_SIZE / 4); | 358 | settings->lowest_freq = period2freq(BUFFER_SIZE / 4); |
327 | settings->yin_threshold = DEFAULT_YIN_THRESHOLD; | 359 | settings->yin_threshold = DEFAULT_YIN_THRESHOLD; |
360 | settings->freq_A = DEFAULT_FREQ_A; | ||
328 | settings->use_sharps = true; | 361 | settings->use_sharps = true; |
329 | settings->display_hz = false; | 362 | settings->display_hz = false; |
330 | } | 363 | } |
@@ -454,11 +487,12 @@ void set_min_freq(int new_freq) | |||
454 | 487 | ||
455 | bool main_menu(void) | 488 | bool main_menu(void) |
456 | { | 489 | { |
457 | int selection=0; | 490 | int selection = 0; |
458 | bool done = false; | 491 | bool done = false; |
459 | bool exit_tuner=false; | 492 | bool exit_tuner = false; |
460 | int choice; | 493 | int choice; |
461 | bool reset = false; | 494 | int freq_val; |
495 | bool reset; | ||
462 | 496 | ||
463 | MENUITEM_STRINGLIST(menu,"Tuner Settings",NULL, | 497 | MENUITEM_STRINGLIST(menu,"Tuner Settings",NULL, |
464 | "Return to Tuner", | 498 | "Return to Tuner", |
@@ -468,6 +502,7 @@ bool main_menu(void) | |||
468 | "Algorithm Pickiness", | 502 | "Algorithm Pickiness", |
469 | "Accidentals", | 503 | "Accidentals", |
470 | "Display Frequency (Hz)", | 504 | "Display Frequency (Hz)", |
505 | "Frequency of A (Hz)", | ||
471 | "Reset Settings", | 506 | "Reset Settings", |
472 | "Quit"); | 507 | "Quit"); |
473 | 508 | ||
@@ -514,21 +549,31 @@ bool main_menu(void) | |||
514 | BOOL, noyes_text, 2, NULL); | 549 | BOOL, noyes_text, 2, NULL); |
515 | break; | 550 | break; |
516 | case 7: | 551 | case 7: |
552 | freq_val = freq_A[tuner_settings.freq_A].frequency; | ||
553 | rb->set_int("Frequency of A (Hz)", | ||
554 | "Hz", UNIT_INT, &freq_val, NULL, | ||
555 | 1, freq_A[0].frequency, freq_A[NUM_FREQ_A-1].frequency, | ||
556 | NULL); | ||
557 | tuner_settings.freq_A = freq_val - freq_A[0].frequency; | ||
558 | break; | ||
559 | case 8: | ||
560 | reset = false; | ||
517 | rb->set_option("Reset Tuner Settings?", | 561 | rb->set_option("Reset Tuner Settings?", |
518 | &reset, | 562 | &reset, |
519 | BOOL, noyes_text, 2, tuner_settings_reset_query); | 563 | BOOL, noyes_text, 2, tuner_settings_reset_query); |
520 | break; | 564 | break; |
521 | case 8: | 565 | case 9: |
522 | exit_tuner = true; | 566 | exit_tuner = true; |
567 | done = true; | ||
568 | break; | ||
523 | case 0: | 569 | case 0: |
524 | default: | 570 | default: |
525 | /* Return to the tuner */ | 571 | /* Return to the tuner */ |
526 | done = true; | 572 | done = true; |
527 | break; | 573 | break; |
528 | |||
529 | } | 574 | } |
530 | } | 575 | } |
531 | return(exit_tuner); | 576 | return exit_tuner; |
532 | } | 577 | } |
533 | 578 | ||
534 | /*=================================================================*/ | 579 | /*=================================================================*/ |
@@ -650,11 +695,11 @@ void draw_bar(fixed wrong_by_cents) | |||
650 | int x; | 695 | int x; |
651 | 696 | ||
652 | #ifdef HAVE_LCD_COLOR | 697 | #ifdef HAVE_LCD_COLOR |
653 | rb->lcd_set_foreground(LCD_RGBPACK(255,255,255)); /* Color screens */ | 698 | rb->lcd_set_foreground(LCD_RGBPACK(255,255,255)); /* Color screens */ |
654 | #elif LCD_DEPTH > 1 | 699 | #elif LCD_DEPTH > 1 |
655 | rb->lcd_set_foreground(LCD_BLACK); /* Greyscale screens */ | 700 | rb->lcd_set_foreground(LCD_BLACK); /* Greyscale screens */ |
656 | #else | 701 | #else |
657 | rb->lcd_set_foreground(LCD_BLACK); /* Black and white screens */ | 702 | rb->lcd_set_foreground(LCD_BLACK); /* Black and white screens */ |
658 | #endif | 703 | #endif |
659 | 704 | ||
660 | rb->lcd_hline(0,LCD_WIDTH-1, BAR_HLINE_Y); | 705 | rb->lcd_hline(0,LCD_WIDTH-1, BAR_HLINE_Y); |
@@ -702,14 +747,22 @@ void display_frequency (fixed freq) | |||
702 | { | 747 | { |
703 | fixed ldf, mldf; | 748 | fixed ldf, mldf; |
704 | fixed lfreq, nfreq; | 749 | fixed lfreq, nfreq; |
750 | fixed orig_freq; | ||
705 | int i, note = 0; | 751 | int i, note = 0; |
706 | char str_buf[30]; | 752 | char str_buf[30]; |
707 | 753 | ||
708 | if (fp_lt(freq, FP_LOW)) | 754 | if (fp_lt(freq, FP_LOW)) |
709 | freq = FP_LOW; | 755 | freq = FP_LOW; |
710 | lfreq = log(freq); | 756 | |
711 | 757 | /* We calculate the frequency and its log as if */ | |
712 | /* Get the frequency to within the range of our reference table */ | 758 | /* the reference frequency of A were 440 Hz. */ |
759 | orig_freq = freq; | ||
760 | lfreq = fp_add(log(freq), freq_A[tuner_settings.freq_A].logratio); | ||
761 | freq = fp_mul(freq, freq_A[tuner_settings.freq_A].ratio); | ||
762 | |||
763 | /* This calculates a log freq offset for note A */ | ||
764 | /* Get the frequency to within the range of our reference table, */ | ||
765 | /* i.e. into the right octave. */ | ||
713 | while (fp_lt(lfreq, fp_sub(lfreqs[0], fp_shr(LOG_D_NOTE, 1)))) | 766 | while (fp_lt(lfreq, fp_sub(lfreqs[0], fp_shr(LOG_D_NOTE, 1)))) |
714 | lfreq = fp_add(lfreq, LOG_2); | 767 | lfreq = fp_add(lfreq, LOG_2); |
715 | while (fp_gte(lfreq, fp_sub(fp_add(lfreqs[0], LOG_2), | 768 | while (fp_gte(lfreq, fp_sub(fp_add(lfreqs[0], LOG_2), |
@@ -722,19 +775,19 @@ void display_frequency (fixed freq) | |||
722 | fp_sub(lfreq,lfreqs[i]) : fp_neg(fp_sub(lfreq,lfreqs[i])); | 775 | fp_sub(lfreq,lfreqs[i]) : fp_neg(fp_sub(lfreq,lfreqs[i])); |
723 | if (fp_lt(ldf, mldf)) | 776 | if (fp_lt(ldf, mldf)) |
724 | { | 777 | { |
725 | mldf = ldf; | 778 | mldf = ldf; |
726 | note = i; | 779 | note = i; |
727 | } | 780 | } |
728 | } | 781 | } |
729 | nfreq = freqs[note]; | 782 | nfreq = freqs[note]; |
730 | while (fp_gt(fp_div(nfreq, freq), D_NOTE_SQRT)) | 783 | while (fp_gt(fp_div(nfreq, freq), D_NOTE_SQRT)) |
731 | nfreq = fp_shr(nfreq, 1); | 784 | nfreq = fp_shr(nfreq, 1); |
732 | while (fp_gt(fp_div(freq, nfreq), D_NOTE_SQRT)) | 785 | while (fp_gt(fp_div(freq, nfreq), D_NOTE_SQRT)) |
733 | { | 786 | { |
734 | nfreq = fp_shl(nfreq, 1); | 787 | nfreq = fp_shl(nfreq, 1); |
735 | } | 788 | } |
736 | 789 | ||
737 | ldf=fp_mul(int2fixed(1200), log(fp_div(freq,nfreq))); | 790 | ldf = fp_mul(int2fixed(1200), log(fp_div(freq,nfreq))); |
738 | 791 | ||
739 | rb->lcd_clear_display(); | 792 | rb->lcd_clear_display(); |
740 | draw_bar(ldf); /* The red bar */ | 793 | draw_bar(ldf); /* The red bar */ |
@@ -744,8 +797,8 @@ void display_frequency (fixed freq) | |||
744 | if(tuner_settings.display_hz) | 797 | if(tuner_settings.display_hz) |
745 | { | 798 | { |
746 | rb->snprintf(str_buf,30, "%s : %d cents (%d.%02dHz)", | 799 | rb->snprintf(str_buf,30, "%s : %d cents (%d.%02dHz)", |
747 | notes[note], fp_round(ldf) ,fixed2int(freq), | 800 | notes[note], fp_round(ldf) ,fixed2int(orig_freq), |
748 | fp_round(fp_mul(fp_frac(freq), | 801 | fp_round(fp_mul(fp_frac(orig_freq), |
749 | int2fixed(DISPLAY_HZ_PRECISION)))); | 802 | int2fixed(DISPLAY_HZ_PRECISION)))); |
750 | print_str(str_buf); | 803 | print_str(str_buf); |
751 | } | 804 | } |