diff options
author | Steve Bavin <pondlife@pondlife.me> | 2009-06-12 07:20:50 +0000 |
---|---|---|
committer | Steve Bavin <pondlife@pondlife.me> | 2009-06-12 07:20:50 +0000 |
commit | fb2380790edbdb2176a21fe28739a41fb978ce6e (patch) | |
tree | 29ad077356a1463394ceb22f81a057f300ee57d7 | |
parent | 9e3255fdb043d8651bfdbd8be06986d12a7d66eb (diff) | |
download | rockbox-fb2380790edbdb2176a21fe28739a41fb978ce6e.tar.gz rockbox-fb2380790edbdb2176a21fe28739a41fb978ce6e.zip |
FS#8894 - Add time stretching feature to all SWCODEC targets - the current algorithm is best for spoken word.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21258 a1c6a512-1295-4272-9138-f99709370657
40 files changed, 1027 insertions, 261 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 0fe001b242..527b0b20a9 100644 --- a/apps/SOURCES +++ b/apps/SOURCES | |||
@@ -126,6 +126,7 @@ pcmbuf.c | |||
126 | playback.c | 126 | playback.c |
127 | codecs.c | 127 | codecs.c |
128 | dsp.c | 128 | dsp.c |
129 | tdspeed.c | ||
129 | #ifdef HAVE_RECORDING | 130 | #ifdef HAVE_RECORDING |
130 | enc_config.c | 131 | enc_config.c |
131 | #ifndef SIMULATOR | 132 | #ifndef SIMULATOR |
diff --git a/apps/action.h b/apps/action.h index 61c214c609..3e53b6d7a8 100644 --- a/apps/action.h +++ b/apps/action.h | |||
@@ -211,6 +211,8 @@ enum { | |||
211 | ACTION_PS_TOGGLE_MODE, | 211 | ACTION_PS_TOGGLE_MODE, |
212 | ACTION_PS_RESET, | 212 | ACTION_PS_RESET, |
213 | ACTION_PS_EXIT, /* _STD_* isnt going to work here */ | 213 | ACTION_PS_EXIT, /* _STD_* isnt going to work here */ |
214 | ACTION_PS_SLOWER, | ||
215 | ACTION_PS_FASTER, | ||
214 | 216 | ||
215 | /* yesno screen */ | 217 | /* yesno screen */ |
216 | ACTION_YESNO_ACCEPT, | 218 | ACTION_YESNO_ACCEPT, |
diff --git a/apps/dsp.c b/apps/dsp.c index cbae49ab69..b32b641693 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -32,22 +32,19 @@ | |||
32 | #include "replaygain.h" | 32 | #include "replaygain.h" |
33 | #include "misc.h" | 33 | #include "misc.h" |
34 | #include "debug.h" | 34 | #include "debug.h" |
35 | #include "tdspeed.h" | ||
36 | #include "buffer.h" | ||
35 | 37 | ||
36 | /* 16-bit samples are scaled based on these constants. The shift should be | 38 | /* 16-bit samples are scaled based on these constants. The shift should be |
37 | * no more than 15. | 39 | * no more than 15. |
38 | */ | 40 | */ |
39 | #define WORD_SHIFT 12 | 41 | #define WORD_SHIFT 12 |
40 | #define WORD_FRACBITS 27 | 42 | #define WORD_FRACBITS 27 |
41 | 43 | ||
42 | #define NATIVE_DEPTH 16 | 44 | #define NATIVE_DEPTH 16 |
43 | /* If the buffer sizes change, check the assembly code! */ | 45 | /* If the small buffer size changes, check the assembly code! */ |
44 | #define SAMPLE_BUF_COUNT 256 | 46 | #define SMALL_SAMPLE_BUF_COUNT 256 |
45 | #define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ | 47 | #define DEFAULT_GAIN 0x01000000 |
46 | #define DEFAULT_GAIN 0x01000000 | ||
47 | #define SAMPLE_BUF_LEFT_CHANNEL 0 | ||
48 | #define SAMPLE_BUF_RIGHT_CHANNEL (SAMPLE_BUF_COUNT/2) | ||
49 | #define RESAMPLE_BUF_LEFT_CHANNEL 0 | ||
50 | #define RESAMPLE_BUF_RIGHT_CHANNEL (RESAMPLE_BUF_COUNT/2) | ||
51 | 48 | ||
52 | /* enums to index conversion properly with stereo mode and other settings */ | 49 | /* enums to index conversion properly with stereo mode and other settings */ |
53 | enum | 50 | enum |
@@ -101,7 +98,7 @@ struct dsp_data | |||
101 | struct resample_data resample_data; /* 08h */ | 98 | struct resample_data resample_data; /* 08h */ |
102 | int32_t clip_min; /* 18h */ | 99 | int32_t clip_min; /* 18h */ |
103 | int32_t clip_max; /* 1ch */ | 100 | int32_t clip_max; /* 1ch */ |
104 | int32_t gain; /* 20h - Note that this is in S8.23 format. */ | 101 | int32_t gain; /* 20h - Note that this is in S8.23 format. */ |
105 | /* 24h */ | 102 | /* 24h */ |
106 | }; | 103 | }; |
107 | 104 | ||
@@ -140,11 +137,12 @@ struct eq_state | |||
140 | 137 | ||
141 | /* Typedefs keep things much neater in this case */ | 138 | /* Typedefs keep things much neater in this case */ |
142 | typedef void (*sample_input_fn_type)(int count, const char *src[], | 139 | typedef void (*sample_input_fn_type)(int count, const char *src[], |
143 | int32_t *dst[]); | 140 | int32_t *dst[]); |
144 | typedef int (*resample_fn_type)(int count, struct dsp_data *data, | 141 | typedef int (*resample_fn_type)(int count, struct dsp_data *data, |
145 | int32_t *src[], int32_t *dst[]); | 142 | const int32_t *src[], int32_t *dst[]); |
146 | typedef void (*sample_output_fn_type)(int count, struct dsp_data *data, | 143 | typedef void (*sample_output_fn_type)(int count, struct dsp_data *data, |
147 | int32_t *src[], int16_t *dst); | 144 | const int32_t *src[], int16_t *dst); |
145 | |||
148 | /* Single-DSP channel processing in place */ | 146 | /* Single-DSP channel processing in place */ |
149 | typedef void (*channels_process_fn_type)(int count, int32_t *buf[]); | 147 | typedef void (*channels_process_fn_type)(int count, int32_t *buf[]); |
150 | /* DSP local channel processing in place */ | 148 | /* DSP local channel processing in place */ |
@@ -163,6 +161,9 @@ struct dsp_config | |||
163 | int sample_depth; | 161 | int sample_depth; |
164 | int sample_bytes; | 162 | int sample_bytes; |
165 | int stereo_mode; | 163 | int stereo_mode; |
164 | bool tdspeed_enabled; /* User has enabled timestretch */ | ||
165 | int tdspeed_percent; /* Speed % */ | ||
166 | bool tdspeed_active; /* Timestretch is in use */ | ||
166 | int frac_bits; | 167 | int frac_bits; |
167 | #ifdef HAVE_SW_TONE_CONTROLS | 168 | #ifdef HAVE_SW_TONE_CONTROLS |
168 | /* Filter struct for software bass/treble controls */ | 169 | /* Filter struct for software bass/treble controls */ |
@@ -218,16 +219,31 @@ static long album_peak; | |||
218 | static long replaygain; | 219 | static long replaygain; |
219 | static bool crossfeed_enabled; | 220 | static bool crossfeed_enabled; |
220 | 221 | ||
221 | #define audio_dsp (dsp_conf[CODEC_IDX_AUDIO]) | 222 | #define AUDIO_DSP (dsp_conf[CODEC_IDX_AUDIO]) |
222 | #define voice_dsp (dsp_conf[CODEC_IDX_VOICE]) | 223 | #define VOICE_DSP (dsp_conf[CODEC_IDX_VOICE]) |
223 | 224 | ||
224 | /* The internal format is 32-bit samples, non-interleaved, stereo. This | 225 | /* The internal format is 32-bit samples, non-interleaved, stereo. This |
225 | * format is similar to the raw output from several codecs, so the amount | 226 | * format is similar to the raw output from several codecs, so the amount |
226 | * of copying needed is minimized for that case. | 227 | * of copying needed is minimized for that case. |
227 | */ | 228 | */ |
228 | 229 | ||
229 | int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; | 230 | #define RESAMPLE_RATIO 4 /* Enough for 11,025 Hz -> 44,100 Hz */ |
230 | static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; | 231 | |
232 | static int32_t small_sample_buf[SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR; | ||
233 | static int32_t small_resample_buf[SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO] IBSS_ATTR; | ||
234 | |||
235 | static int32_t *big_sample_buf = NULL; | ||
236 | static int32_t *big_resample_buf = NULL; | ||
237 | static int big_sample_buf_count = -1; /* -1=unknown, 0=not available */ | ||
238 | |||
239 | static int sample_buf_count; | ||
240 | static int32_t *sample_buf; | ||
241 | static int32_t *resample_buf; | ||
242 | |||
243 | #define SAMPLE_BUF_LEFT_CHANNEL 0 | ||
244 | #define SAMPLE_BUF_RIGHT_CHANNEL (sample_buf_count/2) | ||
245 | #define RESAMPLE_BUF_LEFT_CHANNEL 0 | ||
246 | #define RESAMPLE_BUF_RIGHT_CHANNEL (sample_buf_count/2 * RESAMPLE_RATIO) | ||
231 | 247 | ||
232 | #if 0 | 248 | #if 0 |
233 | /* Clip sample to arbitrary limits where range > 0 and min + range = max */ | 249 | /* Clip sample to arbitrary limits where range > 0 and min + range = max */ |
@@ -260,8 +276,66 @@ int sound_get_pitch(void) | |||
260 | void sound_set_pitch(int permille) | 276 | void sound_set_pitch(int permille) |
261 | { | 277 | { |
262 | pitch_ratio = permille; | 278 | pitch_ratio = permille; |
263 | dsp_configure(&audio_dsp, DSP_SWITCH_FREQUENCY, | 279 | dsp_configure(&AUDIO_DSP, DSP_SWITCH_FREQUENCY, |
264 | audio_dsp.codec_frequency); | 280 | AUDIO_DSP.codec_frequency); |
281 | } | ||
282 | |||
283 | void tdspeed_setup(struct dsp_config *dspc) | ||
284 | { | ||
285 | if (dspc == &AUDIO_DSP) | ||
286 | { | ||
287 | dspc->tdspeed_active = false; | ||
288 | if (!dspc->tdspeed_enabled) | ||
289 | return; | ||
290 | if (dspc->tdspeed_percent == 0) | ||
291 | dspc->tdspeed_percent = 100; | ||
292 | if (!tdspeed_init( | ||
293 | dspc->codec_frequency == 0 ? NATIVE_FREQUENCY : dspc->codec_frequency, | ||
294 | dspc->stereo_mode != STEREO_MONO, | ||
295 | dspc->tdspeed_percent)) | ||
296 | return; | ||
297 | if (dspc->tdspeed_percent == 100 || big_sample_buf_count <= 0) | ||
298 | return; | ||
299 | dspc->tdspeed_active = true; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | void dsp_timestretch_enable(bool enable) | ||
304 | { | ||
305 | if (enable) | ||
306 | { | ||
307 | /* Set up timestretch buffers on first enable */ | ||
308 | if (big_sample_buf_count < 0) | ||
309 | { | ||
310 | big_sample_buf_count = SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO; | ||
311 | big_sample_buf = small_resample_buf; | ||
312 | big_resample_buf = (int32_t *) buffer_alloc(big_sample_buf_count * RESAMPLE_RATIO * sizeof(int32_t)); | ||
313 | } | ||
314 | } | ||
315 | else | ||
316 | { | ||
317 | /* If not enabled at startup, buffers will never be available */ | ||
318 | if (big_sample_buf_count < 0) | ||
319 | big_sample_buf_count = 0; | ||
320 | } | ||
321 | AUDIO_DSP.tdspeed_enabled = enable; | ||
322 | tdspeed_setup(&AUDIO_DSP); | ||
323 | } | ||
324 | |||
325 | void dsp_set_timestretch(int percent) | ||
326 | { | ||
327 | AUDIO_DSP.tdspeed_percent = percent; | ||
328 | tdspeed_setup(&AUDIO_DSP); | ||
329 | } | ||
330 | |||
331 | int dsp_get_timestretch() | ||
332 | { | ||
333 | return AUDIO_DSP.tdspeed_percent; | ||
334 | } | ||
335 | |||
336 | bool dsp_timestretch_enabled() | ||
337 | { | ||
338 | return (AUDIO_DSP.tdspeed_enabled && big_sample_buf_count > 0); | ||
265 | } | 339 | } |
266 | 340 | ||
267 | /* Convert count samples to the internal format, if needed. Updates src | 341 | /* Convert count samples to the internal format, if needed. Updates src |
@@ -403,10 +477,11 @@ static void sample_input_new_format(struct dsp_config *dsp) | |||
403 | dsp->input_samples = sample_input_functions[convert]; | 477 | dsp->input_samples = sample_input_functions[convert]; |
404 | } | 478 | } |
405 | 479 | ||
480 | |||
406 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO | 481 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO |
407 | /* write mono internal format to output format */ | 482 | /* write mono internal format to output format */ |
408 | static void sample_output_mono(int count, struct dsp_data *data, | 483 | static void sample_output_mono(int count, struct dsp_data *data, |
409 | int32_t *src[], int16_t *dst) | 484 | const int32_t *src[], int16_t *dst) |
410 | { | 485 | { |
411 | const int32_t *s0 = src[0]; | 486 | const int32_t *s0 = src[0]; |
412 | const int scale = data->output_scale; | 487 | const int scale = data->output_scale; |
@@ -425,7 +500,7 @@ static void sample_output_mono(int count, struct dsp_data *data, | |||
425 | /* write stereo internal format to output format */ | 500 | /* write stereo internal format to output format */ |
426 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO | 501 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO |
427 | static void sample_output_stereo(int count, struct dsp_data *data, | 502 | static void sample_output_stereo(int count, struct dsp_data *data, |
428 | int32_t *src[], int16_t *dst) | 503 | const int32_t *src[], int16_t *dst) |
429 | { | 504 | { |
430 | const int32_t *s0 = src[0]; | 505 | const int32_t *s0 = src[0]; |
431 | const int32_t *s1 = src[1]; | 506 | const int32_t *s1 = src[1]; |
@@ -448,7 +523,7 @@ static void sample_output_stereo(int count, struct dsp_data *data, | |||
448 | * This function handles mono and stereo outputs. | 523 | * This function handles mono and stereo outputs. |
449 | */ | 524 | */ |
450 | static void sample_output_dithered(int count, struct dsp_data *data, | 525 | static void sample_output_dithered(int count, struct dsp_data *data, |
451 | int32_t *src[], int16_t *dst) | 526 | const int32_t *src[], int16_t *dst) |
452 | { | 527 | { |
453 | const int32_t mask = dither_mask; | 528 | const int32_t mask = dither_mask; |
454 | const int32_t bias = dither_bias; | 529 | const int32_t bias = dither_bias; |
@@ -462,7 +537,7 @@ static void sample_output_dithered(int count, struct dsp_data *data, | |||
462 | for (ch = 0; ch < data->num_channels; ch++) | 537 | for (ch = 0; ch < data->num_channels; ch++) |
463 | { | 538 | { |
464 | struct dither_data * const dither = &dither_data[ch]; | 539 | struct dither_data * const dither = &dither_data[ch]; |
465 | int32_t *s = src[ch]; | 540 | const int32_t *s = src[ch]; |
466 | int i; | 541 | int i; |
467 | 542 | ||
468 | for (i = 0, d = &dst[ch]; i < count; i++, s++, d += 2) | 543 | for (i = 0, d = &dst[ch]; i < count; i++, s++, d += 2) |
@@ -540,7 +615,7 @@ static void sample_output_new_format(struct dsp_config *dsp) | |||
540 | 615 | ||
541 | int out = dsp->data.num_channels - 1; | 616 | int out = dsp->data.num_channels - 1; |
542 | 617 | ||
543 | if (dsp == &audio_dsp && dither_enabled) | 618 | if (dsp == &AUDIO_DSP && dither_enabled) |
544 | out += 2; | 619 | out += 2; |
545 | 620 | ||
546 | dsp->output_samples = sample_output_functions[out]; | 621 | dsp->output_samples = sample_output_functions[out]; |
@@ -552,7 +627,7 @@ static void sample_output_new_format(struct dsp_config *dsp) | |||
552 | */ | 627 | */ |
553 | #ifndef DSP_HAVE_ASM_RESAMPLING | 628 | #ifndef DSP_HAVE_ASM_RESAMPLING |
554 | static int dsp_downsample(int count, struct dsp_data *data, | 629 | static int dsp_downsample(int count, struct dsp_data *data, |
555 | int32_t *src[], int32_t *dst[]) | 630 | const int32_t *src[], int32_t *dst[]) |
556 | { | 631 | { |
557 | int ch = data->num_channels - 1; | 632 | int ch = data->num_channels - 1; |
558 | uint32_t delta = data->resample_data.delta; | 633 | uint32_t delta = data->resample_data.delta; |
@@ -565,9 +640,9 @@ static int dsp_downsample(int count, struct dsp_data *data, | |||
565 | /* Just initialize things and not worry too much about the relatively | 640 | /* Just initialize things and not worry too much about the relatively |
566 | * uncommon case of not being able to spit out a sample for the frame. | 641 | * uncommon case of not being able to spit out a sample for the frame. |
567 | */ | 642 | */ |
568 | int32_t *s = src[ch]; | 643 | const int32_t *s = src[ch]; |
569 | int32_t last = data->resample_data.last_sample[ch]; | 644 | int32_t last = data->resample_data.last_sample[ch]; |
570 | 645 | ||
571 | data->resample_data.last_sample[ch] = s[count - 1]; | 646 | data->resample_data.last_sample[ch] = s[count - 1]; |
572 | d = dst[ch]; | 647 | d = dst[ch]; |
573 | phase = data->resample_data.phase; | 648 | phase = data->resample_data.phase; |
@@ -593,7 +668,7 @@ static int dsp_downsample(int count, struct dsp_data *data, | |||
593 | } | 668 | } |
594 | 669 | ||
595 | static int dsp_upsample(int count, struct dsp_data *data, | 670 | static int dsp_upsample(int count, struct dsp_data *data, |
596 | int32_t *src[], int32_t *dst[]) | 671 | const int32_t *src[], int32_t *dst[]) |
597 | { | 672 | { |
598 | int ch = data->num_channels - 1; | 673 | int ch = data->num_channels - 1; |
599 | uint32_t delta = data->resample_data.delta; | 674 | uint32_t delta = data->resample_data.delta; |
@@ -603,11 +678,10 @@ static int dsp_upsample(int count, struct dsp_data *data, | |||
603 | /* Rolled channel loop actually showed slightly faster. */ | 678 | /* Rolled channel loop actually showed slightly faster. */ |
604 | do | 679 | do |
605 | { | 680 | { |
606 | /* Should always be able to output a sample for a ratio up to | 681 | /* Should always be able to output a sample for a ratio up to RESAMPLE_RATIO */ |
607 | RESAMPLE_BUF_COUNT / SAMPLE_BUF_COUNT. */ | 682 | const int32_t *s = src[ch]; |
608 | int32_t *s = src[ch]; | ||
609 | int32_t last = data->resample_data.last_sample[ch]; | 683 | int32_t last = data->resample_data.last_sample[ch]; |
610 | 684 | ||
611 | data->resample_data.last_sample[ch] = s[count - 1]; | 685 | data->resample_data.last_sample[ch] = s[count - 1]; |
612 | d = dst[ch]; | 686 | d = dst[ch]; |
613 | phase = data->resample_data.phase; | 687 | phase = data->resample_data.phase; |
@@ -638,7 +712,7 @@ static int dsp_upsample(int count, struct dsp_data *data, | |||
638 | 712 | ||
639 | static void resampler_new_delta(struct dsp_config *dsp) | 713 | static void resampler_new_delta(struct dsp_config *dsp) |
640 | { | 714 | { |
641 | dsp->data.resample_data.delta = (unsigned long) | 715 | dsp->data.resample_data.delta = (unsigned long) |
642 | dsp->frequency * 65536LL / NATIVE_FREQUENCY; | 716 | dsp->frequency * 65536LL / NATIVE_FREQUENCY; |
643 | 717 | ||
644 | if (dsp->frequency == NATIVE_FREQUENCY) | 718 | if (dsp->frequency == NATIVE_FREQUENCY) |
@@ -669,7 +743,7 @@ static inline int resample(struct dsp_config *dsp, int count, int32_t *src[]) | |||
669 | &resample_buf[RESAMPLE_BUF_RIGHT_CHANNEL], | 743 | &resample_buf[RESAMPLE_BUF_RIGHT_CHANNEL], |
670 | }; | 744 | }; |
671 | 745 | ||
672 | count = dsp->resample(count, &dsp->data, src, dst); | 746 | count = dsp->resample(count, &dsp->data, (const int32_t **)src, dst); |
673 | 747 | ||
674 | src[0] = dst[0]; | 748 | src[0] = dst[0]; |
675 | src[1] = dst[dsp->data.num_channels - 1]; | 749 | src[1] = dst[dsp->data.num_channels - 1]; |
@@ -686,7 +760,7 @@ static void dither_init(struct dsp_config *dsp) | |||
686 | 760 | ||
687 | void dsp_dither_enable(bool enable) | 761 | void dsp_dither_enable(bool enable) |
688 | { | 762 | { |
689 | struct dsp_config *dsp = &audio_dsp; | 763 | struct dsp_config *dsp = &AUDIO_DSP; |
690 | dither_enabled = enable; | 764 | dither_enabled = enable; |
691 | sample_output_new_format(dsp); | 765 | sample_output_new_format(dsp); |
692 | } | 766 | } |
@@ -705,7 +779,7 @@ static void apply_crossfeed(int count, int32_t *buf[]) | |||
705 | int32_t *coefs = &crossfeed_data.coefs[0]; | 779 | int32_t *coefs = &crossfeed_data.coefs[0]; |
706 | int32_t gain = crossfeed_data.gain; | 780 | int32_t gain = crossfeed_data.gain; |
707 | int32_t *di = crossfeed_data.index; | 781 | int32_t *di = crossfeed_data.index; |
708 | 782 | ||
709 | int32_t acc; | 783 | int32_t acc; |
710 | int32_t left, right; | 784 | int32_t left, right; |
711 | int i; | 785 | int i; |
@@ -734,7 +808,7 @@ static void apply_crossfeed(int count, int32_t *buf[]) | |||
734 | /* Now add the attenuated direct sound and write to outputs */ | 808 | /* Now add the attenuated direct sound and write to outputs */ |
735 | buf[0][i] = FRACMUL(left, gain) + hist_r[1]; | 809 | buf[0][i] = FRACMUL(left, gain) + hist_r[1]; |
736 | buf[1][i] = FRACMUL(right, gain) + hist_l[1]; | 810 | buf[1][i] = FRACMUL(right, gain) + hist_l[1]; |
737 | 811 | ||
738 | /* Wrap delay line index if bigger than delay line size */ | 812 | /* Wrap delay line index if bigger than delay line size */ |
739 | if (di >= delay + 13*2) | 813 | if (di >= delay + 13*2) |
740 | di = delay; | 814 | di = delay; |
@@ -754,7 +828,7 @@ static void apply_crossfeed(int count, int32_t *buf[]) | |||
754 | void dsp_set_crossfeed(bool enable) | 828 | void dsp_set_crossfeed(bool enable) |
755 | { | 829 | { |
756 | crossfeed_enabled = enable; | 830 | crossfeed_enabled = enable; |
757 | audio_dsp.apply_crossfeed = (enable && audio_dsp.data.num_channels > 1) | 831 | AUDIO_DSP.apply_crossfeed = (enable && AUDIO_DSP.data.num_channels > 1) |
758 | ? apply_crossfeed : NULL; | 832 | ? apply_crossfeed : NULL; |
759 | } | 833 | } |
760 | 834 | ||
@@ -815,17 +889,17 @@ static void set_gain(struct dsp_config *dsp) | |||
815 | dsp->data.gain = DEFAULT_GAIN; | 889 | dsp->data.gain = DEFAULT_GAIN; |
816 | 890 | ||
817 | /* Replay gain not relevant to voice */ | 891 | /* Replay gain not relevant to voice */ |
818 | if (dsp == &audio_dsp && replaygain) | 892 | if (dsp == &AUDIO_DSP && replaygain) |
819 | { | 893 | { |
820 | dsp->data.gain = replaygain; | 894 | dsp->data.gain = replaygain; |
821 | } | 895 | } |
822 | 896 | ||
823 | if (dsp->eq_process && eq_precut) | 897 | if (dsp->eq_process && eq_precut) |
824 | { | 898 | { |
825 | dsp->data.gain = | 899 | dsp->data.gain = |
826 | (long) (((int64_t) dsp->data.gain * eq_precut) >> 24); | 900 | (long) (((int64_t) dsp->data.gain * eq_precut) >> 24); |
827 | } | 901 | } |
828 | 902 | ||
829 | if (dsp->data.gain == DEFAULT_GAIN) | 903 | if (dsp->data.gain == DEFAULT_GAIN) |
830 | { | 904 | { |
831 | dsp->data.gain = 0; | 905 | dsp->data.gain = 0; |
@@ -846,7 +920,7 @@ static void set_gain(struct dsp_config *dsp) | |||
846 | void dsp_set_eq_precut(int precut) | 920 | void dsp_set_eq_precut(int precut) |
847 | { | 921 | { |
848 | eq_precut = get_replaygain_int(precut * -10); | 922 | eq_precut = get_replaygain_int(precut * -10); |
849 | set_gain(&audio_dsp); | 923 | set_gain(&AUDIO_DSP); |
850 | } | 924 | } |
851 | 925 | ||
852 | /** | 926 | /** |
@@ -867,10 +941,10 @@ void dsp_set_eq_coefs(int band) | |||
867 | cutoff = 0xffffffff / NATIVE_FREQUENCY * (*setting++); | 941 | cutoff = 0xffffffff / NATIVE_FREQUENCY * (*setting++); |
868 | q = *setting++; | 942 | q = *setting++; |
869 | gain = *setting++; | 943 | gain = *setting++; |
870 | 944 | ||
871 | if (q == 0) | 945 | if (q == 0) |
872 | q = 1; | 946 | q = 1; |
873 | 947 | ||
874 | /* NOTE: The coef functions assume the EMAC unit is in fractional mode, | 948 | /* NOTE: The coef functions assume the EMAC unit is in fractional mode, |
875 | which it should be, since we're executed from the main thread. */ | 949 | which it should be, since we're executed from the main thread. */ |
876 | 950 | ||
@@ -903,7 +977,7 @@ static void eq_process(int count, int32_t *buf[]) | |||
903 | EQ_PEAK_SHIFT, /* peaking */ | 977 | EQ_PEAK_SHIFT, /* peaking */ |
904 | EQ_SHELF_SHIFT, /* high shelf */ | 978 | EQ_SHELF_SHIFT, /* high shelf */ |
905 | }; | 979 | }; |
906 | unsigned int channels = audio_dsp.data.num_channels; | 980 | unsigned int channels = AUDIO_DSP.data.num_channels; |
907 | int i; | 981 | int i; |
908 | 982 | ||
909 | /* filter configuration currently is 1 low shelf filter, 3 band peaking | 983 | /* filter configuration currently is 1 low shelf filter, 3 band peaking |
@@ -925,14 +999,14 @@ static void eq_process(int count, int32_t *buf[]) | |||
925 | */ | 999 | */ |
926 | void dsp_set_eq(bool enable) | 1000 | void dsp_set_eq(bool enable) |
927 | { | 1001 | { |
928 | audio_dsp.eq_process = enable ? eq_process : NULL; | 1002 | AUDIO_DSP.eq_process = enable ? eq_process : NULL; |
929 | set_gain(&audio_dsp); | 1003 | set_gain(&AUDIO_DSP); |
930 | } | 1004 | } |
931 | 1005 | ||
932 | static void dsp_set_stereo_width(int value) | 1006 | static void dsp_set_stereo_width(int value) |
933 | { | 1007 | { |
934 | long width, straight, cross; | 1008 | long width, straight, cross; |
935 | 1009 | ||
936 | width = value * 0x7fffff / 100; | 1010 | width = value * 0x7fffff / 100; |
937 | 1011 | ||
938 | if (value <= 100) | 1012 | if (value <= 100) |
@@ -1039,14 +1113,14 @@ static void dsp_set_channel_config(int value) | |||
1039 | }; | 1113 | }; |
1040 | 1114 | ||
1041 | if ((unsigned)value >= ARRAYLEN(channels_process_functions) || | 1115 | if ((unsigned)value >= ARRAYLEN(channels_process_functions) || |
1042 | audio_dsp.stereo_mode == STEREO_MONO) | 1116 | AUDIO_DSP.stereo_mode == STEREO_MONO) |
1043 | { | 1117 | { |
1044 | value = SOUND_CHAN_STEREO; | 1118 | value = SOUND_CHAN_STEREO; |
1045 | } | 1119 | } |
1046 | 1120 | ||
1047 | /* This doesn't apply to voice */ | 1121 | /* This doesn't apply to voice */ |
1048 | channels_mode = value; | 1122 | channels_mode = value; |
1049 | audio_dsp.channels_process = channels_process_functions[value]; | 1123 | AUDIO_DSP.channels_process = channels_process_functions[value]; |
1050 | } | 1124 | } |
1051 | 1125 | ||
1052 | #if CONFIG_CODEC == SWCODEC | 1126 | #if CONFIG_CODEC == SWCODEC |
@@ -1057,10 +1131,10 @@ static void set_tone_controls(void) | |||
1057 | filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200, | 1131 | filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200, |
1058 | 0xffffffff/NATIVE_FREQUENCY*3500, | 1132 | 0xffffffff/NATIVE_FREQUENCY*3500, |
1059 | bass, treble, -prescale, | 1133 | bass, treble, -prescale, |
1060 | audio_dsp.tone_filter.coefs); | 1134 | AUDIO_DSP.tone_filter.coefs); |
1061 | /* Sync the voice dsp coefficients */ | 1135 | /* Sync the voice dsp coefficients */ |
1062 | memcpy(&voice_dsp.tone_filter.coefs, audio_dsp.tone_filter.coefs, | 1136 | memcpy(&VOICE_DSP.tone_filter.coefs, AUDIO_DSP.tone_filter.coefs, |
1063 | sizeof (voice_dsp.tone_filter.coefs)); | 1137 | sizeof (VOICE_DSP.tone_filter.coefs)); |
1064 | } | 1138 | } |
1065 | #endif | 1139 | #endif |
1066 | 1140 | ||
@@ -1069,7 +1143,8 @@ static void set_tone_controls(void) | |||
1069 | */ | 1143 | */ |
1070 | int dsp_callback(int msg, intptr_t param) | 1144 | int dsp_callback(int msg, intptr_t param) |
1071 | { | 1145 | { |
1072 | switch (msg) { | 1146 | switch (msg) |
1147 | { | ||
1073 | #ifdef HAVE_SW_TONE_CONTROLS | 1148 | #ifdef HAVE_SW_TONE_CONTROLS |
1074 | case DSP_CALLBACK_SET_PRESCALE: | 1149 | case DSP_CALLBACK_SET_PRESCALE: |
1075 | prescale = param; | 1150 | prescale = param; |
@@ -1112,7 +1187,6 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1112 | static long last_yield; | 1187 | static long last_yield; |
1113 | long tick; | 1188 | long tick; |
1114 | int written = 0; | 1189 | int written = 0; |
1115 | int samples; | ||
1116 | 1190 | ||
1117 | #if defined(CPU_COLDFIRE) | 1191 | #if defined(CPU_COLDFIRE) |
1118 | /* set emac unit for dsp processing, and save old macsr, we're running in | 1192 | /* set emac unit for dsp processing, and save old macsr, we're running in |
@@ -1132,43 +1206,58 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1132 | will be preloaded to be used for the call if not. */ | 1206 | will be preloaded to be used for the call if not. */ |
1133 | while (count > 0) | 1207 | while (count > 0) |
1134 | { | 1208 | { |
1135 | samples = MIN(SAMPLE_BUF_COUNT/2, count); | 1209 | int samples = MIN(sample_buf_count/2, count); |
1136 | count -= samples; | 1210 | count -= samples; |
1137 | 1211 | ||
1138 | dsp->input_samples(samples, src, tmp); | 1212 | dsp->input_samples(samples, src, tmp); |
1139 | 1213 | ||
1140 | if (dsp->apply_gain) | 1214 | if (dsp->tdspeed_active) |
1141 | dsp->apply_gain(samples, &dsp->data, tmp); | 1215 | samples = tdspeed_doit(tmp, samples); |
1142 | 1216 | ||
1143 | if (dsp->resample && (samples = resample(dsp, samples, tmp)) <= 0) | 1217 | int chunk_offset = 0; |
1144 | break; /* I'm pretty sure we're downsampling here */ | 1218 | while (samples > 0) |
1219 | { | ||
1220 | int32_t *t2[2]; | ||
1221 | t2[0] = tmp[0]+chunk_offset; | ||
1222 | t2[1] = tmp[1]+chunk_offset; | ||
1223 | |||
1224 | int chunk = MIN(sample_buf_count/2, samples); | ||
1225 | chunk_offset += chunk; | ||
1226 | samples -= chunk; | ||
1227 | |||
1228 | if (dsp->apply_gain) | ||
1229 | dsp->apply_gain(chunk, &dsp->data, t2); | ||
1230 | |||
1231 | if (dsp->resample && (chunk = resample(dsp, chunk, t2)) <= 0) | ||
1232 | break; /* I'm pretty sure we're downsampling here */ | ||
1145 | 1233 | ||
1146 | if (dsp->apply_crossfeed) | 1234 | if (dsp->apply_crossfeed) |
1147 | dsp->apply_crossfeed(samples, tmp); | 1235 | dsp->apply_crossfeed(chunk, t2); |
1148 | 1236 | ||
1149 | if (dsp->eq_process) | 1237 | if (dsp->eq_process) |
1150 | dsp->eq_process(samples, tmp); | 1238 | dsp->eq_process(chunk, t2); |
1151 | 1239 | ||
1152 | #ifdef HAVE_SW_TONE_CONTROLS | 1240 | #ifdef HAVE_SW_TONE_CONTROLS |
1153 | if ((bass | treble) != 0) | 1241 | if ((bass | treble) != 0) |
1154 | eq_filter(tmp, &dsp->tone_filter, samples, | 1242 | eq_filter(t2, &dsp->tone_filter, chunk, |
1155 | dsp->data.num_channels, FILTER_BISHELF_SHIFT); | 1243 | dsp->data.num_channels, FILTER_BISHELF_SHIFT); |
1156 | #endif | 1244 | #endif |
1157 | 1245 | ||
1158 | if (dsp->channels_process) | 1246 | if (dsp->channels_process) |
1159 | dsp->channels_process(samples, tmp); | 1247 | dsp->channels_process(chunk, t2); |
1160 | 1248 | ||
1161 | dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst); | 1249 | dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst); |
1162 | 1250 | ||
1163 | written += samples; | 1251 | written += chunk; |
1164 | dst += samples * sizeof (int16_t) * 2; | 1252 | dst += chunk * sizeof (int16_t) * 2; |
1165 | 1253 | ||
1166 | /* yield at least once each tick */ | 1254 | /* yield at least once each tick */ |
1167 | tick = current_tick; | 1255 | tick = current_tick; |
1168 | if (TIME_AFTER(tick, last_yield)) | 1256 | if (TIME_AFTER(tick, last_yield)) |
1169 | { | 1257 | { |
1170 | last_yield = tick; | 1258 | last_yield = tick; |
1171 | yield(); | 1259 | yield(); |
1260 | } | ||
1172 | } | 1261 | } |
1173 | } | 1262 | } |
1174 | 1263 | ||
@@ -1188,6 +1277,20 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) | |||
1188 | /* dsp_input_size MUST be called afterwards */ | 1277 | /* dsp_input_size MUST be called afterwards */ |
1189 | int dsp_output_count(struct dsp_config *dsp, int count) | 1278 | int dsp_output_count(struct dsp_config *dsp, int count) |
1190 | { | 1279 | { |
1280 | if(!dsp->tdspeed_active) | ||
1281 | { | ||
1282 | sample_buf = small_sample_buf; | ||
1283 | resample_buf = small_resample_buf; | ||
1284 | sample_buf_count = SMALL_SAMPLE_BUF_COUNT; | ||
1285 | } | ||
1286 | else | ||
1287 | { | ||
1288 | sample_buf = big_sample_buf; | ||
1289 | sample_buf_count = big_sample_buf_count; | ||
1290 | resample_buf = big_resample_buf; | ||
1291 | } | ||
1292 | if(dsp->tdspeed_active) | ||
1293 | count = tdspeed_est_output_size(); | ||
1191 | if (dsp->resample) | 1294 | if (dsp->resample) |
1192 | { | 1295 | { |
1193 | count = (int)(((unsigned long)count * NATIVE_FREQUENCY | 1296 | count = (int)(((unsigned long)count * NATIVE_FREQUENCY |
@@ -1195,12 +1298,12 @@ int dsp_output_count(struct dsp_config *dsp, int count) | |||
1195 | } | 1298 | } |
1196 | 1299 | ||
1197 | /* Now we have the resampled sample count which must not exceed | 1300 | /* Now we have the resampled sample count which must not exceed |
1198 | * RESAMPLE_BUF_COUNT/2 to avoid resample buffer overflow. One | 1301 | * RESAMPLE_BUF_RIGHT_CHANNEL to avoid resample buffer overflow. One |
1199 | * must call dsp_input_count() to get the correct input sample | 1302 | * must call dsp_input_count() to get the correct input sample |
1200 | * count. | 1303 | * count. |
1201 | */ | 1304 | */ |
1202 | if (count > RESAMPLE_BUF_COUNT/2) | 1305 | if (count > RESAMPLE_BUF_RIGHT_CHANNEL) |
1203 | count = RESAMPLE_BUF_COUNT/2; | 1306 | count = RESAMPLE_BUF_RIGHT_CHANNEL; |
1204 | 1307 | ||
1205 | return count; | 1308 | return count; |
1206 | } | 1309 | } |
@@ -1221,6 +1324,9 @@ int dsp_input_count(struct dsp_config *dsp, int count) | |||
1221 | dsp->data.resample_data.delta) >> 16); | 1324 | dsp->data.resample_data.delta) >> 16); |
1222 | } | 1325 | } |
1223 | 1326 | ||
1327 | if(dsp->tdspeed_active) | ||
1328 | count = tdspeed_est_input_size(count); | ||
1329 | |||
1224 | return count; | 1330 | return count; |
1225 | } | 1331 | } |
1226 | 1332 | ||
@@ -1234,7 +1340,7 @@ static void dsp_update_functions(struct dsp_config *dsp) | |||
1234 | { | 1340 | { |
1235 | sample_input_new_format(dsp); | 1341 | sample_input_new_format(dsp); |
1236 | sample_output_new_format(dsp); | 1342 | sample_output_new_format(dsp); |
1237 | if (dsp == &audio_dsp) | 1343 | if (dsp == &AUDIO_DSP) |
1238 | dsp_set_crossfeed(crossfeed_enabled); | 1344 | dsp_set_crossfeed(crossfeed_enabled); |
1239 | } | 1345 | } |
1240 | 1346 | ||
@@ -1246,9 +1352,9 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1246 | switch (value) | 1352 | switch (value) |
1247 | { | 1353 | { |
1248 | case CODEC_IDX_AUDIO: | 1354 | case CODEC_IDX_AUDIO: |
1249 | return (intptr_t)&audio_dsp; | 1355 | return (intptr_t)&AUDIO_DSP; |
1250 | case CODEC_IDX_VOICE: | 1356 | case CODEC_IDX_VOICE: |
1251 | return (intptr_t)&voice_dsp; | 1357 | return (intptr_t)&VOICE_DSP; |
1252 | default: | 1358 | default: |
1253 | return (intptr_t)NULL; | 1359 | return (intptr_t)NULL; |
1254 | } | 1360 | } |
@@ -1262,12 +1368,13 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1262 | if we're called from the main audio thread. Voice UI thread should | 1368 | if we're called from the main audio thread. Voice UI thread should |
1263 | not need this feature. | 1369 | not need this feature. |
1264 | */ | 1370 | */ |
1265 | if (dsp == &audio_dsp) | 1371 | if (dsp == &AUDIO_DSP) |
1266 | dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; | 1372 | dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; |
1267 | else | 1373 | else |
1268 | dsp->frequency = dsp->codec_frequency; | 1374 | dsp->frequency = dsp->codec_frequency; |
1269 | 1375 | ||
1270 | resampler_new_delta(dsp); | 1376 | resampler_new_delta(dsp); |
1377 | tdspeed_setup(dsp); | ||
1271 | break; | 1378 | break; |
1272 | 1379 | ||
1273 | case DSP_SET_SAMPLE_DEPTH: | 1380 | case DSP_SET_SAMPLE_DEPTH: |
@@ -1290,13 +1397,14 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1290 | 1397 | ||
1291 | dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; | 1398 | dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; |
1292 | sample_input_new_format(dsp); | 1399 | sample_input_new_format(dsp); |
1293 | dither_init(dsp); | 1400 | dither_init(dsp); |
1294 | break; | 1401 | break; |
1295 | 1402 | ||
1296 | case DSP_SET_STEREO_MODE: | 1403 | case DSP_SET_STEREO_MODE: |
1297 | dsp->stereo_mode = value; | 1404 | dsp->stereo_mode = value; |
1298 | dsp->data.num_channels = value == STEREO_MONO ? 1 : 2; | 1405 | dsp->data.num_channels = value == STEREO_MONO ? 1 : 2; |
1299 | dsp_update_functions(dsp); | 1406 | dsp_update_functions(dsp); |
1407 | tdspeed_setup(dsp); | ||
1300 | break; | 1408 | break; |
1301 | 1409 | ||
1302 | case DSP_RESET: | 1410 | case DSP_RESET: |
@@ -1310,7 +1418,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1310 | dsp->data.clip_min = -((1 << WORD_FRACBITS)); | 1418 | dsp->data.clip_min = -((1 << WORD_FRACBITS)); |
1311 | dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; | 1419 | dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; |
1312 | 1420 | ||
1313 | if (dsp == &audio_dsp) | 1421 | if (dsp == &AUDIO_DSP) |
1314 | { | 1422 | { |
1315 | track_gain = 0; | 1423 | track_gain = 0; |
1316 | album_gain = 0; | 1424 | album_gain = 0; |
@@ -1321,6 +1429,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1321 | 1429 | ||
1322 | dsp_update_functions(dsp); | 1430 | dsp_update_functions(dsp); |
1323 | resampler_new_delta(dsp); | 1431 | resampler_new_delta(dsp); |
1432 | tdspeed_setup(dsp); | ||
1324 | break; | 1433 | break; |
1325 | 1434 | ||
1326 | case DSP_FLUSH: | 1435 | case DSP_FLUSH: |
@@ -1328,25 +1437,26 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) | |||
1328 | sizeof (dsp->data.resample_data)); | 1437 | sizeof (dsp->data.resample_data)); |
1329 | resampler_new_delta(dsp); | 1438 | resampler_new_delta(dsp); |
1330 | dither_init(dsp); | 1439 | dither_init(dsp); |
1440 | tdspeed_setup(dsp); | ||
1331 | break; | 1441 | break; |
1332 | 1442 | ||
1333 | case DSP_SET_TRACK_GAIN: | 1443 | case DSP_SET_TRACK_GAIN: |
1334 | if (dsp == &audio_dsp) | 1444 | if (dsp == &AUDIO_DSP) |
1335 | dsp_set_gain_var(&track_gain, value); | 1445 | dsp_set_gain_var(&track_gain, value); |
1336 | break; | 1446 | break; |
1337 | 1447 | ||
1338 | case DSP_SET_ALBUM_GAIN: | 1448 | case DSP_SET_ALBUM_GAIN: |
1339 | if (dsp == &audio_dsp) | 1449 | if (dsp == &AUDIO_DSP) |
1340 | dsp_set_gain_var(&album_gain, value); | 1450 | dsp_set_gain_var(&album_gain, value); |
1341 | break; | 1451 | break; |
1342 | 1452 | ||
1343 | case DSP_SET_TRACK_PEAK: | 1453 | case DSP_SET_TRACK_PEAK: |
1344 | if (dsp == &audio_dsp) | 1454 | if (dsp == &AUDIO_DSP) |
1345 | dsp_set_gain_var(&track_peak, value); | 1455 | dsp_set_gain_var(&track_peak, value); |
1346 | break; | 1456 | break; |
1347 | 1457 | ||
1348 | case DSP_SET_ALBUM_PEAK: | 1458 | case DSP_SET_ALBUM_PEAK: |
1349 | if (dsp == &audio_dsp) | 1459 | if (dsp == &AUDIO_DSP) |
1350 | dsp_set_gain_var(&album_peak, value); | 1460 | dsp_set_gain_var(&album_peak, value); |
1351 | break; | 1461 | break; |
1352 | 1462 | ||
@@ -1403,5 +1513,5 @@ void dsp_set_replaygain(void) | |||
1403 | 1513 | ||
1404 | /* Store in S8.23 format to simplify calculations. */ | 1514 | /* Store in S8.23 format to simplify calculations. */ |
1405 | replaygain = gain; | 1515 | replaygain = gain; |
1406 | set_gain(&audio_dsp); | 1516 | set_gain(&AUDIO_DSP); |
1407 | } | 1517 | } |
diff --git a/apps/dsp.h b/apps/dsp.h index c3239360b0..5c4211f251 100644 --- a/apps/dsp.h +++ b/apps/dsp.h | |||
@@ -164,5 +164,9 @@ void sound_set_pitch(int r); | |||
164 | int sound_get_pitch(void); | 164 | int sound_get_pitch(void); |
165 | int dsp_callback(int msg, intptr_t param); | 165 | int dsp_callback(int msg, intptr_t param); |
166 | void dsp_dither_enable(bool enable); | 166 | void dsp_dither_enable(bool enable); |
167 | void dsp_timestretch_enable(bool enable); | ||
168 | void dsp_set_timestretch(int percent); | ||
169 | bool dsp_timestretch_enabled(void); | ||
170 | int dsp_get_timestretch(void); | ||
167 | 171 | ||
168 | #endif | 172 | #endif |
diff --git a/apps/dsp_arm.S b/apps/dsp_arm.S index 5b43c3bb5b..11b7ba7141 100644 --- a/apps/dsp_arm.S +++ b/apps/dsp_arm.S | |||
@@ -86,7 +86,7 @@ channels_process_sound_chan_karaoke: | |||
86 | 86 | ||
87 | /**************************************************************************** | 87 | /**************************************************************************** |
88 | * void sample_output_mono(int count, struct dsp_data *data, | 88 | * void sample_output_mono(int count, struct dsp_data *data, |
89 | int32_t *src[], int16_t *dst) | 89 | * const int32_t *src[], int16_t *dst) |
90 | * NOTE: The following code processes two samples at once. When count is odd, | 90 | * NOTE: The following code processes two samples at once. When count is odd, |
91 | * there is an additional obsolete sample processed, which will not be | 91 | * there is an additional obsolete sample processed, which will not be |
92 | * used by the calling functions. | 92 | * used by the calling functions. |
@@ -136,7 +136,7 @@ sample_output_mono: | |||
136 | 136 | ||
137 | /**************************************************************************** | 137 | /**************************************************************************** |
138 | * void sample_output_stereo(int count, struct dsp_data *data, | 138 | * void sample_output_stereo(int count, struct dsp_data *data, |
139 | int32_t *src[], int16_t *dst) | 139 | * const int32_t *src[], int16_t *dst) |
140 | * NOTE: The following code processes two samples at once. When count is odd, | 140 | * NOTE: The following code processes two samples at once. When count is odd, |
141 | * there is an additional obsolete sample processed, which will not be | 141 | * there is an additional obsolete sample processed, which will not be |
142 | * used by the calling functions. | 142 | * used by the calling functions. |
diff --git a/apps/dsp_asm.h b/apps/dsp_asm.h index 64373d3eea..85db57b6ef 100644 --- a/apps/dsp_asm.h +++ b/apps/dsp_asm.h | |||
@@ -54,9 +54,9 @@ void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[]); | |||
54 | 54 | ||
55 | #ifdef DSP_HAVE_ASM_RESAMPLING | 55 | #ifdef DSP_HAVE_ASM_RESAMPLING |
56 | int dsp_upsample(int count, struct dsp_data *data, | 56 | int dsp_upsample(int count, struct dsp_data *data, |
57 | int32_t *src[], int32_t *dst[]); | 57 | const int32_t *src[], int32_t *dst[]); |
58 | int dsp_downsample(int count, struct dsp_data *data, | 58 | int dsp_downsample(int count, struct dsp_data *data, |
59 | int32_t *src[], int32_t *dst[]); | 59 | const int32_t *src[], int32_t *dst[]); |
60 | #endif /* DSP_HAVE_ASM_RESAMPLING */ | 60 | #endif /* DSP_HAVE_ASM_RESAMPLING */ |
61 | 61 | ||
62 | #ifdef DSP_HAVE_ASM_SOUND_CHAN_MONO | 62 | #ifdef DSP_HAVE_ASM_SOUND_CHAN_MONO |
@@ -73,12 +73,12 @@ void channels_process_sound_chan_karaoke(int count, int32_t *buf[]); | |||
73 | 73 | ||
74 | #ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO | 74 | #ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO |
75 | void sample_output_stereo(int count, struct dsp_data *data, | 75 | void sample_output_stereo(int count, struct dsp_data *data, |
76 | int32_t *src[], int16_t *dst); | 76 | const int32_t *src[], int16_t *dst); |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | #ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO | 79 | #ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO |
80 | void sample_output_mono(int count, struct dsp_data *data, | 80 | void sample_output_mono(int count, struct dsp_data *data, |
81 | int32_t *src[], int16_t *dst); | 81 | const int32_t *src[], int16_t *dst); |
82 | #endif | 82 | #endif |
83 | 83 | ||
84 | #endif /* _DSP_ASM_H */ | 84 | #endif /* _DSP_ASM_H */ |
diff --git a/apps/dsp_cf.S b/apps/dsp_cf.S index d8869fcb09..cda811a7d5 100644 --- a/apps/dsp_cf.S +++ b/apps/dsp_cf.S | |||
@@ -191,7 +191,7 @@ dsp_downsample: | |||
191 | 191 | ||
192 | /**************************************************************************** | 192 | /**************************************************************************** |
193 | * int dsp_upsample(int count, struct dsp_data *dsp, | 193 | * int dsp_upsample(int count, struct dsp_data *dsp, |
194 | * int32_t *src[], int32_t *dst[]) | 194 | * const int32_t *src[], int32_t *dst[]) |
195 | */ | 195 | */ |
196 | .section .text | 196 | .section .text |
197 | .align 2 | 197 | .align 2 |
@@ -395,7 +395,7 @@ channels_process_sound_chan_karaoke: | |||
395 | 395 | ||
396 | /**************************************************************************** | 396 | /**************************************************************************** |
397 | * void sample_output_stereo(int count, struct dsp_data *data, | 397 | * void sample_output_stereo(int count, struct dsp_data *data, |
398 | * int32_t *src[], int16_t *dst) | 398 | * const int32_t *src[], int16_t *dst) |
399 | * | 399 | * |
400 | * Framework based on the ubiquitous Rockbox line transfer logic for | 400 | * Framework based on the ubiquitous Rockbox line transfer logic for |
401 | * Coldfire CPUs. | 401 | * Coldfire CPUs. |
@@ -517,7 +517,7 @@ sample_output_stereo: | |||
517 | 517 | ||
518 | /**************************************************************************** | 518 | /**************************************************************************** |
519 | * void sample_output_mono(int count, struct dsp_data *data, | 519 | * void sample_output_mono(int count, struct dsp_data *data, |
520 | * int32_t *src[], int16_t *dst) | 520 | * const int32_t *src[], int16_t *dst) |
521 | * | 521 | * |
522 | * Same treatment as sample_output_stereo but for one channel. | 522 | * Same treatment as sample_output_stereo but for one channel. |
523 | */ | 523 | */ |
diff --git a/apps/gui/pitchscreen.c b/apps/gui/pitchscreen.c index 485eb7861c..5072031652 100644 --- a/apps/gui/pitchscreen.c +++ b/apps/gui/pitchscreen.c | |||
@@ -36,12 +36,13 @@ | |||
36 | #include "system.h" | 36 | #include "system.h" |
37 | #include "misc.h" | 37 | #include "misc.h" |
38 | #include "pitchscreen.h" | 38 | #include "pitchscreen.h" |
39 | #if CONFIG_CODEC == SWCODEC | ||
40 | #include "tdspeed.h" | ||
41 | #endif | ||
42 | |||
39 | 43 | ||
40 | #define PITCH_MODE_ABSOLUTE 1 | ||
41 | #define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE | ||
42 | #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */ | 44 | #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */ |
43 | /* on both sides when drawing */ | 45 | /* on both sides when drawing */ |
44 | |||
45 | 46 | ||
46 | #define PITCH_MAX 2000 | 47 | #define PITCH_MAX 2000 |
47 | #define PITCH_MIN 500 | 48 | #define PITCH_MIN 500 |
@@ -49,8 +50,14 @@ | |||
49 | #define PITCH_BIG_DELTA 10 | 50 | #define PITCH_BIG_DELTA 10 |
50 | #define PITCH_NUDGE_DELTA 20 | 51 | #define PITCH_NUDGE_DELTA 20 |
51 | 52 | ||
52 | 53 | static enum | |
53 | static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */ | 54 | { |
55 | PITCH_MODE_ABSOLUTE, | ||
56 | PITCH_MODE_SEMITONE, | ||
57 | #if CONFIG_CODEC == SWCODEC | ||
58 | PITCH_MODE_TIMESTRETCH, | ||
59 | #endif | ||
60 | } pitch_mode = PITCH_MODE_ABSOLUTE; | ||
54 | 61 | ||
55 | enum | 62 | enum |
56 | { | 63 | { |
@@ -83,8 +90,8 @@ static void pitchscreen_fix_viewports(struct viewport *parent, | |||
83 | 90 | ||
84 | /* must be called before pitchscreen_draw, or within | 91 | /* must be called before pitchscreen_draw, or within |
85 | * since it neither clears nor updates the display */ | 92 | * since it neither clears nor updates the display */ |
86 | static void pitchscreen_draw_icons (struct screen *display, | 93 | static void pitchscreen_draw_icons(struct screen *display, |
87 | struct viewport *parent) | 94 | struct viewport *parent) |
88 | { | 95 | { |
89 | display->set_viewport(parent); | 96 | display->set_viewport(parent); |
90 | display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow], | 97 | display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow], |
@@ -102,25 +109,29 @@ static void pitchscreen_draw_icons (struct screen *display, | |||
102 | display->update_viewport(); | 109 | display->update_viewport(); |
103 | } | 110 | } |
104 | 111 | ||
105 | static void pitchscreen_draw (struct screen *display, int max_lines, | 112 | static void pitchscreen_draw(struct screen *display, int max_lines, |
106 | struct viewport pitch_viewports[PITCH_ITEM_COUNT], int pitch) | 113 | struct viewport pitch_viewports[PITCH_ITEM_COUNT], |
114 | int pitch | ||
115 | #if CONFIG_CODEC == SWCODEC | ||
116 | ,int speed | ||
117 | #endif | ||
118 | ) | ||
107 | { | 119 | { |
108 | unsigned char* ptr; | 120 | unsigned char* ptr; |
109 | unsigned char buf[32]; | 121 | char buf[32]; |
110 | int width_val, w, h; | 122 | int w, h; |
111 | bool show_lang_pitch; | 123 | bool show_lang_pitch; |
112 | 124 | ||
113 | /* Hide "Pitch up/Pitch down" for a small screen */ | 125 | /* "Pitch up/Pitch down" - hide for a small screen */ |
114 | if (max_lines >= 5) | 126 | if (max_lines >= 5) |
115 | { | 127 | { |
116 | /* UP: Pitch Up */ | 128 | /* UP: Pitch Up */ |
117 | display->set_viewport(&pitch_viewports[PITCH_TOP]); | 129 | display->set_viewport(&pitch_viewports[PITCH_TOP]); |
118 | if (pitch_mode == PITCH_MODE_ABSOLUTE) { | 130 | if (pitch_mode == PITCH_MODE_SEMITONE) |
119 | ptr = str(LANG_PITCH_UP); | ||
120 | } else { | ||
121 | ptr = str(LANG_PITCH_UP_SEMITONE); | 131 | ptr = str(LANG_PITCH_UP_SEMITONE); |
122 | } | 132 | else |
123 | display->getstringsize(ptr,&w,&h); | 133 | ptr = str(LANG_PITCH_UP); |
134 | display->getstringsize(ptr, &w, &h); | ||
124 | display->clear_viewport(); | 135 | display->clear_viewport(); |
125 | /* draw text */ | 136 | /* draw text */ |
126 | display->putsxy((pitch_viewports[PITCH_TOP].width / 2) - | 137 | display->putsxy((pitch_viewports[PITCH_TOP].width / 2) - |
@@ -129,81 +140,125 @@ static void pitchscreen_draw (struct screen *display, int max_lines, | |||
129 | 140 | ||
130 | /* DOWN: Pitch Down */ | 141 | /* DOWN: Pitch Down */ |
131 | display->set_viewport(&pitch_viewports[PITCH_BOTTOM]); | 142 | display->set_viewport(&pitch_viewports[PITCH_BOTTOM]); |
132 | if (pitch_mode == PITCH_MODE_ABSOLUTE) { | 143 | if (pitch_mode == PITCH_MODE_SEMITONE) |
133 | ptr = str(LANG_PITCH_DOWN); | ||
134 | } else { | ||
135 | ptr = str(LANG_PITCH_DOWN_SEMITONE); | 144 | ptr = str(LANG_PITCH_DOWN_SEMITONE); |
136 | } | 145 | else |
137 | display->getstringsize(ptr,&w,&h); | 146 | ptr = str(LANG_PITCH_DOWN); |
147 | display->getstringsize(ptr, &w, &h); | ||
138 | display->clear_viewport(); | 148 | display->clear_viewport(); |
139 | /* draw text */ | 149 | /* draw text */ |
140 | display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) - | 150 | display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) - |
141 | (w / 2), 0, ptr); | 151 | (w / 2), 0, ptr); |
142 | display->update_viewport(); | 152 | display->update_viewport(); |
143 | } | 153 | } |
144 | display->set_viewport(&pitch_viewports[PITCH_MID]); | ||
145 | 154 | ||
146 | snprintf((char *)buf, sizeof(buf), "%s", str(LANG_PITCH)); | 155 | /* Middle section */ |
147 | display->getstringsize(buf,&w,&h); | 156 | display->set_viewport(&pitch_viewports[PITCH_MID]); |
148 | /* lets hide LANG_PITCH for smaller screens */ | ||
149 | display->clear_viewport(); | 157 | display->clear_viewport(); |
158 | int width_used = 0; | ||
159 | |||
160 | /* Middle section upper line - hide for a small screen */ | ||
150 | if ((show_lang_pitch = (max_lines >= 3))) | 161 | if ((show_lang_pitch = (max_lines >= 3))) |
162 | { | ||
163 | #if CONFIG_CODEC == SWCODEC | ||
164 | if (pitch_mode != PITCH_MODE_TIMESTRETCH) | ||
165 | { | ||
166 | #endif | ||
167 | /* LANG_PITCH */ | ||
168 | snprintf(buf, sizeof(buf), "%s", str(LANG_PITCH)); | ||
169 | #if CONFIG_CODEC == SWCODEC | ||
170 | } | ||
171 | else | ||
172 | { | ||
173 | /* Pitch:XXX.X% */ | ||
174 | snprintf(buf, sizeof(buf), "%s:%d.%d%%", str(LANG_PITCH), | ||
175 | pitch / 10, pitch % 10); | ||
176 | } | ||
177 | #endif | ||
178 | display->getstringsize(buf, &w, &h); | ||
151 | display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2), | 179 | display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2), |
152 | 0, buf); | 180 | 0, buf); |
153 | 181 | if (w > width_used) | |
154 | /* "XXX.X%" */ | 182 | width_used = w; |
155 | snprintf((char *)buf, sizeof(buf), "%d.%d%%", | 183 | } |
156 | pitch / 10, pitch % 10 ); | 184 | |
157 | display->getstringsize(buf,&width_val,&h); | 185 | /* Middle section lower line */ |
158 | display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (width_val / 2), | 186 | #if CONFIG_CODEC == SWCODEC |
159 | (show_lang_pitch? h : h/2), buf); | 187 | if (pitch_mode != PITCH_MODE_TIMESTRETCH) |
160 | 188 | { | |
161 | /* What's wider? LANG_PITCH or the value? | 189 | #endif |
162 | * Only interesting if LANG_PITCH is actually drawn */ | 190 | /* "XXX.X%" */ |
163 | if (show_lang_pitch && width_val > w) | 191 | snprintf(buf, sizeof(buf), "%d.%d%%", |
164 | w = width_val; | 192 | pitch / 10, pitch % 10); |
165 | 193 | #if CONFIG_CODEC == SWCODEC | |
166 | /* Let's treat '+' and '-' as equally wide | 194 | } |
167 | * This saves a getstringsize call | 195 | else |
168 | * Also, it wouldn't look nice if -2% shows up, but +2% not */ | 196 | { |
169 | display->getstringsize("+2%",&width_val,&h); | 197 | /* "Speed:XXX%" */ |
170 | w += width_val*2; | 198 | snprintf(buf, sizeof(buf), "%s:%d%%", str(LANG_SPEED), speed); |
171 | /* hide +2%/-2% for a narrow screens */ | 199 | } |
172 | if (w <= pitch_viewports[PITCH_MID].width) | 200 | #endif |
201 | display->getstringsize(buf, &w, &h); | ||
202 | display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2), | ||
203 | (show_lang_pitch ? h : h/2), buf); | ||
204 | if (w > width_used) | ||
205 | width_used = w; | ||
206 | |||
207 | /* Middle section left/right labels */ | ||
208 | const char *leftlabel = "-2%"; | ||
209 | const char *rightlabel = "+2%"; | ||
210 | #if CONFIG_CODEC == SWCODEC | ||
211 | if (pitch_mode == PITCH_MODE_TIMESTRETCH) | ||
212 | { | ||
213 | leftlabel = "<<"; | ||
214 | rightlabel = ">>"; | ||
215 | } | ||
216 | #endif | ||
217 | |||
218 | /* Only display if they fit */ | ||
219 | display->getstringsize(leftlabel, &w, &h); | ||
220 | width_used += w; | ||
221 | display->getstringsize(rightlabel, &w, &h); | ||
222 | width_used += w; | ||
223 | |||
224 | if (width_used <= pitch_viewports[PITCH_MID].width) | ||
173 | { | 225 | { |
174 | /* RIGHT: +2% */ | 226 | display->putsxy(0, h / 2, leftlabel); |
175 | display->putsxy(pitch_viewports[PITCH_MID].width - width_val, h /2, "+2%"); | 227 | display->putsxy(pitch_viewports[PITCH_MID].width - w, h /2, rightlabel); |
176 | /* LEFT: -2% */ | ||
177 | display->putsxy(0, h / 2, "-2%"); | ||
178 | } | 228 | } |
179 | display->update_viewport(); | 229 | display->update_viewport(); |
180 | display->set_viewport(NULL); | 230 | display->set_viewport(NULL); |
181 | } | 231 | } |
182 | 232 | ||
183 | static int pitch_increase(int pitch, int delta, bool allow_cutoff) | 233 | static int pitch_increase(int pitch, int pitch_delta, bool allow_cutoff) |
184 | { | 234 | { |
185 | int new_pitch; | 235 | int new_pitch; |
186 | 236 | ||
187 | if (delta < 0) { | 237 | if (pitch_delta < 0) |
188 | if (pitch + delta >= PITCH_MIN) { | 238 | { |
189 | new_pitch = pitch + delta; | 239 | if (pitch + pitch_delta >= PITCH_MIN) |
190 | } else { | 240 | new_pitch = pitch + pitch_delta; |
191 | if (!allow_cutoff) { | 241 | else |
242 | { | ||
243 | if (!allow_cutoff) | ||
192 | return pitch; | 244 | return pitch; |
193 | } | ||
194 | new_pitch = PITCH_MIN; | 245 | new_pitch = PITCH_MIN; |
195 | } | 246 | } |
196 | } else if (delta > 0) { | 247 | } |
197 | if (pitch + delta <= PITCH_MAX) { | 248 | else if (pitch_delta > 0) |
198 | new_pitch = pitch + delta; | 249 | { |
199 | } else { | 250 | if (pitch + pitch_delta <= PITCH_MAX) |
200 | if (!allow_cutoff) { | 251 | new_pitch = pitch + pitch_delta; |
252 | else | ||
253 | { | ||
254 | if (!allow_cutoff) | ||
201 | return pitch; | 255 | return pitch; |
202 | } | ||
203 | new_pitch = PITCH_MAX; | 256 | new_pitch = PITCH_MAX; |
204 | } | 257 | } |
205 | } else { | 258 | } |
206 | /* delta == 0 -> no real change */ | 259 | else |
260 | { | ||
261 | /* pitch_delta == 0 -> no real change */ | ||
207 | return pitch; | 262 | return pitch; |
208 | } | 263 | } |
209 | sound_set_pitch(new_pitch); | 264 | sound_set_pitch(new_pitch); |
@@ -234,10 +289,13 @@ static int pitch_increase_semitone(int pitch, bool up) | |||
234 | uint32_t tmp; | 289 | uint32_t tmp; |
235 | uint32_t round_fct; /* How much to scale down at the end */ | 290 | uint32_t round_fct; /* How much to scale down at the end */ |
236 | tmp = pitch; | 291 | tmp = pitch; |
237 | if (up) { | 292 | if (up) |
293 | { | ||
238 | tmp = tmp * PITCH_SEMITONE_FACTOR; | 294 | tmp = tmp * PITCH_SEMITONE_FACTOR; |
239 | round_fct = PITCH_K_FCT; | 295 | round_fct = PITCH_K_FCT; |
240 | } else { | 296 | } |
297 | else | ||
298 | { | ||
241 | tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR; | 299 | tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR; |
242 | round_fct = PITCH_N_FCT; | 300 | round_fct = PITCH_N_FCT; |
243 | } | 301 | } |
@@ -256,7 +314,12 @@ int gui_syncpitchscreen_run(void) | |||
256 | { | 314 | { |
257 | int button, i; | 315 | int button, i; |
258 | int pitch = sound_get_pitch(); | 316 | int pitch = sound_get_pitch(); |
259 | int new_pitch, delta = 0; | 317 | #if CONFIG_CODEC == SWCODEC |
318 | int speed = dsp_get_timestretch(); | ||
319 | int maintain_speed_pitch = speed * pitch; /* speed * pitch to maintain */ | ||
320 | #endif | ||
321 | int new_pitch; | ||
322 | int pitch_delta = 0; | ||
260 | bool nudged = false; | 323 | bool nudged = false; |
261 | bool exit = false; | 324 | bool exit = false; |
262 | /* should maybe be passed per parameter later, not needed for now */ | 325 | /* should maybe be passed per parameter later, not needed for now */ |
@@ -283,58 +346,118 @@ int gui_syncpitchscreen_run(void) | |||
283 | { | 346 | { |
284 | FOR_NB_SCREENS(i) | 347 | FOR_NB_SCREENS(i) |
285 | pitchscreen_draw(&screens[i], max_lines[i], | 348 | pitchscreen_draw(&screens[i], max_lines[i], |
286 | pitch_viewports[i], pitch); | 349 | pitch_viewports[i], pitch |
287 | button = get_action(CONTEXT_PITCHSCREEN,HZ); | 350 | #if CONFIG_CODEC == SWCODEC |
288 | switch (button) { | 351 | , speed |
352 | #endif | ||
353 | ); | ||
354 | button = get_action(CONTEXT_PITCHSCREEN, HZ); | ||
355 | switch (button) | ||
356 | { | ||
289 | case ACTION_PS_INC_SMALL: | 357 | case ACTION_PS_INC_SMALL: |
290 | delta = PITCH_SMALL_DELTA; | 358 | pitch_delta = PITCH_SMALL_DELTA; |
291 | break; | 359 | break; |
292 | 360 | ||
293 | case ACTION_PS_INC_BIG: | 361 | case ACTION_PS_INC_BIG: |
294 | delta = PITCH_BIG_DELTA; | 362 | pitch_delta = PITCH_BIG_DELTA; |
295 | break; | 363 | break; |
296 | 364 | ||
297 | case ACTION_PS_DEC_SMALL: | 365 | case ACTION_PS_DEC_SMALL: |
298 | delta = -PITCH_SMALL_DELTA; | 366 | pitch_delta = -PITCH_SMALL_DELTA; |
299 | break; | 367 | break; |
300 | 368 | ||
301 | case ACTION_PS_DEC_BIG: | 369 | case ACTION_PS_DEC_BIG: |
302 | delta = -PITCH_BIG_DELTA; | 370 | pitch_delta = -PITCH_BIG_DELTA; |
303 | break; | 371 | break; |
304 | 372 | ||
305 | case ACTION_PS_NUDGE_RIGHT: | 373 | case ACTION_PS_NUDGE_RIGHT: |
306 | new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); | 374 | #if CONFIG_CODEC == SWCODEC |
307 | nudged = (new_pitch != pitch); | 375 | if (pitch_mode != PITCH_MODE_TIMESTRETCH) |
308 | pitch = new_pitch; | 376 | { |
377 | #endif | ||
378 | new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); | ||
379 | nudged = (new_pitch != pitch); | ||
380 | pitch = new_pitch; | ||
381 | break; | ||
382 | #if CONFIG_CODEC == SWCODEC | ||
383 | } | ||
384 | |||
385 | case ACTION_PS_FASTER: | ||
386 | if (pitch_mode == PITCH_MODE_TIMESTRETCH) | ||
387 | { | ||
388 | if (speed < SPEED_MAX) | ||
389 | { | ||
390 | speed++; | ||
391 | dsp_set_timestretch(speed); | ||
392 | maintain_speed_pitch = speed * pitch; | ||
393 | } | ||
394 | } | ||
309 | break; | 395 | break; |
396 | #endif | ||
310 | 397 | ||
311 | case ACTION_PS_NUDGE_RIGHTOFF: | 398 | case ACTION_PS_NUDGE_RIGHTOFF: |
312 | if (nudged) { | 399 | if (nudged) |
400 | { | ||
313 | pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); | 401 | pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); |
402 | nudged = false; | ||
314 | } | 403 | } |
315 | nudged = false; | ||
316 | break; | 404 | break; |
317 | 405 | ||
318 | case ACTION_PS_NUDGE_LEFT: | 406 | case ACTION_PS_NUDGE_LEFT: |
319 | new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); | 407 | #if CONFIG_CODEC == SWCODEC |
320 | nudged = (new_pitch != pitch); | 408 | if (pitch_mode != PITCH_MODE_TIMESTRETCH) |
321 | pitch = new_pitch; | 409 | { |
410 | #endif | ||
411 | new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false); | ||
412 | nudged = (new_pitch != pitch); | ||
413 | pitch = new_pitch; | ||
414 | break; | ||
415 | #if CONFIG_CODEC == SWCODEC | ||
416 | } | ||
417 | |||
418 | case ACTION_PS_SLOWER: | ||
419 | if (pitch_mode == PITCH_MODE_TIMESTRETCH) | ||
420 | { | ||
421 | if (speed > SPEED_MIN) | ||
422 | { | ||
423 | speed--; | ||
424 | dsp_set_timestretch(speed); | ||
425 | maintain_speed_pitch = speed * pitch; | ||
426 | } | ||
427 | } | ||
322 | break; | 428 | break; |
429 | #endif | ||
323 | 430 | ||
324 | case ACTION_PS_NUDGE_LEFTOFF: | 431 | case ACTION_PS_NUDGE_LEFTOFF: |
325 | if (nudged) { | 432 | if (nudged) |
433 | { | ||
326 | pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); | 434 | pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false); |
435 | nudged = false; | ||
327 | } | 436 | } |
328 | nudged = false; | ||
329 | break; | 437 | break; |
330 | 438 | ||
331 | case ACTION_PS_RESET: | 439 | case ACTION_PS_RESET: |
332 | pitch = 1000; | 440 | pitch = 1000; |
333 | sound_set_pitch( pitch ); | 441 | sound_set_pitch(pitch); |
442 | #if CONFIG_CODEC == SWCODEC | ||
443 | speed = 100; | ||
444 | dsp_set_timestretch(speed); | ||
445 | maintain_speed_pitch = speed * pitch; | ||
446 | #endif | ||
334 | break; | 447 | break; |
335 | 448 | ||
336 | case ACTION_PS_TOGGLE_MODE: | 449 | case ACTION_PS_TOGGLE_MODE: |
337 | pitch_mode = -pitch_mode; | 450 | ++pitch_mode; |
451 | #if CONFIG_CODEC == SWCODEC | ||
452 | if (dsp_timestretch_enabled()) | ||
453 | { | ||
454 | if (pitch_mode > PITCH_MODE_TIMESTRETCH) | ||
455 | pitch_mode = PITCH_MODE_ABSOLUTE; | ||
456 | break; | ||
457 | } | ||
458 | #endif | ||
459 | if (pitch_mode > PITCH_MODE_SEMITONE) | ||
460 | pitch_mode = PITCH_MODE_ABSOLUTE; | ||
338 | break; | 461 | break; |
339 | 462 | ||
340 | case ACTION_PS_EXIT: | 463 | case ACTION_PS_EXIT: |
@@ -342,19 +465,32 @@ int gui_syncpitchscreen_run(void) | |||
342 | break; | 465 | break; |
343 | 466 | ||
344 | default: | 467 | default: |
345 | if(default_event_handler(button) == SYS_USB_CONNECTED) | 468 | if (default_event_handler(button) == SYS_USB_CONNECTED) |
346 | return 1; | 469 | return 1; |
347 | break; | 470 | break; |
348 | } | 471 | } |
349 | if(delta) | 472 | if (pitch_delta) |
350 | { | 473 | { |
351 | if (pitch_mode == PITCH_MODE_ABSOLUTE) { | 474 | if (pitch_mode == PITCH_MODE_SEMITONE) |
352 | pitch = pitch_increase(pitch, delta, true); | 475 | pitch = pitch_increase_semitone(pitch, pitch_delta > 0); |
353 | } else { | 476 | else |
354 | pitch = pitch_increase_semitone(pitch, delta > 0); | 477 | pitch = pitch_increase(pitch, pitch_delta, true); |
478 | #if CONFIG_CODEC == SWCODEC | ||
479 | if (pitch_mode == PITCH_MODE_TIMESTRETCH) | ||
480 | { | ||
481 | /* Set speed to maintain time dimension */ | ||
482 | /* i.e. increase pitch, slow down speed */ | ||
483 | int new_speed = maintain_speed_pitch / pitch; | ||
484 | if (new_speed >= SPEED_MIN && new_speed <= SPEED_MAX) | ||
485 | { | ||
486 | speed = new_speed; | ||
487 | dsp_set_timestretch(speed); | ||
488 | } | ||
355 | } | 489 | } |
356 | 490 | else | |
357 | delta = 0; | 491 | maintain_speed_pitch = speed * pitch; |
492 | #endif | ||
493 | pitch_delta = 0; | ||
358 | } | 494 | } |
359 | } | 495 | } |
360 | #if CONFIG_CODEC == SWCODEC | 496 | #if CONFIG_CODEC == SWCODEC |
diff --git a/apps/keymaps/keymap-av300.c b/apps/keymaps/keymap-av300.c index 6c91499a50..1cca2c2a8b 100644 --- a/apps/keymaps/keymap-av300.c +++ b/apps/keymaps/keymap-av300.c | |||
@@ -159,6 +159,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
159 | { ACTION_PS_TOGGLE_MODE, BUTTON_F1, BUTTON_NONE }, | 159 | { ACTION_PS_TOGGLE_MODE, BUTTON_F1, BUTTON_NONE }, |
160 | { ACTION_PS_RESET, BUTTON_ON, BUTTON_NONE }, | 160 | { ACTION_PS_RESET, BUTTON_ON, BUTTON_NONE }, |
161 | { ACTION_PS_EXIT, BUTTON_OFF, BUTTON_NONE }, | 161 | { ACTION_PS_EXIT, BUTTON_OFF, BUTTON_NONE }, |
162 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
163 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
162 | 164 | ||
163 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 165 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
164 | }; /* button_context_pitchcreen */ | 166 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-c100.c b/apps/keymaps/keymap-c100.c index c8ba16cdfb..80948c0e19 100644 --- a/apps/keymaps/keymap-c100.c +++ b/apps/keymaps/keymap-c100.c | |||
@@ -174,6 +174,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
174 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, | 174 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, |
175 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 175 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
176 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 176 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
177 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
178 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
177 | 179 | ||
178 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 180 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
179 | }; /* button_context_pitchscreen */ | 181 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-c200.c b/apps/keymaps/keymap-c200.c index 56504584f8..c9e5d4394e 100644 --- a/apps/keymaps/keymap-c200.c +++ b/apps/keymaps/keymap-c200.c | |||
@@ -194,19 +194,17 @@ static const struct button_mapping button_context_settings_right_is_inc[] = { | |||
194 | static const struct button_mapping button_context_pitchscreen[] = { | 194 | static const struct button_mapping button_context_pitchscreen[] = { |
195 | { ACTION_PS_INC_SMALL, BUTTON_UP, BUTTON_NONE }, | 195 | { ACTION_PS_INC_SMALL, BUTTON_UP, BUTTON_NONE }, |
196 | { ACTION_PS_INC_BIG, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE }, | 196 | { ACTION_PS_INC_BIG, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE }, |
197 | |||
198 | { ACTION_PS_DEC_SMALL, BUTTON_DOWN, BUTTON_NONE }, | 197 | { ACTION_PS_DEC_SMALL, BUTTON_DOWN, BUTTON_NONE }, |
199 | { ACTION_PS_DEC_BIG, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, | 198 | { ACTION_PS_DEC_BIG, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, |
200 | |||
201 | { ACTION_PS_NUDGE_LEFT, BUTTON_LEFT, BUTTON_NONE }, | 199 | { ACTION_PS_NUDGE_LEFT, BUTTON_LEFT, BUTTON_NONE }, |
202 | { ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE }, | 200 | { ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE }, |
203 | |||
204 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, | 201 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, |
205 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, | 202 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, |
206 | 203 | { ACTION_PS_TOGGLE_MODE, BUTTON_REC, BUTTON_NONE }, | |
207 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 204 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
208 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 205 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
209 | 206 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | |
207 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
210 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 208 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
211 | }; /* button_context_pitchscreen */ | 209 | }; /* button_context_pitchscreen */ |
212 | 210 | ||
diff --git a/apps/keymaps/keymap-clip.c b/apps/keymaps/keymap-clip.c index 4b778beeb7..002cc3c36f 100644 --- a/apps/keymaps/keymap-clip.c +++ b/apps/keymaps/keymap-clip.c | |||
@@ -182,19 +182,19 @@ static const struct button_mapping button_context_settings_right_is_inc[] = { | |||
182 | }; /* button_context_settings_right_is_inc */ | 182 | }; /* button_context_settings_right_is_inc */ |
183 | 183 | ||
184 | static const struct button_mapping button_context_pitchscreen[] = { | 184 | static const struct button_mapping button_context_pitchscreen[] = { |
185 | { ACTION_PS_INC_SMALL, BUTTON_RIGHT, BUTTON_NONE }, | 185 | { ACTION_PS_INC_SMALL, BUTTON_UP, BUTTON_NONE }, |
186 | { ACTION_PS_INC_BIG, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | 186 | { ACTION_PS_INC_BIG, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE }, |
187 | { ACTION_PS_DEC_SMALL, BUTTON_LEFT, BUTTON_NONE }, | 187 | { ACTION_PS_DEC_SMALL, BUTTON_DOWN, BUTTON_NONE }, |
188 | { ACTION_PS_DEC_BIG, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | 188 | { ACTION_PS_DEC_BIG, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, |
189 | { ACTION_PS_NUDGE_LEFT, BUTTON_LEFT, BUTTON_NONE }, | 189 | { ACTION_PS_NUDGE_LEFT, BUTTON_LEFT, BUTTON_NONE }, |
190 | { ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE }, | 190 | { ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE }, |
191 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, | 191 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, |
192 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, | 192 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, |
193 | { ACTION_PS_TOGGLE_MODE, BUTTON_HOME, BUTTON_NONE }, | 193 | { ACTION_PS_TOGGLE_MODE, BUTTON_HOME, BUTTON_NONE }, |
194 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 194 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
195 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 195 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
196 | { ACTION_PS_EXIT, BUTTON_UP, BUTTON_NONE }, | 196 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, |
197 | 197 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | |
198 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 198 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
199 | }; /* button_context_pitchscreen */ | 199 | }; /* button_context_pitchscreen */ |
200 | 200 | ||
diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c index a2017de6f3..569862827d 100644 --- a/apps/keymaps/keymap-e200.c +++ b/apps/keymaps/keymap-e200.c | |||
@@ -203,6 +203,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
203 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 203 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
204 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 204 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
205 | { ACTION_PS_EXIT, BUTTON_UP, BUTTON_NONE }, | 205 | { ACTION_PS_EXIT, BUTTON_UP, BUTTON_NONE }, |
206 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
207 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT,BUTTON_NONE }, | ||
206 | 208 | ||
207 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 209 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
208 | }; /* button_context_pitchscreen */ | 210 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-fuze.c b/apps/keymaps/keymap-fuze.c index 697598843b..783446429f 100644 --- a/apps/keymaps/keymap-fuze.c +++ b/apps/keymaps/keymap-fuze.c | |||
@@ -203,6 +203,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
203 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 203 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
204 | { ACTION_PS_EXIT, BUTTON_HOME|BUTTON_REPEAT, BUTTON_NONE }, | 204 | { ACTION_PS_EXIT, BUTTON_HOME|BUTTON_REPEAT, BUTTON_NONE }, |
205 | { ACTION_PS_EXIT, BUTTON_UP, BUTTON_NONE }, | 205 | { ACTION_PS_EXIT, BUTTON_UP, BUTTON_NONE }, |
206 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
207 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
206 | 208 | ||
207 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 209 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
208 | }; /* button_context_pitchscreen */ | 210 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-gigabeat-s.c b/apps/keymaps/keymap-gigabeat-s.c index 66b58615c5..da7baa29cb 100644 --- a/apps/keymaps/keymap-gigabeat-s.c +++ b/apps/keymaps/keymap-gigabeat-s.c | |||
@@ -252,6 +252,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
252 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 252 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
253 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, | 253 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, |
254 | { ACTION_PS_EXIT, BUTTON_BACK, BUTTON_NONE }, | 254 | { ACTION_PS_EXIT, BUTTON_BACK, BUTTON_NONE }, |
255 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
256 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT,BUTTON_NONE }, | ||
255 | 257 | ||
256 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 258 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
257 | }; /* button_context_pitchcreen */ | 259 | }; /* button_context_pitchcreen */ |
@@ -445,6 +447,8 @@ static const struct button_mapping remote_button_context_pitchscreen[] = { | |||
445 | { ACTION_PS_RESET, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY }, | 447 | { ACTION_PS_RESET, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY }, |
446 | { ACTION_PS_TOGGLE_MODE, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY }, | 448 | { ACTION_PS_TOGGLE_MODE, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY }, |
447 | { ACTION_PS_EXIT, BUTTON_RC_DSP|BUTTON_REL, BUTTON_RC_DSP }, | 449 | { ACTION_PS_EXIT, BUTTON_RC_DSP|BUTTON_REL, BUTTON_RC_DSP }, |
450 | { ACTION_PS_SLOWER, BUTTON_RC_RW|BUTTON_REPEAT, BUTTON_NONE }, | ||
451 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
448 | 452 | ||
449 | LAST_ITEM_IN_LIST | 453 | LAST_ITEM_IN_LIST |
450 | }; /* remote_button_context_pitchscreen */ | 454 | }; /* remote_button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-gigabeat.c b/apps/keymaps/keymap-gigabeat.c index 31abce5bb2..3e5f404c71 100644 --- a/apps/keymaps/keymap-gigabeat.c +++ b/apps/keymaps/keymap-gigabeat.c | |||
@@ -240,6 +240,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
241 | { ACTION_PS_RESET, BUTTON_A, BUTTON_NONE }, | 241 | { ACTION_PS_RESET, BUTTON_A, BUTTON_NONE }, |
242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
243 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
244 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
243 | 245 | ||
244 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 246 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
245 | }; /* button_context_pitchcreen */ | 247 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c index aed55dbfa2..0c1d4b2331 100644 --- a/apps/keymaps/keymap-h10.c +++ b/apps/keymaps/keymap-h10.c | |||
@@ -260,6 +260,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
260 | { ACTION_PS_TOGGLE_MODE, BUTTON_POWER, BUTTON_NONE }, | 260 | { ACTION_PS_TOGGLE_MODE, BUTTON_POWER, BUTTON_NONE }, |
261 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, | 261 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, |
262 | { ACTION_PS_EXIT, BUTTON_LEFT, BUTTON_NONE }, | 262 | { ACTION_PS_EXIT, BUTTON_LEFT, BUTTON_NONE }, |
263 | { ACTION_PS_SLOWER, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE }, | ||
264 | { ACTION_PS_FASTER, BUTTON_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
263 | 265 | ||
264 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 266 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
265 | }; /* button_context_pitchscreen */ | 267 | }; /* button_context_pitchscreen */ |
@@ -274,6 +276,8 @@ static const struct button_mapping remote_button_context_pitchscreen[] = { | |||
274 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RC_FF, BUTTON_NONE }, | 276 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RC_FF, BUTTON_NONE }, |
275 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RC_FF|BUTTON_REL, BUTTON_NONE }, | 277 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RC_FF|BUTTON_REL, BUTTON_NONE }, |
276 | { ACTION_PS_RESET, BUTTON_RC_PLAY, BUTTON_NONE }, | 278 | { ACTION_PS_RESET, BUTTON_RC_PLAY, BUTTON_NONE }, |
279 | { ACTION_PS_SLOWER, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, | ||
280 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
277 | 281 | ||
278 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 282 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
279 | }; /* button_context_pitchscreen */ | 283 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-h1x0_h3x0.c b/apps/keymaps/keymap-h1x0_h3x0.c index e4eb6c8168..cd18bf0041 100644 --- a/apps/keymaps/keymap-h1x0_h3x0.c +++ b/apps/keymaps/keymap-h1x0_h3x0.c | |||
@@ -230,6 +230,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
230 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 230 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
231 | { ACTION_PS_EXIT, BUTTON_ON, BUTTON_NONE }, | 231 | { ACTION_PS_EXIT, BUTTON_ON, BUTTON_NONE }, |
232 | { ACTION_PS_EXIT, BUTTON_OFF, BUTTON_NONE }, | 232 | { ACTION_PS_EXIT, BUTTON_OFF, BUTTON_NONE }, |
233 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
234 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
233 | 235 | ||
234 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 236 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
235 | }; /* button_context_pitchcreen */ | 237 | }; /* button_context_pitchcreen */ |
@@ -561,6 +563,8 @@ static const struct button_mapping button_context_pitchscreen_nonlcdremote[] = | |||
561 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, | 563 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, |
562 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, | 564 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, |
563 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, | 565 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, |
566 | { ACTION_PS_SLOWER, BUTTON_RC_REW|BUTTON_REPEAT,BUTTON_NONE }, | ||
567 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
564 | 568 | ||
565 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 569 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
566 | }; /* button_context_pitchcreen */ | 570 | }; /* button_context_pitchcreen */ |
@@ -577,6 +581,8 @@ static const struct button_mapping button_context_pitchscreen_h100lcdremote[] = | |||
577 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, | 581 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, |
578 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, | 582 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, |
579 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, | 583 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, |
584 | { ACTION_PS_SLOWER, BUTTON_RC_SOURCE|BUTTON_REPEAT, BUTTON_NONE }, | ||
585 | { ACTION_PS_FASTER, BUTTON_RC_BITRATE|BUTTON_REPEAT, BUTTON_NONE }, | ||
580 | 586 | ||
581 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 587 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
582 | }; | 588 | }; |
@@ -593,6 +599,8 @@ static const struct button_mapping button_context_pitchscreen_h300lcdremote[] = | |||
593 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, | 599 | { ACTION_PS_RESET, BUTTON_RC_MENU, BUTTON_NONE }, |
594 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, | 600 | { ACTION_PS_EXIT, BUTTON_RC_ON, BUTTON_NONE }, |
595 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, | 601 | { ACTION_PS_EXIT, BUTTON_RC_STOP, BUTTON_NONE }, |
602 | { ACTION_PS_SLOWER, BUTTON_RC_REW|BUTTON_REPEAT,BUTTON_NONE }, | ||
603 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
596 | 604 | ||
597 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 605 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
598 | }; | 606 | }; |
diff --git a/apps/keymaps/keymap-hdd1630.c b/apps/keymaps/keymap-hdd1630.c index deb77307b8..86a6a58797 100644 --- a/apps/keymaps/keymap-hdd1630.c +++ b/apps/keymaps/keymap-hdd1630.c | |||
@@ -238,8 +238,10 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
238 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, | 238 | { ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, |
239 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, | 239 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, |
240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
241 | { ACTION_PS_RESET, BUTTON_VIEW, BUTTON_NONE }, | 241 | { ACTION_PS_RESET, BUTTON_VIEW, BUTTON_NONE }, |
242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
243 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
244 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
243 | 245 | ||
244 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 246 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
245 | }; /* button_context_pitchcreen */ | 247 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-iaudio67.c b/apps/keymaps/keymap-iaudio67.c index b0dac93386..a1eeb08886 100644 --- a/apps/keymaps/keymap-iaudio67.c +++ b/apps/keymaps/keymap-iaudio67.c | |||
@@ -197,6 +197,10 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
197 | 197 | ||
198 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, | 198 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, |
199 | { ACTION_PS_EXIT, BUTTON_MENU, BUTTON_NONE }, | 199 | { ACTION_PS_EXIT, BUTTON_MENU, BUTTON_NONE }, |
200 | |||
201 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
202 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
203 | |||
200 | #endif | 204 | #endif |
201 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 205 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
202 | }; /* button_context_pitchscreen */ | 206 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-ifp7xx.c b/apps/keymaps/keymap-ifp7xx.c index 06631438bc..3b09df49fc 100644 --- a/apps/keymaps/keymap-ifp7xx.c +++ b/apps/keymaps/keymap-ifp7xx.c | |||
@@ -132,6 +132,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
132 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, | 132 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, |
133 | { ACTION_PS_RESET, BUTTON_MODE, BUTTON_NONE }, | 133 | { ACTION_PS_RESET, BUTTON_MODE, BUTTON_NONE }, |
134 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, | 134 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, |
135 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
136 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
135 | 137 | ||
136 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 138 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
137 | }; /* button_context_pitchcreen */ | 139 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c index 65c5703451..8170e8c7e1 100644 --- a/apps/keymaps/keymap-ipod.c +++ b/apps/keymaps/keymap-ipod.c | |||
@@ -146,6 +146,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
146 | { ACTION_PS_TOGGLE_MODE, BUTTON_PLAY, BUTTON_NONE }, | 146 | { ACTION_PS_TOGGLE_MODE, BUTTON_PLAY, BUTTON_NONE }, |
147 | { ACTION_PS_RESET, BUTTON_MENU, BUTTON_NONE }, | 147 | { ACTION_PS_RESET, BUTTON_MENU, BUTTON_NONE }, |
148 | { ACTION_PS_EXIT, BUTTON_SELECT, BUTTON_NONE }, | 148 | { ACTION_PS_EXIT, BUTTON_SELECT, BUTTON_NONE }, |
149 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
150 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
149 | 151 | ||
150 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 152 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
151 | }; /* button_context_pitchscreen */ | 153 | }; /* button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-logikdax.c b/apps/keymaps/keymap-logikdax.c index fdf51e1652..cda6107b45 100644 --- a/apps/keymaps/keymap-logikdax.c +++ b/apps/keymaps/keymap-logikdax.c | |||
@@ -190,6 +190,9 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
190 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 190 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
191 | { ACTION_PS_EXIT, BUTTON_MODE, BUTTON_NONE }, | 191 | { ACTION_PS_EXIT, BUTTON_MODE, BUTTON_NONE }, |
192 | 192 | ||
193 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
194 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
195 | |||
193 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 196 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
194 | }; /* button_context_pitchscreen */ | 197 | }; /* button_context_pitchscreen */ |
195 | 198 | ||
diff --git a/apps/keymaps/keymap-m200.c b/apps/keymaps/keymap-m200.c index 86144c0b0c..8318bd42e7 100644 --- a/apps/keymaps/keymap-m200.c +++ b/apps/keymaps/keymap-m200.c | |||
@@ -207,6 +207,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
207 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, | 207 | { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE }, |
208 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 208 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
209 | 209 | ||
210 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
211 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
210 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), | 212 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), |
211 | }; /* button_context_pitchscreen */ | 213 | }; /* button_context_pitchscreen */ |
212 | 214 | ||
diff --git a/apps/keymaps/keymap-m3.c b/apps/keymaps/keymap-m3.c index 4da6855644..6b68f1f881 100644 --- a/apps/keymaps/keymap-m3.c +++ b/apps/keymaps/keymap-m3.c | |||
@@ -162,6 +162,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
162 | { ACTION_PS_TOGGLE_MODE, BUTTON_MODE, BUTTON_NONE }, | 162 | { ACTION_PS_TOGGLE_MODE, BUTTON_MODE, BUTTON_NONE }, |
163 | { ACTION_PS_RESET, BUTTON_REC, BUTTON_NONE }, | 163 | { ACTION_PS_RESET, BUTTON_REC, BUTTON_NONE }, |
164 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, | 164 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, |
165 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
166 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
165 | 167 | ||
166 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 168 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
167 | }; /* button_context_pitchscreen */ | 169 | }; /* button_context_pitchscreen */ |
@@ -178,6 +180,8 @@ static const struct button_mapping remote_button_context_pitchscreen[] = { | |||
178 | { ACTION_PS_TOGGLE_MODE, BUTTON_RC_MODE, BUTTON_NONE }, | 180 | { ACTION_PS_TOGGLE_MODE, BUTTON_RC_MODE, BUTTON_NONE }, |
179 | { ACTION_PS_RESET, BUTTON_RC_REC, BUTTON_NONE }, | 181 | { ACTION_PS_RESET, BUTTON_RC_REC, BUTTON_NONE }, |
180 | { ACTION_PS_EXIT, BUTTON_RC_PLAY, BUTTON_NONE }, | 182 | { ACTION_PS_EXIT, BUTTON_RC_PLAY, BUTTON_NONE }, |
183 | { ACTION_PS_SLOWER, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, | ||
184 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
181 | 185 | ||
182 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 186 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
183 | }; /* remote_button_context_pitchscreen */ | 187 | }; /* remote_button_context_pitchscreen */ |
diff --git a/apps/keymaps/keymap-meizu-m6sl.c b/apps/keymaps/keymap-meizu-m6sl.c index ec19dd63a8..0741f632b7 100644 --- a/apps/keymaps/keymap-meizu-m6sl.c +++ b/apps/keymaps/keymap-meizu-m6sl.c | |||
@@ -227,6 +227,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
227 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 227 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
228 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, | 228 | { ACTION_PS_RESET, BUTTON_PLAY, BUTTON_NONE }, |
229 | { ACTION_PS_EXIT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, | 229 | { ACTION_PS_EXIT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, |
230 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
231 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
230 | 232 | ||
231 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 233 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
232 | }; /* button_context_pitchcreen */ | 234 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-mr100.c b/apps/keymaps/keymap-mr100.c index f9bb8c2419..4f178b7793 100644 --- a/apps/keymaps/keymap-mr100.c +++ b/apps/keymaps/keymap-mr100.c | |||
@@ -237,6 +237,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
237 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 237 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
238 | { ACTION_PS_RESET, BUTTON_DISPLAY, BUTTON_NONE }, | 238 | { ACTION_PS_RESET, BUTTON_DISPLAY, BUTTON_NONE }, |
239 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, | 239 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, |
240 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
241 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
240 | 242 | ||
241 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 243 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
242 | }; /* button_context_pitchcreen */ | 244 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-sa9200.c b/apps/keymaps/keymap-sa9200.c index 3091ec6156..c77f3e9bb4 100644 --- a/apps/keymaps/keymap-sa9200.c +++ b/apps/keymaps/keymap-sa9200.c | |||
@@ -240,6 +240,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, | 240 | { ACTION_PS_TOGGLE_MODE, BUTTON_MENU, BUTTON_NONE }, |
241 | { ACTION_PS_RESET, BUTTON_RIGHT, BUTTON_NONE }, | 241 | { ACTION_PS_RESET, BUTTON_RIGHT, BUTTON_NONE }, |
242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, | 242 | { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, |
243 | { ACTION_PS_SLOWER, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE }, | ||
244 | { ACTION_PS_FASTER, BUTTON_FFWD|BUTTON_REPEAT, BUTTON_NONE }, | ||
243 | 245 | ||
244 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 246 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
245 | }; /* button_context_pitchcreen */ | 247 | }; /* button_context_pitchcreen */ |
diff --git a/apps/keymaps/keymap-touchscreen.c b/apps/keymaps/keymap-touchscreen.c index 70009794a5..b285446546 100644 --- a/apps/keymaps/keymap-touchscreen.c +++ b/apps/keymaps/keymap-touchscreen.c | |||
@@ -206,6 +206,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
206 | { ACTION_PS_TOGGLE_MODE, BUTTON_BOTTOMRIGHT, BUTTON_NONE }, | 206 | { ACTION_PS_TOGGLE_MODE, BUTTON_BOTTOMRIGHT, BUTTON_NONE }, |
207 | { ACTION_PS_RESET, BUTTON_CENTER, BUTTON_NONE }, | 207 | { ACTION_PS_RESET, BUTTON_CENTER, BUTTON_NONE }, |
208 | { ACTION_PS_EXIT, BUTTON_TOPLEFT, BUTTON_NONE }, | 208 | { ACTION_PS_EXIT, BUTTON_TOPLEFT, BUTTON_NONE }, |
209 | { ACTION_PS_SLOWER, BUTTON_MIDLEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
210 | { ACTION_PS_FASTER, BUTTON_MIDRIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
209 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM2|CONTEXT_PITCHSCREEN) | 211 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM2|CONTEXT_PITCHSCREEN) |
210 | }; /* button_context_pitchcreen */ | 212 | }; /* button_context_pitchcreen */ |
211 | 213 | ||
diff --git a/apps/keymaps/keymap-x5.c b/apps/keymaps/keymap-x5.c index 9495bf3306..4401f790d4 100644 --- a/apps/keymaps/keymap-x5.c +++ b/apps/keymaps/keymap-x5.c | |||
@@ -151,6 +151,8 @@ static const struct button_mapping button_context_pitchscreen[] = { | |||
151 | { ACTION_PS_TOGGLE_MODE, BUTTON_SELECT, BUTTON_NONE }, | 151 | { ACTION_PS_TOGGLE_MODE, BUTTON_SELECT, BUTTON_NONE }, |
152 | { ACTION_PS_RESET, BUTTON_POWER, BUTTON_NONE }, | 152 | { ACTION_PS_RESET, BUTTON_POWER, BUTTON_NONE }, |
153 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, | 153 | { ACTION_PS_EXIT, BUTTON_PLAY, BUTTON_NONE }, |
154 | { ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, | ||
155 | { ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, | ||
154 | 156 | ||
155 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 157 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
156 | }; /* button_context_pitchscreen */ | 158 | }; /* button_context_pitchscreen */ |
@@ -166,6 +168,8 @@ static const struct button_mapping remote_button_context_pitchscreen[] = { | |||
166 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RC_FF|BUTTON_REL, BUTTON_NONE }, | 168 | { ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RC_FF|BUTTON_REL, BUTTON_NONE }, |
167 | { ACTION_PS_RESET, BUTTON_RC_MODE, BUTTON_NONE }, | 169 | { ACTION_PS_RESET, BUTTON_RC_MODE, BUTTON_NONE }, |
168 | { ACTION_PS_EXIT, BUTTON_RC_PLAY, BUTTON_NONE }, | 170 | { ACTION_PS_EXIT, BUTTON_RC_PLAY, BUTTON_NONE }, |
171 | { ACTION_PS_SLOWER, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE }, | ||
172 | { ACTION_PS_FASTER, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE }, | ||
169 | 173 | ||
170 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) | 174 | LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) |
171 | }; /* remote_button_context_pitchscreen */ | 175 | }; /* remote_button_context_pitchscreen */ |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index ddddce328a..09cbdbfc09 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -12468,3 +12468,37 @@ | |||
12468 | *: "Prevent Track Skipping" | 12468 | *: "Prevent Track Skipping" |
12469 | </voice> | 12469 | </voice> |
12470 | </phrase> | 12470 | </phrase> |
12471 | <phrase> | ||
12472 | id: LANG_TIMESTRETCH | ||
12473 | desc: timestretch enable | ||
12474 | user: core | ||
12475 | <source> | ||
12476 | *: none | ||
12477 | swcodec: "Timestretch" | ||
12478 | </source> | ||
12479 | <dest> | ||
12480 | *: none | ||
12481 | swcodec: "Timestretch" | ||
12482 | </dest> | ||
12483 | <voice> | ||
12484 | *: none | ||
12485 | swcodec: "Timestretch" | ||
12486 | </voice> | ||
12487 | </phrase> | ||
12488 | <phrase> | ||
12489 | id: LANG_SPEED | ||
12490 | desc: timestretch speed | ||
12491 | user: core | ||
12492 | <source> | ||
12493 | *: none | ||
12494 | swcodec: "Speed" | ||
12495 | </source> | ||
12496 | <dest> | ||
12497 | *: none | ||
12498 | swcodec: "Speed" | ||
12499 | </dest> | ||
12500 | <voice> | ||
12501 | *: none | ||
12502 | swcodec: "Speed" | ||
12503 | </voice> | ||
12504 | </phrase> | ||
diff --git a/apps/menus/sound_menu.c b/apps/menus/sound_menu.c index 70730a1e5a..bfba8171da 100644 --- a/apps/menus/sound_menu.c +++ b/apps/menus/sound_menu.c | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | /*************************************************************************** | 1 | /*************************************************************************** |
3 | * __________ __ ___. | 2 | * __________ __ ___. |
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
@@ -32,6 +31,9 @@ | |||
32 | #include "eq_menu.h" | 31 | #include "eq_menu.h" |
33 | #include "exported_menus.h" | 32 | #include "exported_menus.h" |
34 | #include "menu_common.h" | 33 | #include "menu_common.h" |
34 | #include "splash.h" | ||
35 | #include "kernel.h" | ||
36 | #include "dsp.h" | ||
35 | 37 | ||
36 | /***********************************/ | 38 | /***********************************/ |
37 | /* SOUND MENU */ | 39 | /* SOUND MENU */ |
@@ -57,14 +59,14 @@ MENUITEM_SETTING(treble, &global_settings.treble, | |||
57 | MENUITEM_SETTING(treble_cutoff, &global_settings.treble_cutoff, NULL); | 59 | MENUITEM_SETTING(treble_cutoff, &global_settings.treble_cutoff, NULL); |
58 | #endif | 60 | #endif |
59 | MENUITEM_SETTING(balance, &global_settings.balance, NULL); | 61 | MENUITEM_SETTING(balance, &global_settings.balance, NULL); |
60 | MENUITEM_SETTING(channel_config, &global_settings.channel_config, | 62 | MENUITEM_SETTING(channel_config, &global_settings.channel_config, |
61 | #if CONFIG_CODEC == SWCODEC | 63 | #if CONFIG_CODEC == SWCODEC |
62 | lowlatency_callback | 64 | lowlatency_callback |
63 | #else | 65 | #else |
64 | NULL | 66 | NULL |
65 | #endif | 67 | #endif |
66 | ); | 68 | ); |
67 | MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, | 69 | MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, |
68 | #if CONFIG_CODEC == SWCODEC | 70 | #if CONFIG_CODEC == SWCODEC |
69 | lowlatency_callback | 71 | lowlatency_callback |
70 | #else | 72 | #else |
@@ -86,7 +88,21 @@ MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, | |||
86 | MAKE_MENU(crossfeed_menu,ID2P(LANG_CROSSFEED), NULL, Icon_NOICON, | 88 | MAKE_MENU(crossfeed_menu,ID2P(LANG_CROSSFEED), NULL, Icon_NOICON, |
87 | &crossfeed, &crossfeed_direct_gain, &crossfeed_cross_gain, | 89 | &crossfeed, &crossfeed_direct_gain, &crossfeed_cross_gain, |
88 | &crossfeed_hf_attenuation, &crossfeed_hf_cutoff); | 90 | &crossfeed_hf_attenuation, &crossfeed_hf_cutoff); |
89 | 91 | ||
92 | static int timestretch_callback(int action,const struct menu_item_ex *this_item) | ||
93 | { | ||
94 | switch (action) | ||
95 | { | ||
96 | case ACTION_EXIT_MENUITEM: /* on exit */ | ||
97 | if (global_settings.timestretch_enabled && !dsp_timestretch_enabled()) | ||
98 | splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); | ||
99 | break; | ||
100 | } | ||
101 | lowlatency_callback(action, this_item); | ||
102 | return action; | ||
103 | } | ||
104 | MENUITEM_SETTING(timestretch_enabled, | ||
105 | &global_settings.timestretch_enabled, timestretch_callback); | ||
90 | MENUITEM_SETTING(dithering_enabled, | 106 | MENUITEM_SETTING(dithering_enabled, |
91 | &global_settings.dithering_enabled, lowlatency_callback); | 107 | &global_settings.dithering_enabled, lowlatency_callback); |
92 | #endif | 108 | #endif |
@@ -120,7 +136,8 @@ MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, Icon_Audio, | |||
120 | #endif | 136 | #endif |
121 | &balance,&channel_config,&stereo_width | 137 | &balance,&channel_config,&stereo_width |
122 | #if CONFIG_CODEC == SWCODEC | 138 | #if CONFIG_CODEC == SWCODEC |
123 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled | 139 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled |
140 | ,×tretch_enabled | ||
124 | #endif | 141 | #endif |
125 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 142 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
126 | ,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength | 143 | ,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength |
diff --git a/apps/settings.c b/apps/settings.c index 6652141f9c..9594bd164e 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -936,6 +936,7 @@ void settings_apply(bool read_disk) | |||
936 | } | 936 | } |
937 | 937 | ||
938 | dsp_dither_enable(global_settings.dithering_enabled); | 938 | dsp_dither_enable(global_settings.dithering_enabled); |
939 | dsp_timestretch_enable(global_settings.timestretch_enabled); | ||
939 | #endif | 940 | #endif |
940 | 941 | ||
941 | #ifdef HAVE_SPDIF_POWER | 942 | #ifdef HAVE_SPDIF_POWER |
diff --git a/apps/settings.h b/apps/settings.h index 3b13ff8e6b..6ccaeed92e 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -374,6 +374,7 @@ struct user_settings | |||
374 | int keyclick; /* keyclick volume */ | 374 | int keyclick; /* keyclick volume */ |
375 | int keyclick_repeats; /* keyclick on repeats */ | 375 | int keyclick_repeats; /* keyclick on repeats */ |
376 | bool dithering_enabled; | 376 | bool dithering_enabled; |
377 | bool timestretch_enabled; | ||
377 | #endif /* CONFIG_CODEC == SWCODEC */ | 378 | #endif /* CONFIG_CODEC == SWCODEC */ |
378 | 379 | ||
379 | #ifdef HAVE_RECORDING | 380 | #ifdef HAVE_RECORDING |
diff --git a/apps/settings_list.c b/apps/settings_list.c index 0485ec4ab3..74e2cab3cd 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -1181,6 +1181,10 @@ const struct settings_list settings[] = { | |||
1181 | /* dithering */ | 1181 | /* dithering */ |
1182 | OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false, | 1182 | OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false, |
1183 | "dithering enabled", dsp_dither_enable), | 1183 | "dithering enabled", dsp_dither_enable), |
1184 | |||
1185 | /* timestretch */ | ||
1186 | OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false, | ||
1187 | "timestretch enabled", dsp_timestretch_enable), | ||
1184 | #endif | 1188 | #endif |
1185 | #ifdef HAVE_WM8758 | 1189 | #ifdef HAVE_WM8758 |
1186 | SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF, | 1190 | SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF, |
diff --git a/apps/tdspeed.c b/apps/tdspeed.c new file mode 100644 index 0000000000..67f749f6c3 --- /dev/null +++ b/apps/tdspeed.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org> | ||
11 | * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include <inttypes.h> | ||
24 | #include <stddef.h> | ||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | #include "buffer.h" | ||
28 | #include "debug.h" | ||
29 | #include "system.h" | ||
30 | #include "tdspeed.h" | ||
31 | |||
32 | #define assert(cond) | ||
33 | |||
34 | #define MIN_RATE 8000 | ||
35 | #define MAX_RATE 48000 /* double buffer for double rate */ | ||
36 | #define MINFREQ 100 | ||
37 | |||
38 | #define FIXED_BUFSIZE 3072 /* 48KHz factor 3.0 */ | ||
39 | |||
40 | struct tdspeed_state_s | ||
41 | { | ||
42 | bool stereo; | ||
43 | int32_t shift_max; /* maximum displacement on a frame */ | ||
44 | int32_t src_step; /* source window pace */ | ||
45 | int32_t dst_step; /* destination window pace */ | ||
46 | int32_t dst_order; /* power of two for dst_step */ | ||
47 | int32_t ovl_shift; /* overlap buffer frame shift */ | ||
48 | int32_t ovl_size; /* overlap buffer used size */ | ||
49 | int32_t ovl_space; /* overlap buffer size */ | ||
50 | int32_t *ovl_buff[2]; /* overlap buffer */ | ||
51 | }; | ||
52 | static struct tdspeed_state_s tdspeed_state; | ||
53 | |||
54 | static int32_t *overlap_buffer[2] = { NULL, NULL }; | ||
55 | static int32_t *outbuf[2] = { NULL, NULL }; | ||
56 | |||
57 | bool tdspeed_init(int samplerate, bool stereo, int factor) | ||
58 | { | ||
59 | struct tdspeed_state_s *st = &tdspeed_state; | ||
60 | int src_frame_sz; | ||
61 | |||
62 | /* Allocate buffers */ | ||
63 | if (overlap_buffer[0] == NULL) | ||
64 | overlap_buffer[0] = (int32_t *) buffer_alloc(FIXED_BUFSIZE * sizeof(int32_t)); | ||
65 | if (overlap_buffer[1] == NULL) | ||
66 | overlap_buffer[1] = (int32_t *) buffer_alloc(FIXED_BUFSIZE * sizeof(int32_t)); | ||
67 | if (outbuf[0] == NULL) | ||
68 | outbuf[0] = (int32_t *) buffer_alloc(TDSPEED_OUTBUFSIZE * sizeof(int32_t)); | ||
69 | if (outbuf[1] == NULL) | ||
70 | outbuf[1] = (int32_t *) buffer_alloc(TDSPEED_OUTBUFSIZE * sizeof(int32_t)); | ||
71 | |||
72 | /* Check parameters */ | ||
73 | if (factor == 100) | ||
74 | return false; | ||
75 | if (samplerate < MIN_RATE || samplerate > MAX_RATE) | ||
76 | return false; | ||
77 | if (factor < SPEED_MIN || factor > SPEED_MAX) | ||
78 | return false; | ||
79 | |||
80 | st->stereo = stereo; | ||
81 | st->dst_step = samplerate / MINFREQ; | ||
82 | |||
83 | if (factor > 100) | ||
84 | st->dst_step = st->dst_step * 100 / factor; | ||
85 | st->dst_order = 1; | ||
86 | |||
87 | while (st->dst_step >>= 1) | ||
88 | st->dst_order++; | ||
89 | st->dst_step = (1 << st->dst_order); | ||
90 | st->src_step = st->dst_step * factor / 100; | ||
91 | st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step; | ||
92 | |||
93 | src_frame_sz = st->shift_max + st->dst_step; | ||
94 | if (st->dst_step > st->src_step) | ||
95 | src_frame_sz += st->dst_step - st->src_step; | ||
96 | st->ovl_space = ((src_frame_sz - 2)/st->src_step) * st->src_step | ||
97 | + src_frame_sz; | ||
98 | if (st->src_step > st->dst_step) | ||
99 | st->ovl_space += 2*st->src_step - st->dst_step; | ||
100 | |||
101 | if (st->ovl_space > FIXED_BUFSIZE) | ||
102 | st->ovl_space = FIXED_BUFSIZE; | ||
103 | |||
104 | st->ovl_size = 0; | ||
105 | st->ovl_shift = 0; | ||
106 | |||
107 | st->ovl_buff[0] = overlap_buffer[0]; | ||
108 | if (stereo) | ||
109 | st->ovl_buff[1] = overlap_buffer[1]; | ||
110 | else | ||
111 | st->ovl_buff[1] = st->ovl_buff[0]; | ||
112 | |||
113 | return true; | ||
114 | } | ||
115 | |||
116 | static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], | ||
117 | int data_len, int last, int out_size) | ||
118 | /* data_len in samples */ | ||
119 | { | ||
120 | struct tdspeed_state_s *st = &tdspeed_state; | ||
121 | int32_t *curr, *prev, *dest[2], *d; | ||
122 | int32_t i, j, next_frame, prev_frame, shift, src_frame_sz; | ||
123 | bool stereo = buf_in[0] != buf_in[1]; | ||
124 | assert(stereo == st->stereo); | ||
125 | |||
126 | src_frame_sz = st->shift_max + st->dst_step; | ||
127 | if (st->dst_step > st->src_step) | ||
128 | src_frame_sz += st->dst_step - st->src_step; | ||
129 | |||
130 | /* deal with overlap data first, if any */ | ||
131 | if (st->ovl_size) | ||
132 | { | ||
133 | int32_t have, copy, steps; | ||
134 | have = st->ovl_size; | ||
135 | if (st->ovl_shift > 0) | ||
136 | have -= st->ovl_shift; | ||
137 | /* append just enough data to have all of the overlap buffer consumed */ | ||
138 | steps = (have - 1) / st->src_step; | ||
139 | copy = steps * st->src_step + src_frame_sz - have; | ||
140 | if (copy < src_frame_sz - st->dst_step) | ||
141 | copy += st->src_step; /* one more step to allow for pregap data */ | ||
142 | if (copy > data_len) copy = data_len; | ||
143 | assert(st->ovl_size +copy <= FIXED_BUFSIZE); | ||
144 | memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0], | ||
145 | copy * sizeof(int32_t)); | ||
146 | if (stereo) | ||
147 | memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1], | ||
148 | copy * sizeof(int32_t)); | ||
149 | if (!last && have + copy < src_frame_sz) | ||
150 | { | ||
151 | /* still not enough to process at least one frame */ | ||
152 | st->ovl_size += copy; | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* recursively call ourselves to process the overlap buffer */ | ||
157 | have = st->ovl_size; | ||
158 | st->ovl_size = 0; | ||
159 | if (copy == data_len) | ||
160 | { | ||
161 | assert( (have+copy) <= FIXED_BUFSIZE); | ||
162 | return tdspeed_apply(buf_out, st->ovl_buff, have+copy, last, | ||
163 | out_size); | ||
164 | } | ||
165 | assert( (have+copy) <= FIXED_BUFSIZE); | ||
166 | i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, -1, out_size); | ||
167 | dest[0] = buf_out[0] + i; | ||
168 | dest[1] = buf_out[1] + i; | ||
169 | |||
170 | /* readjust pointers to account for data already consumed */ | ||
171 | next_frame = copy - src_frame_sz + st->src_step; | ||
172 | prev_frame = next_frame - st->ovl_shift; | ||
173 | } | ||
174 | else | ||
175 | { | ||
176 | dest[0] = buf_out[0]; | ||
177 | dest[1] = buf_out[1]; | ||
178 | next_frame = prev_frame = 0; | ||
179 | if (st->ovl_shift > 0) | ||
180 | next_frame += st->ovl_shift; | ||
181 | else | ||
182 | prev_frame += -st->ovl_shift; | ||
183 | } | ||
184 | st->ovl_shift = 0; | ||
185 | |||
186 | /* process all complete frames */ | ||
187 | while (data_len - next_frame >= src_frame_sz) | ||
188 | { | ||
189 | /* find frame overlap by autocorelation */ | ||
190 | int64_t min_delta = ~(1ll << 63); /* most positive */ | ||
191 | shift = 0; | ||
192 | #define INC1 8 | ||
193 | #define INC2 32 | ||
194 | /* Power of 2 of a 28bit number requires 56bits, can accumulate | ||
195 | 256times in a 64bit variable. */ | ||
196 | assert(st->dst_step / INC2 <= 256); | ||
197 | assert(next_frame + st->shift_max - 1 + st->dst_step-1 < data_len); | ||
198 | assert(prev_frame + st->dst_step - 1 < data_len); | ||
199 | for (i = 0; i < st->shift_max; i += INC1) | ||
200 | { | ||
201 | int64_t delta = 0; | ||
202 | curr = buf_in[0] + next_frame + i; | ||
203 | prev = buf_in[0] + prev_frame; | ||
204 | for (j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2) | ||
205 | { | ||
206 | int32_t diff = *curr - *prev; | ||
207 | delta += (int64_t)diff * diff; | ||
208 | if (delta >= min_delta) | ||
209 | goto skip; | ||
210 | } | ||
211 | if (stereo) | ||
212 | { | ||
213 | curr = buf_in[1] +next_frame + i; | ||
214 | prev = buf_in[1] +prev_frame; | ||
215 | for (j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2) | ||
216 | { | ||
217 | int32_t diff = *curr - *prev; | ||
218 | delta += (int64_t)diff * diff; | ||
219 | if (delta >= min_delta) | ||
220 | goto skip; | ||
221 | } | ||
222 | } | ||
223 | min_delta = delta; | ||
224 | shift = i; | ||
225 | skip:; | ||
226 | } | ||
227 | |||
228 | /* overlap fading-out previous frame with fading-in current frame */ | ||
229 | curr = buf_in[0] + next_frame + shift; | ||
230 | prev = buf_in[0] + prev_frame; | ||
231 | d = dest[0]; | ||
232 | assert(next_frame + shift + st->dst_step - 1 < data_len); | ||
233 | assert(prev_frame + st->dst_step - 1 < data_len); | ||
234 | assert(dest[0] - buf_out[0] + st->dst_step - 1 < out_size); | ||
235 | for (i = 0, j = st->dst_step; j; i++, j--) | ||
236 | { | ||
237 | *d++ = (*curr++ * (int64_t)i | ||
238 | + *prev++ * (int64_t)j) >> st->dst_order; | ||
239 | } | ||
240 | dest[0] = d; | ||
241 | if (stereo) | ||
242 | { | ||
243 | curr = buf_in[1] +next_frame + shift; | ||
244 | prev = buf_in[1] +prev_frame; | ||
245 | d = dest[1]; | ||
246 | for (i = 0, j = st->dst_step; j; i++, j--) | ||
247 | { | ||
248 | assert(d < buf_out[1] +out_size); | ||
249 | *d++ = (*curr++ * (int64_t) i | ||
250 | + *prev++ * (int64_t) j) >> st->dst_order; | ||
251 | } | ||
252 | dest[1] = d; | ||
253 | } | ||
254 | |||
255 | /* adjust pointers for next frame */ | ||
256 | prev_frame = next_frame + shift + st->dst_step; | ||
257 | next_frame += st->src_step; | ||
258 | |||
259 | /* here next_frame - prev_frame = src_step - dst_step - shift */ | ||
260 | assert(next_frame - prev_frame == st->src_step - st->dst_step - shift); | ||
261 | } | ||
262 | |||
263 | /* now deal with remaining partial frames */ | ||
264 | if (last == -1) | ||
265 | { | ||
266 | /* special overlap buffer processing: remember frame shift only */ | ||
267 | st->ovl_shift = next_frame - prev_frame; | ||
268 | } | ||
269 | else if (last != 0) | ||
270 | { | ||
271 | /* last call: purge all remaining data to output buffer */ | ||
272 | i = data_len -prev_frame; | ||
273 | assert(dest[0] +i <= buf_out[0] +out_size); | ||
274 | memcpy(dest[0], buf_in[0] +prev_frame, i * sizeof(int32_t)); | ||
275 | dest[0] += i; | ||
276 | if (stereo) | ||
277 | { | ||
278 | assert(dest[1] +i <= buf_out[1] +out_size); | ||
279 | memcpy(dest[1], buf_in[1] +prev_frame, i * sizeof(int32_t)); | ||
280 | dest[1] += i; | ||
281 | } | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | /* preserve remaining data + needed overlap data for next call */ | ||
286 | st->ovl_shift = next_frame - prev_frame; | ||
287 | i = (st->ovl_shift < 0) ? next_frame : prev_frame; | ||
288 | st->ovl_size = data_len - i; | ||
289 | assert(st->ovl_size <= FIXED_BUFSIZE); | ||
290 | memcpy(st->ovl_buff[0], buf_in[0]+i, st->ovl_size * sizeof(int32_t)); | ||
291 | if (stereo) | ||
292 | memcpy(st->ovl_buff[1], buf_in[1]+i, st->ovl_size * sizeof(int32_t)); | ||
293 | } | ||
294 | |||
295 | return dest[0] - buf_out[0]; | ||
296 | } | ||
297 | |||
298 | long tdspeed_est_output_size() | ||
299 | { | ||
300 | return TDSPEED_OUTBUFSIZE; | ||
301 | } | ||
302 | |||
303 | long tdspeed_est_input_size(long size) | ||
304 | { | ||
305 | struct tdspeed_state_s *st = &tdspeed_state; | ||
306 | size = (size -st->ovl_size) *st->src_step / st->dst_step; | ||
307 | if (size < 0) | ||
308 | size = 0; | ||
309 | return size; | ||
310 | } | ||
311 | |||
312 | int tdspeed_doit(int32_t *src[], int count) | ||
313 | { | ||
314 | count = tdspeed_apply( (int32_t *[2]) { outbuf[0], outbuf[1] }, | ||
315 | src, count, 0, TDSPEED_OUTBUFSIZE); | ||
316 | src[0] = outbuf[0]; | ||
317 | src[1] = outbuf[1]; | ||
318 | return count; | ||
319 | } | ||
diff --git a/apps/tdspeed.h b/apps/tdspeed.h new file mode 100644 index 0000000000..6d7cecdcdf --- /dev/null +++ b/apps/tdspeed.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org> | ||
11 | * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #ifndef _TDSPEED_H | ||
24 | #define _TDSPEED_H | ||
25 | |||
26 | #define TDSPEED_OUTBUFSIZE 4096 | ||
27 | |||
28 | bool tdspeed_init(int samplerate, bool stereo, int factor); | ||
29 | long tdspeed_est_output_size(void); | ||
30 | long tdspeed_est_input_size(long size); | ||
31 | int tdspeed_doit(int32_t *src[], int count); | ||
32 | |||
33 | #define SPEED_MAX 250 | ||
34 | #define SPEED_MIN 35 | ||
35 | |||
36 | #endif | ||
diff --git a/docs/CREDITS b/docs/CREDITS index 99ddc3a763..cb491f1ab4 100644 --- a/docs/CREDITS +++ b/docs/CREDITS | |||
@@ -468,6 +468,8 @@ Michael Carr | |||
468 | Eric Clayton | 468 | Eric Clayton |
469 | Marko Pahlke | 469 | Marko Pahlke |
470 | Vytenis Sabelka | 470 | Vytenis Sabelka |
471 | Nicolas Pitre | ||
472 | Benedikt Goos | ||
471 | 473 | ||
472 | The libmad team | 474 | The libmad team |
473 | The wavpack team | 475 | The wavpack team |
diff --git a/manual/configure_rockbox/sound_settings.tex b/manual/configure_rockbox/sound_settings.tex index b699eeb821..ef0a0f31a8 100644 --- a/manual/configure_rockbox/sound_settings.tex +++ b/manual/configure_rockbox/sound_settings.tex | |||
@@ -421,3 +421,13 @@ and not easily noticable. | |||
421 | Rockbox uses highpass triangular distribution noise as the dithering noise | 421 | Rockbox uses highpass triangular distribution noise as the dithering noise |
422 | source, and a third order noise shaper. | 422 | source, and a third order noise shaper. |
423 | } | 423 | } |
424 | |||
425 | \opt{swcodec}{ | ||
426 | \section{Timestretch} | ||
427 | Enabling \setting{Timestretch} allows you to change the playback speed without it | ||
428 | affecting the pitch of the recording. | ||
429 | |||
430 | After enabling this feature and rebooting, you can access this via the \setting{Pitch Screen}. | ||
431 | This function is intended for speech playback and may significantly dilute your listening | ||
432 | experience with more complex audio. | ||
433 | } | ||
diff --git a/manual/rockbox_interface/wps.tex b/manual/rockbox_interface/wps.tex index 6807fd886b..6780999a7d 100644 --- a/manual/rockbox_interface/wps.tex +++ b/manual/rockbox_interface/wps.tex | |||
@@ -239,44 +239,78 @@ Delete the currently playing file. | |||
239 | \nopt{player}{ | 239 | \nopt{player}{ |
240 | \subsubsection{\label{sec:pitchscreen}Pitch} | 240 | \subsubsection{\label{sec:pitchscreen}Pitch} |
241 | 241 | ||
242 | The \setting{Pitch Screen} allows you to change the pitch and (at the same | 242 | The \setting{Pitch Screen} allows you to change the pitch and the playback |
243 | time) the playback speed of your \dap. The pitch value can be adjusted | 243 | speed of your \dap. The pitch value can be adjusted between 50\% and 200\%. |
244 | between 50\% and 200\%. 50\% means half the normal playback speed and the | 244 | 50\% means half the normal playback speed and the pitch that is an octave lower |
245 | pitch that is an octave lower than the normal pitch. 200\% means double | 245 | than the normal pitch. 200\% means double playback speed and the pitch that |
246 | playback speed and the pitch that is an octave higher than the normal pitch. | 246 | is an octave higher than the normal pitch. |
247 | It is not possible to change the pitch without changing the playback speed and | 247 | |
248 | vice versa. Changing the pitch can be done in two modes: procentual and | 248 | \opt{masf}{ |
249 | semitone. Initially (after the \dap{} is switched on), procentual mode | 249 | Changing the pitch can be done in two modes: procentual and semitone. |
250 | is active. | 250 | Initially (after the \dap{} is switched on), procentual mode is active. |
251 | 251 | ||
252 | \begin{table} | 252 | \begin{table} |
253 | \begin{btnmap}{}{} | 253 | \begin{btnmap}{}{} |
254 | \ActionPsToggleMode | 254 | \ActionPsToggleMode |
255 | & Toggle pitch changing mode \\ | 255 | & Toggle pitch changing mode \\ |
256 | % | 256 | % |
257 | \ActionPsIncSmall{} / \ActionPsDecSmall | 257 | \ActionPsIncSmall{} / \ActionPsDecSmall |
258 | & Increase / Decrease pitch by 0.1\% (in procentual mode) or a semitone | 258 | & Increase / Decrease pitch by 0.1\% (in procentual mode) or a semitone |
259 | (in semitone mode)\\ | 259 | (in semitone mode)\\ |
260 | % | 260 | % |
261 | \ActionPsIncBig{} / \ActionPsDecBig | 261 | \ActionPsIncBig{} / \ActionPsDecBig |
262 | & Increase / Decrease pitch by 1\% (in procentual mode) or a semitone | 262 | & Increase / Decrease pitch by 1\% (in procentual mode) or a semitone |
263 | (in semitone mode)\\ | 263 | (in semitone mode)\\ |
264 | % | 264 | % |
265 | \ActionPsNudgeRight{} / \ActionPsNudgeLeft | 265 | \ActionPsNudgeLeft{} / \ActionPsNudgeRight |
266 | & Temporarily increase / decrease pitch by 2.0\% \\ | 266 | & Temporarily change pitch by 2.0\% (beatmatch) \\ |
267 | % | 267 | % |
268 | \ActionPsReset | 268 | \ActionPsReset |
269 | & Reset pitch to 100\% \\ | 269 | & Reset pitch to 100\% \\ |
270 | % | 270 | % |
271 | \ActionPsExit | 271 | \ActionPsExit |
272 | & Leave the Pitch Screen \\ | 272 | & Leave the Pitch Screen \\ |
273 | % | 273 | % |
274 | \end{btnmap} | 274 | \end{btnmap} |
275 | \end{table} | 275 | \end{table} |
276 | 276 | ||
277 | \opt{MASCODEC}{ | ||
278 | \warn{Changing the pitch can cause audible 'Artifacts' or 'Dropouts'.} | 277 | \warn{Changing the pitch can cause audible 'Artifacts' or 'Dropouts'.} |
279 | } | 278 | } |
279 | |||
280 | \opt{swcodec}{ | ||
281 | Changing the pitch can be done in three modes: procentual, semitone and | ||
282 | timestretch. Initially (after the \dap{} is switched on), procentual mode is active. | ||
283 | |||
284 | Timestretch mode allows you to change the playback speed of your recording without | ||
285 | affecting the pitch, and vice versa. To access this you must enable the \setting{Timestretch} | ||
286 | option in \setting{Sound Settings} and reboot. | ||
287 | |||
288 | \begin{table} | ||
289 | \begin{btnmap}{}{} | ||
290 | \ActionPsToggleMode | ||
291 | & Toggle pitch changing mode \\ | ||
292 | % | ||
293 | \ActionPsIncSmall{} / \ActionPsDecSmall | ||
294 | & Increase / Decrease pitch by 0.1\% (in procentual mode) or a semitone | ||
295 | (in semitone mode)\\ | ||
296 | % | ||
297 | \ActionPsIncBig{} / \ActionPsDecBig | ||
298 | & Increase / Decrease pitch by 1\% (in procentual mode) or a semitone | ||
299 | (in semitone mode)\\ | ||
300 | % | ||
301 | \ActionPsNudgeLeft{} / \ActionPsNudgeRight | ||
302 | & Temporarily change pitch by 2.0\% (beatmatch), or modify speed (in timestretch mode) \\ | ||
303 | % | ||
304 | \ActionPsReset | ||
305 | & Reset pitch and speed to 100\% \\ | ||
306 | % | ||
307 | \ActionPsExit | ||
308 | & Leave the Pitch Screen \\ | ||
309 | % | ||
310 | \end{btnmap} | ||
311 | \end{table} | ||
312 | } | ||
313 | |||
280 | } | 314 | } |
281 | 315 | ||
282 | %********************QUICKSCREENS*********************************************** | 316 | %********************QUICKSCREENS*********************************************** |