diff options
| author | Thom Johansen <thomj@rockbox.org> | 2005-11-28 22:26:20 +0000 |
|---|---|---|
| committer | Thom Johansen <thomj@rockbox.org> | 2005-11-28 22:26:20 +0000 |
| commit | 27c658c8a655ebe4f8160c24486867aca2900754 (patch) | |
| tree | 9b91b1275e1c0ed493af477f5656f5edfb42b9aa | |
| parent | 1d6eeea1e196b6d7beefab70a6ee664340ab7bef (diff) | |
| download | rockbox-27c658c8a655ebe4f8160c24486867aca2900754.zip rockbox-27c658c8a655ebe4f8160c24486867aca2900754.tar.gz rockbox-27c658c8a655ebe4f8160c24486867aca2900754.tar.bz2 rockbox-27c658c8a655ebe4f8160c24486867aca2900754.tar.xz | |
Enabled playback speed adjustment support for H1x0. Modified the resampler to do both channels in one pass.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8099 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | apps/dsp.c | 145 | ||||
| -rw-r--r-- | apps/dsp.h | 3 | ||||
| -rw-r--r-- | apps/playback.c | 3 | ||||
| -rw-r--r-- | apps/playback.h | 3 | ||||
| -rw-r--r-- | apps/screens.c | 13 | ||||
| -rw-r--r-- | apps/screens.h | 4 |
6 files changed, 101 insertions, 70 deletions
@@ -128,7 +128,8 @@ struct dsp_config { - long frequency; + long codec_frequency; /* Sample rate of data coming from the codec */ + long frequency; /* Effective sample rate after pitch shift (if any) */ long clip_min; long clip_max; long track_gain; @@ -147,9 +148,8 @@ struct dsp_config struct resample_data { - long last_sample; - long phase; - long delta; + long phase, delta; + long last_sample[2]; }; struct dither_data @@ -168,9 +168,11 @@ struct crossfeed_data static struct dsp_config dsp_conf[2] IBSS_ATTR; static struct dither_data dither_data[2] IBSS_ATTR; -static struct resample_data resample_data[2][2] IBSS_ATTR; +static struct resample_data resample_data[2] IBSS_ATTR; struct crossfeed_data crossfeed_data IBSS_ATTR; +static int pitch_ratio = 1000; + extern int current_codec; struct dsp_config *dsp; @@ -182,6 +184,18 @@ struct dsp_config *dsp; static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; +int sound_get_pitch(void) +{ + return pitch_ratio; +} + +void sound_set_pitch(int permille) +{ + pitch_ratio = permille; + + dsp_configure(DSP_SWITCH_FREQUENCY, (int *)dsp->codec_frequency); +} + /* Convert at most count samples to the internal format, if needed. Returns * number of samples ready for further processing. Updates src to point * past the samples "consumed" and dst is set to point to the samples to @@ -270,64 +284,81 @@ static int convert_to_internal(char* src[], int count, long* dst[]) return count; } +static void resampler_set_delta(int frequency) +{ + resample_data[current_codec].delta = (unsigned long) + frequency * 65536LL / NATIVE_FREQUENCY; +} + /* Linear resampling that introduces a one sample delay, because of our * inability to look into the future at the end of a frame. */ -static long downsample(long *dst, long *src, int count, +/* TODO: we really should have a separate set of resample functions for both + mono and stereo to avoid all this internal branching and looping. */ +static long downsample(long **dst, long **src, int count, struct resample_data *r) { long phase = r->phase; long delta = r->delta; - long last_sample = r->last_sample; + long last_sample; + long *d[2] = { dst[0], dst[1] }; int pos = phase >> 16; - int i = 1; - - /* Do we need last sample of previous frame for interpolation? */ - if (pos > 0) - { - last_sample = src[pos - 1]; + int i = 1, j; + int num_channels = src[0] == src[1] ? 1 : 2; + + for (j = 0; j < num_channels; j++) { + last_sample = r->last_sample[j]; + /* Do we need last sample of previous frame for interpolation? */ + if (pos > 0) + { + last_sample = src[j][pos - 1]; + } + *d[j]++ = last_sample + FRACMUL((phase & 0xffff) << 15, + src[j][pos] - last_sample); } - - *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15, - src[pos] - last_sample); phase += delta; - + while ((pos = phase >> 16) < count) { - *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15, - src[pos] - src[pos - 1]); - phase += delta; - i++; + for (j = 0; j < num_channels; j++) + *d[j]++ = src[j][pos - 1] + FRACMUL((phase & 0xffff) << 15, + src[j][pos] - src[j][pos - 1]); + phase += delta; + i++; } /* Wrap phase accumulator back to start of next frame. */ r->phase = phase - (count << 16); r->delta = delta; - r->last_sample = src[count - 1]; + r->last_sample[0] = src[0][count - 1]; + r->last_sample[1] = src[1][count - 1]; return i; } -static long upsample(long *dst, long *src, int count, struct resample_data *r) +static long upsample(long **dst, long **src, int count, struct resample_data *r) { long phase = r->phase; long delta = r->delta; - long last_sample = r->last_sample; - int i = 0; + long *d[2] = { dst[0], dst[1] }; + int i = 0, j; int pos; - + int num_channels = src[0] == src[1] ? 1 : 2; + while ((pos = phase >> 16) == 0) { - *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15, - src[pos] - last_sample); + for (j = 0; j < num_channels; j++) + *d[j]++ = r->last_sample[j] + FRACMUL((phase & 0xffff) << 15, + src[j][pos] - r->last_sample[j]); phase += delta; i++; } while ((pos = phase >> 16) < count) { - *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15, - src[pos] - src[pos - 1]); + for (j = 0; j < num_channels; j++) + *d[j]++ = src[j][pos - 1] + FRACMUL((phase & 0xffff) << 15, + src[j][pos] - src[j][pos - 1]); phase += delta; i++; } @@ -335,7 +366,8 @@ static long upsample(long *dst, long *src, int count, struct resample_data *r) /* Wrap phase accumulator back to start of next frame. */ r->phase = phase - (count << 16); r->delta = delta; - r->last_sample = src[count - 1]; + r->last_sample[0] = src[0][count - 1]; + r->last_sample[1] = src[1][count - 1]; return i; } @@ -349,36 +381,21 @@ static inline int resample(long* src[], int count) if (dsp->frequency != NATIVE_FREQUENCY) { - long* d0 = &resample_buf[0]; - /* Only process the second channel if needed. */ - long* d1 = (src[0] == src[1]) ? d0 - : &resample_buf[RESAMPLE_BUF_SIZE / 2]; + long* dst[2] = {&resample_buf[0], &resample_buf[RESAMPLE_BUF_SIZE / 2]}; if (dsp->frequency < NATIVE_FREQUENCY) { - new_count = upsample(d0, src[0], count, - &resample_data[current_codec][0]); - - if (d0 != d1) - { - upsample(d1, src[1], count, - &resample_data[current_codec][1]); - } + new_count = upsample(dst, src, count, + &resample_data[current_codec]); } else { - new_count = downsample(d0, src[0], count, - &resample_data[current_codec][0]); - - if (d0 != d1) - { - downsample(d1, src[1], count, - &resample_data[current_codec][1]); - } + new_count = downsample(dst, src, count, + &resample_data[current_codec]); } - src[0] = d0; - src[1] = d1; + src[0] = dst[0]; + src[1] = dst[1]; } else { @@ -767,7 +784,7 @@ long dsp_input_size(long size) * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and * round towards zero to avoid buffer overflows. */ size = ((unsigned long)size * - resample_data[current_codec][0].delta) >> 16; + resample_data[current_codec].delta) >> 16; } /* Convert back to bytes. */ @@ -793,14 +810,20 @@ bool dsp_configure(int setting, void *value) switch (setting) { case DSP_SET_FREQUENCY: - memset(&resample_data[current_codec][0], 0, - sizeof(struct resample_data) * 2); + memset(&resample_data[current_codec], 0, + sizeof(struct resample_data)); /* Fall through!!! */ case DSP_SWITCH_FREQUENCY: - dsp->frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value; - resample_data[current_codec][0].delta = - resample_data[current_codec][1].delta = - (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY; + dsp->codec_frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value; + /* Account for playback speed adjustment when settingg dsp->frequency + if we're called from the main audio thread. Voice UI thread should + not need this feature. + */ + if (current_codec == CODEC_IDX_AUDIO) + dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; + else + dsp->frequency = dsp->codec_frequency; + resampler_set_delta(dsp->frequency); break; case DSP_SET_CLIP_MIN: @@ -844,7 +867,7 @@ bool dsp_configure(int setting, void *value) dsp->album_gain = 0; dsp->track_peak = 0; dsp->album_peak = 0; - dsp->frequency = NATIVE_FREQUENCY; + dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; dsp->sample_depth = NATIVE_DEPTH; dsp->frac_bits = WORD_FRACBITS; dsp->new_gain = true; @@ -54,5 +54,6 @@ int dsp_stereo_mode(void); bool dsp_configure(int setting, void *value); void dsp_set_replaygain(bool always); void dsp_set_crossfeed(bool enable); - +void sound_set_pitch(int r); +int sound_get_pitch(void); #endif diff --git a/apps/playback.c b/apps/playback.c index 41659cb..563fb74 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -133,9 +133,6 @@ static struct mutex mutex_codecthread; static struct mp3entry id3_voice; -#define CODEC_IDX_AUDIO 0 -#define CODEC_IDX_VOICE 1 - static char *voicebuf; static int voice_remaining; static bool voice_is_playing; diff --git a/apps/playback.h b/apps/playback.h index 8128cc2..befaae8 100644 --- a/apps/playback.h +++ b/apps/playback.h @@ -27,6 +27,9 @@ #include "id3.h" #include "mp3data.h" +#define CODEC_IDX_AUDIO 0 +#define CODEC_IDX_VOICE 1 + /* Not yet implemented. */ #define CODEC_SET_AUDIOBUF_WATERMARK 4 diff --git a/apps/screens.c b/apps/screens.c index 1693c31..8bf18dc 100644 --- a/apps/screens.c +++ b/apps/screens.c @@ -342,11 +342,16 @@ int charging_screen(void) #endif /* HAVE_CHARGING && !HAVE_POWEROFF_WHILE_CHARGING */ -#if CONFIG_KEYPAD == RECORDER_PAD +#if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == IRIVER_H100_PAD /* returns: 0 if no key was pressed 1 if a key was pressed (or if ON was held down long enough to repeat) 2 if USB was connected */ +#if CONFIG_KEYPAD == RECORDER_PAD +#define PITCH_PAUSE BUTTON_PLAY +#elif CONFIG_KEYPAD == IRIVER_H100_PAD +#define PITCH_PAUSE BUTTON_SELECT +#endif int pitch_screen(void) { int button; @@ -411,17 +416,17 @@ int pitch_screen(void) sound_set_pitch(pitch); break; - case BUTTON_ON | BUTTON_PLAY: + case BUTTON_ON | PITCH_PAUSE: audio_pause(); used = true; break; - case BUTTON_PLAY | BUTTON_REL: + case PITCH_PAUSE | BUTTON_REL: audio_resume(); used = true; break; - case BUTTON_ON | BUTTON_PLAY | BUTTON_REL: + case BUTTON_ON | PITCH_PAUSE | BUTTON_REL: audio_resume(); exit = true; break; diff --git a/apps/screens.h b/apps/screens.h index f879da2..ea5e944 100644 --- a/apps/screens.h +++ b/apps/screens.h @@ -33,8 +33,10 @@ void charging_splash(void); int mmc_remove_request(void); #endif -#if CONFIG_KEYPAD == RECORDER_PAD +#if CONFIG_KEYPAD == RECORDER_PAD || defined(IRIVER_H100_SERIES) int pitch_screen(void); +#endif +#if CONFIG_KEYPAD == RECORDER_PAD extern bool quick_screen_f3(int button_enter); #endif extern bool quick_screen_quick(int button_enter); |