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 /apps/dsp.c | |
parent | 1d6eeea1e196b6d7beefab70a6ee664340ab7bef (diff) | |
download | rockbox-27c658c8a655ebe4f8160c24486867aca2900754.tar.gz rockbox-27c658c8a655ebe4f8160c24486867aca2900754.zip |
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
Diffstat (limited to 'apps/dsp.c')
-rw-r--r-- | apps/dsp.c | 145 |
1 files changed, 84 insertions, 61 deletions
diff --git a/apps/dsp.c b/apps/dsp.c index 35f9cb66bd..3d02f5a630 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -128,7 +128,8 @@ | |||
128 | 128 | ||
129 | struct dsp_config | 129 | struct dsp_config |
130 | { | 130 | { |
131 | long frequency; | 131 | long codec_frequency; /* Sample rate of data coming from the codec */ |
132 | long frequency; /* Effective sample rate after pitch shift (if any) */ | ||
132 | long clip_min; | 133 | long clip_min; |
133 | long clip_max; | 134 | long clip_max; |
134 | long track_gain; | 135 | long track_gain; |
@@ -147,9 +148,8 @@ struct dsp_config | |||
147 | 148 | ||
148 | struct resample_data | 149 | struct resample_data |
149 | { | 150 | { |
150 | long last_sample; | 151 | long phase, delta; |
151 | long phase; | 152 | long last_sample[2]; |
152 | long delta; | ||
153 | }; | 153 | }; |
154 | 154 | ||
155 | struct dither_data | 155 | struct dither_data |
@@ -168,9 +168,11 @@ struct crossfeed_data | |||
168 | 168 | ||
169 | static struct dsp_config dsp_conf[2] IBSS_ATTR; | 169 | static struct dsp_config dsp_conf[2] IBSS_ATTR; |
170 | static struct dither_data dither_data[2] IBSS_ATTR; | 170 | static struct dither_data dither_data[2] IBSS_ATTR; |
171 | static struct resample_data resample_data[2][2] IBSS_ATTR; | 171 | static struct resample_data resample_data[2] IBSS_ATTR; |
172 | struct crossfeed_data crossfeed_data IBSS_ATTR; | 172 | struct crossfeed_data crossfeed_data IBSS_ATTR; |
173 | 173 | ||
174 | static int pitch_ratio = 1000; | ||
175 | |||
174 | extern int current_codec; | 176 | extern int current_codec; |
175 | struct dsp_config *dsp; | 177 | struct dsp_config *dsp; |
176 | 178 | ||
@@ -182,6 +184,18 @@ struct dsp_config *dsp; | |||
182 | static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; | 184 | static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; |
183 | static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; | 185 | static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; |
184 | 186 | ||
187 | int sound_get_pitch(void) | ||
188 | { | ||
189 | return pitch_ratio; | ||
190 | } | ||
191 | |||
192 | void sound_set_pitch(int permille) | ||
193 | { | ||
194 | pitch_ratio = permille; | ||
195 | |||
196 | dsp_configure(DSP_SWITCH_FREQUENCY, (int *)dsp->codec_frequency); | ||
197 | } | ||
198 | |||
185 | /* Convert at most count samples to the internal format, if needed. Returns | 199 | /* Convert at most count samples to the internal format, if needed. Returns |
186 | * number of samples ready for further processing. Updates src to point | 200 | * number of samples ready for further processing. Updates src to point |
187 | * past the samples "consumed" and dst is set to point to the samples to | 201 | * 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[]) | |||
270 | return count; | 284 | return count; |
271 | } | 285 | } |
272 | 286 | ||
287 | static void resampler_set_delta(int frequency) | ||
288 | { | ||
289 | resample_data[current_codec].delta = (unsigned long) | ||
290 | frequency * 65536LL / NATIVE_FREQUENCY; | ||
291 | } | ||
292 | |||
273 | /* Linear resampling that introduces a one sample delay, because of our | 293 | /* Linear resampling that introduces a one sample delay, because of our |
274 | * inability to look into the future at the end of a frame. | 294 | * inability to look into the future at the end of a frame. |
275 | */ | 295 | */ |
276 | 296 | ||
277 | static long downsample(long *dst, long *src, int count, | 297 | /* TODO: we really should have a separate set of resample functions for both |
298 | mono and stereo to avoid all this internal branching and looping. */ | ||
299 | static long downsample(long **dst, long **src, int count, | ||
278 | struct resample_data *r) | 300 | struct resample_data *r) |
279 | { | 301 | { |
280 | long phase = r->phase; | 302 | long phase = r->phase; |
281 | long delta = r->delta; | 303 | long delta = r->delta; |
282 | long last_sample = r->last_sample; | 304 | long last_sample; |
305 | long *d[2] = { dst[0], dst[1] }; | ||
283 | int pos = phase >> 16; | 306 | int pos = phase >> 16; |
284 | int i = 1; | 307 | int i = 1, j; |
285 | 308 | int num_channels = src[0] == src[1] ? 1 : 2; | |
286 | /* Do we need last sample of previous frame for interpolation? */ | 309 | |
287 | if (pos > 0) | 310 | for (j = 0; j < num_channels; j++) { |
288 | { | 311 | last_sample = r->last_sample[j]; |
289 | last_sample = src[pos - 1]; | 312 | /* Do we need last sample of previous frame for interpolation? */ |
313 | if (pos > 0) | ||
314 | { | ||
315 | last_sample = src[j][pos - 1]; | ||
316 | } | ||
317 | *d[j]++ = last_sample + FRACMUL((phase & 0xffff) << 15, | ||
318 | src[j][pos] - last_sample); | ||
290 | } | 319 | } |
291 | |||
292 | *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15, | ||
293 | src[pos] - last_sample); | ||
294 | phase += delta; | 320 | phase += delta; |
295 | 321 | ||
296 | while ((pos = phase >> 16) < count) | 322 | while ((pos = phase >> 16) < count) |
297 | { | 323 | { |
298 | *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15, | 324 | for (j = 0; j < num_channels; j++) |
299 | src[pos] - src[pos - 1]); | 325 | *d[j]++ = src[j][pos - 1] + FRACMUL((phase & 0xffff) << 15, |
300 | phase += delta; | 326 | src[j][pos] - src[j][pos - 1]); |
301 | i++; | 327 | phase += delta; |
328 | i++; | ||
302 | } | 329 | } |
303 | 330 | ||
304 | /* Wrap phase accumulator back to start of next frame. */ | 331 | /* Wrap phase accumulator back to start of next frame. */ |
305 | r->phase = phase - (count << 16); | 332 | r->phase = phase - (count << 16); |
306 | r->delta = delta; | 333 | r->delta = delta; |
307 | r->last_sample = src[count - 1]; | 334 | r->last_sample[0] = src[0][count - 1]; |
335 | r->last_sample[1] = src[1][count - 1]; | ||
308 | return i; | 336 | return i; |
309 | } | 337 | } |
310 | 338 | ||
311 | static long upsample(long *dst, long *src, int count, struct resample_data *r) | 339 | static long upsample(long **dst, long **src, int count, struct resample_data *r) |
312 | { | 340 | { |
313 | long phase = r->phase; | 341 | long phase = r->phase; |
314 | long delta = r->delta; | 342 | long delta = r->delta; |
315 | long last_sample = r->last_sample; | 343 | long *d[2] = { dst[0], dst[1] }; |
316 | int i = 0; | 344 | int i = 0, j; |
317 | int pos; | 345 | int pos; |
318 | 346 | int num_channels = src[0] == src[1] ? 1 : 2; | |
347 | |||
319 | while ((pos = phase >> 16) == 0) | 348 | while ((pos = phase >> 16) == 0) |
320 | { | 349 | { |
321 | *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15, | 350 | for (j = 0; j < num_channels; j++) |
322 | src[pos] - last_sample); | 351 | *d[j]++ = r->last_sample[j] + FRACMUL((phase & 0xffff) << 15, |
352 | src[j][pos] - r->last_sample[j]); | ||
323 | phase += delta; | 353 | phase += delta; |
324 | i++; | 354 | i++; |
325 | } | 355 | } |
326 | 356 | ||
327 | while ((pos = phase >> 16) < count) | 357 | while ((pos = phase >> 16) < count) |
328 | { | 358 | { |
329 | *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15, | 359 | for (j = 0; j < num_channels; j++) |
330 | src[pos] - src[pos - 1]); | 360 | *d[j]++ = src[j][pos - 1] + FRACMUL((phase & 0xffff) << 15, |
361 | src[j][pos] - src[j][pos - 1]); | ||
331 | phase += delta; | 362 | phase += delta; |
332 | i++; | 363 | i++; |
333 | } | 364 | } |
@@ -335,7 +366,8 @@ static long upsample(long *dst, long *src, int count, struct resample_data *r) | |||
335 | /* Wrap phase accumulator back to start of next frame. */ | 366 | /* Wrap phase accumulator back to start of next frame. */ |
336 | r->phase = phase - (count << 16); | 367 | r->phase = phase - (count << 16); |
337 | r->delta = delta; | 368 | r->delta = delta; |
338 | r->last_sample = src[count - 1]; | 369 | r->last_sample[0] = src[0][count - 1]; |
370 | r->last_sample[1] = src[1][count - 1]; | ||
339 | return i; | 371 | return i; |
340 | } | 372 | } |
341 | 373 | ||
@@ -349,36 +381,21 @@ static inline int resample(long* src[], int count) | |||
349 | 381 | ||
350 | if (dsp->frequency != NATIVE_FREQUENCY) | 382 | if (dsp->frequency != NATIVE_FREQUENCY) |
351 | { | 383 | { |
352 | long* d0 = &resample_buf[0]; | 384 | long* dst[2] = {&resample_buf[0], &resample_buf[RESAMPLE_BUF_SIZE / 2]}; |
353 | /* Only process the second channel if needed. */ | ||
354 | long* d1 = (src[0] == src[1]) ? d0 | ||
355 | : &resample_buf[RESAMPLE_BUF_SIZE / 2]; | ||
356 | 385 | ||
357 | if (dsp->frequency < NATIVE_FREQUENCY) | 386 | if (dsp->frequency < NATIVE_FREQUENCY) |
358 | { | 387 | { |
359 | new_count = upsample(d0, src[0], count, | 388 | new_count = upsample(dst, src, count, |
360 | &resample_data[current_codec][0]); | 389 | &resample_data[current_codec]); |
361 | |||
362 | if (d0 != d1) | ||
363 | { | ||
364 | upsample(d1, src[1], count, | ||
365 | &resample_data[current_codec][1]); | ||
366 | } | ||
367 | } | 390 | } |
368 | else | 391 | else |
369 | { | 392 | { |
370 | new_count = downsample(d0, src[0], count, | 393 | new_count = downsample(dst, src, count, |
371 | &resample_data[current_codec][0]); | 394 | &resample_data[current_codec]); |
372 | |||
373 | if (d0 != d1) | ||
374 | { | ||
375 | downsample(d1, src[1], count, | ||
376 | &resample_data[current_codec][1]); | ||
377 | } | ||
378 | } | 395 | } |
379 | 396 | ||
380 | src[0] = d0; | 397 | src[0] = dst[0]; |
381 | src[1] = d1; | 398 | src[1] = dst[1]; |
382 | } | 399 | } |
383 | else | 400 | else |
384 | { | 401 | { |
@@ -767,7 +784,7 @@ long dsp_input_size(long size) | |||
767 | * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and | 784 | * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and |
768 | * round towards zero to avoid buffer overflows. */ | 785 | * round towards zero to avoid buffer overflows. */ |
769 | size = ((unsigned long)size * | 786 | size = ((unsigned long)size * |
770 | resample_data[current_codec][0].delta) >> 16; | 787 | resample_data[current_codec].delta) >> 16; |
771 | } | 788 | } |
772 | 789 | ||
773 | /* Convert back to bytes. */ | 790 | /* Convert back to bytes. */ |
@@ -793,14 +810,20 @@ bool dsp_configure(int setting, void *value) | |||
793 | switch (setting) | 810 | switch (setting) |
794 | { | 811 | { |
795 | case DSP_SET_FREQUENCY: | 812 | case DSP_SET_FREQUENCY: |
796 | memset(&resample_data[current_codec][0], 0, | 813 | memset(&resample_data[current_codec], 0, |
797 | sizeof(struct resample_data) * 2); | 814 | sizeof(struct resample_data)); |
798 | /* Fall through!!! */ | 815 | /* Fall through!!! */ |
799 | case DSP_SWITCH_FREQUENCY: | 816 | case DSP_SWITCH_FREQUENCY: |
800 | dsp->frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value; | 817 | dsp->codec_frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value; |
801 | resample_data[current_codec][0].delta = | 818 | /* Account for playback speed adjustment when settingg dsp->frequency |
802 | resample_data[current_codec][1].delta = | 819 | if we're called from the main audio thread. Voice UI thread should |
803 | (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY; | 820 | not need this feature. |
821 | */ | ||
822 | if (current_codec == CODEC_IDX_AUDIO) | ||
823 | dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; | ||
824 | else | ||
825 | dsp->frequency = dsp->codec_frequency; | ||
826 | resampler_set_delta(dsp->frequency); | ||
804 | break; | 827 | break; |
805 | 828 | ||
806 | case DSP_SET_CLIP_MIN: | 829 | case DSP_SET_CLIP_MIN: |
@@ -844,7 +867,7 @@ bool dsp_configure(int setting, void *value) | |||
844 | dsp->album_gain = 0; | 867 | dsp->album_gain = 0; |
845 | dsp->track_peak = 0; | 868 | dsp->track_peak = 0; |
846 | dsp->album_peak = 0; | 869 | dsp->album_peak = 0; |
847 | dsp->frequency = NATIVE_FREQUENCY; | 870 | dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; |
848 | dsp->sample_depth = NATIVE_DEPTH; | 871 | dsp->sample_depth = NATIVE_DEPTH; |
849 | dsp->frac_bits = WORD_FRACBITS; | 872 | dsp->frac_bits = WORD_FRACBITS; |
850 | dsp->new_gain = true; | 873 | dsp->new_gain = true; |