summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom Johansen <thomj@rockbox.org>2005-11-28 22:26:20 +0000
committerThom Johansen <thomj@rockbox.org>2005-11-28 22:26:20 +0000
commit27c658c8a655ebe4f8160c24486867aca2900754 (patch)
tree9b91b1275e1c0ed493af477f5656f5edfb42b9aa
parent1d6eeea1e196b6d7beefab70a6ee664340ab7bef (diff)
downloadrockbox-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.c145
-rw-r--r--apps/dsp.h3
-rw-r--r--apps/playback.c3
-rw-r--r--apps/playback.h3
-rw-r--r--apps/screens.c13
-rw-r--r--apps/screens.h4
6 files changed, 101 insertions, 70 deletions
diff --git a/apps/dsp.c b/apps/dsp.c
index 35f9cb6..3d02f5a 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -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;
diff --git a/apps/dsp.h b/apps/dsp.h
index f250d89..f86a4d9 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -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);