summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-05-14 06:25:40 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-05-14 06:25:40 +0000
commit7250405c70a0d2fe8468c225f1e89840266e65c1 (patch)
treecd29e1b5ea7e621a7389daf0ece3d320b21976b8 /apps/plugins
parent0b52d34313b90f42412691f749b03448754f915b (diff)
downloadrockbox-7250405c70a0d2fe8468c225f1e89840266e65c1.zip
rockbox-7250405c70a0d2fe8468c225f1e89840266e65c1.tar.gz
rockbox-7250405c70a0d2fe8468c225f1e89840266e65c1.tar.bz2
rockbox-7250405c70a0d2fe8468c225f1e89840266e65c1.tar.xz
pitch_detector: Use continuous recording, even if the algorithm is too slow for that and record a whole buffer even if the min frequency is higher. Use the minimum samplerate that allows C-4186 to be detected (usually 11.025kHz, which can reduce computational load to 1/16 compared to 44.1kHz). Get rid of 64-bit multiplies when calculating input RMS value. Stop audio playback when entering plugin. Better backlight and CPU frequency handling. audio_sample_type->int16_t. simpler buffer size rounding.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26005 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/pitch_detector.c168
1 files changed, 92 insertions, 76 deletions
diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c
index a394450..9de8d99 100644
--- a/apps/plugins/pitch_detector.c
+++ b/apps/plugins/pitch_detector.c
@@ -25,10 +25,6 @@
* 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
* - 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
*
@@ -54,6 +50,7 @@
* calculation
* Fixed a problem that caused an octave-off error
* -David
+ * 05.14.2010 Multibuffer continuous recording with two buffers
*
*
* CURRENT LIMITATIONS:
@@ -68,19 +65,11 @@
#include "plugin.h"
#include "lib/pluginlib_actions.h"
#include "lib/picture.h"
+#include "lib/helper.h"
#include "pluginbitmaps/pitch_notes.h"
PLUGIN_HEADER
-/* First figure out what sample rate we're going to use */
-#if (REC_SAMPR_CAPS & SAMPR_CAP_44)
-#define SAMPLE_RATE SAMPR_44
-#elif (REC_SAMPR_CAPS & SAMPR_CAP_22)
-#define SAMPLE_RATE SAMPR_22
-#elif (REC_SAMPR_CAPS & SAMPR_CAP_11)
-#define SAMPLE_RATE SAMPR_11
-#endif
-
/* Some fixed point calculation stuff */
typedef int32_t fixed_data;
struct _fixed
@@ -129,10 +118,10 @@ typedef struct _fixed fixed;
/* With an 18-bit decimal precision, the max value in the */
/* integer part is 8192. Divide 44100 by 7 and it'll fit in */
/* that variable. */
-#define fp_period2freq(x) fp_div(int2fixed(SAMPLE_RATE / 7), \
+#define fp_period2freq(x) fp_div(int2fixed(sample_rate / 7), \
fp_div((x),int2fixed(7)))
#define fp_freq2period(x) fp_period2freq(x)
-#define period2freq(x) (SAMPLE_RATE / (x))
+#define period2freq(x) (sample_rate / (x))
#define freq2period(x) period2freq(x)
#define sqr(x) ((x)*(x))
@@ -146,7 +135,7 @@ typedef struct _fixed fixed;
/* The recording buffer size */
/* This is how much is sampled at a time. */
-/* It also determines latency -- if BUFFER_SIZE == SAMPLE_RATE then */
+/* 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 */
@@ -257,11 +246,12 @@ const struct picture note_bitmaps =
};
-typedef signed short audio_sample_type;
+static unsigned int sample_rate;
+static int audio_head = 0; /* which of the two buffers to use? */
+static volatile int audio_tail = 0; /* which of the two buffers to record? */
/* It's stereo, so make the buffer twice as big */
-audio_sample_type audio_data[BUFFER_SIZE];
-fixed yin_buffer[YIN_BUFFER_SIZE];
-static int recording=0;
+static int16_t audio_data[2][BUFFER_SIZE];
+static fixed yin_buffer[YIN_BUFFER_SIZE];
/* Description of a note of scale */
struct note_entry
@@ -460,9 +450,9 @@ void set_min_freq(int new_freq)
tuner_settings.sample_size = SAMPLE_SIZE_MIN;
else if(tuner_settings.sample_size >= BUFFER_SIZE)
tuner_settings.sample_size = BUFFER_SIZE;
- /* sample size must be divisible by 4 */
- else if(tuner_settings.sample_size % 4 != 0)
- tuner_settings.sample_size += 4 - (tuner_settings.sample_size % 4);
+
+ /* sample size must be divisible by 4 - round up */
+ tuner_settings.sample_size = (tuner_settings.sample_size + 3) & ~3;
}
bool main_menu(void)
@@ -474,6 +464,11 @@ bool main_menu(void)
int freq_val;
bool reset;
+ backlight_use_settings();
+#ifdef HAVE_SCHEDULER_BOOSTCTRL
+ rb->cancel_cpu_boost();
+#endif
+
MENUITEM_STRINGLIST(menu,"Tuner Settings",NULL,
"Return to Tuner",
"Volume Threshold",
@@ -506,8 +501,8 @@ bool main_menu(void)
rb->set_int("Lowest Frequency", "Hz", UNIT_INT,
&tuner_settings.lowest_freq, set_min_freq, 1,
/* Range depends on the size of the buffer */
- SAMPLE_RATE / (BUFFER_SIZE / 4),
- SAMPLE_RATE / (SAMPLE_SIZE_MIN / 4), NULL);
+ sample_rate / (BUFFER_SIZE / 4),
+ sample_rate / (SAMPLE_SIZE_MIN / 4), NULL);
break;
case 4:
rb->set_option(
@@ -551,6 +546,8 @@ bool main_menu(void)
break;
}
}
+
+ backlight_force_on();
return exit_tuner;
}
@@ -917,7 +914,7 @@ fixed vec_quadint_min(fixed *x, unsigned bufsize, unsigned pos, unsigned span)
/* 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 pitchyin(audio_sample_type *input, fixed *yin)
+fixed pitchyin(int16_t *input, fixed *yin)
{
fixed retval;
unsigned j,tau = 0;
@@ -957,7 +954,7 @@ fixed pitchyin(audio_sample_type *input, fixed *yin)
/*-----------------------------------------------------------------*/
-uint32_t buffer_magnitude(audio_sample_type *input)
+uint32_t buffer_magnitude(int16_t *input)
{
unsigned n;
uint64_t tally = 0;
@@ -965,7 +962,8 @@ uint32_t buffer_magnitude(audio_sample_type *input)
/* Operate on only one channel of the stereo signal */
for(n = 0; n < tuner_settings.sample_size; n+=2)
{
- tally += (uint64_t)input[n] * (uint64_t)input[n];
+ int s = input[n];
+ tally += s * s;
}
tally /= tuner_settings.sample_size / 2;
@@ -976,12 +974,32 @@ uint32_t buffer_magnitude(audio_sample_type *input)
}
/* Stop the recording when the buffer is full */
+#ifndef SIMULATOR
int recording_callback(int status)
{
- (void) status;
-
- recording=0;
- return -1;
+ int tail = audio_tail ^ 1;
+
+ /* Do not overrun the reader. Reuse current buffer if full. */
+ if (tail != audio_head)
+ audio_tail = tail;
+
+ /* Always record full buffer, even if not required */
+ rb->pcm_record_more(audio_data[tail],
+ BUFFER_SIZE * sizeof (int16_t));
+
+ return 0;
+ (void)status;
+}
+#endif
+
+/* Start recording */
+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],
+ BUFFER_SIZE * sizeof (int16_t));
+#endif
}
/* The main program loop */
@@ -999,41 +1017,32 @@ void record_and_get_pitch(void)
bool waiting = false;
#endif
+ backlight_force_on();
+
+ record_data();
+
while(!quit)
{
-#ifndef SIMULATOR
- /* Start recording */
- rb->pcm_record_data(recording_callback, (void *) audio_data,
- (size_t) tuner_settings.sample_size *
- sizeof(audio_sample_type));
-#endif
- recording=1;
-
- while (recording && !quit) /* wait for the buffer to be filled */
+ while (audio_head == audio_tail && !quit) /* wait for the buffer to be filled */
{
- rb->yield();
-#ifdef SIMULATOR
- /* Only do this loop once if this is the simulator */
- recording = 0;
-#endif
- button=pluginlib_getaction(0, plugin_contexts, PLA_ARRAY_COUNT);
+ button=pluginlib_getaction(HZ/100, plugin_contexts, PLA_ARRAY_COUNT);
+
switch(button)
{
case PLA_QUIT:
quit=true;
- rb->yield();
break;
case PLA_MENU:
- if(main_menu())
- quit=true;
- else redraw = true;
- rb->yield();
+ rb->pcm_stop_recording();
+ quit = main_menu() != 0;
+ if(!quit)
+ {
+ redraw = true;
+ record_data();
+ }
break;
- default:
- rb->yield();
-
break;
}
}
@@ -1042,23 +1051,19 @@ void record_and_get_pitch(void)
{
#ifndef SIMULATOR
/* Only do the heavy lifting if the volume is high enough */
- if(buffer_magnitude(audio_data) >
- sqr(tuner_settings.volume_threshold *
+ if(buffer_magnitude(audio_data[audio_head]) >
+ sqr(tuner_settings.volume_threshold *
rb->sound_max(SOUND_MIC_GAIN)))
{
- if(waiting)
- {
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(true);
-#endif
- waiting = false;
- }
-
- rb->backlight_on();
+ waiting = false;
redraw = false;
+ #ifdef HAVE_SCHEDULER_BOOSTCTRL
+ rb->trigger_cpu_boost();
+ #endif
+
/* This returns the period of the detected pitch in samples */
- period = pitchyin(audio_data, yin_buffer);
+ period = pitchyin(audio_data[audio_head], yin_buffer);
/* Hz = sample rate / period */
if(fp_gt(period, FP_ZERO))
{
@@ -1073,22 +1078,27 @@ void record_and_get_pitch(void)
{
waiting = true;
redraw = false;
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(false);
-#endif
- /*rb->backlight_off();*/
display_frequency(FP_ZERO);
+ #ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cancel_cpu_boost();
+ #endif
}
#else /* SIMULATOR */
/* Display a preselected frequency */
display_frequency(int2fixed(445));
#endif
+ /* Move to next buffer if not empty (but empty *shouldn't* happen
+ * here). */
+ if (audio_head != audio_tail)
+ audio_head ^= 1;
}
}
rb->pcm_close_recording();
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(false);
+#ifdef HAVE_SCHEDULER_BOOSTCTRL
+ rb->cancel_cpu_boost();
#endif
+
+ backlight_use_settings();
}
/* Init recording, tuning, and GUI */
@@ -1096,6 +1106,9 @@ void init_everything(void)
{
load_settings();
+ /* Stop all playback */
+ 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);
@@ -1105,9 +1118,12 @@ void init_everything(void)
tuner_settings.record_gain,
AUDIO_GAIN_MIC);
- rb->pcm_set_frequency(SAMPLE_RATE);
- rb->pcm_apply_settings();
-
+ /* Highest C on piano is approx 4.186 kHz, so we need just over
+ * 8.372 kHz to pass it. */
+ sample_rate = rb->round_value_to_list32(9000, rb->rec_freq_sampr,
+ REC_NUM_FREQ, false);
+ sample_rate = rb->rec_freq_sampr[sample_rate];
+ rb->pcm_set_frequency(sample_rate);
rb->pcm_init_recording();
/* GUI */