Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 18043) +++ apps/lang/english.lang (working copy) @@ -11834,4 +11834,17 @@ *: "Skip Track" - + + id: LANG_SPEED + desc: time-domain speed compress/stretch + user: + + *: "Speed" + + + *: "Speed" + + + *: "Speed" + + Index: apps/settings.c =================================================================== --- apps/settings.c (revision 18043) +++ apps/settings.c (working copy) @@ -913,6 +913,7 @@ } dsp_dither_enable(global_settings.dithering_enabled); + dsp_set_speed(global_settings.sound_speed); #endif #ifdef HAVE_SPDIF_POWER Index: apps/settings.h =================================================================== --- apps/settings.h (revision 18043) +++ apps/settings.h (working copy) @@ -630,6 +630,7 @@ int eq_band4_gain; /* +/- dB */ bool dithering_enabled; + int sound_speed; #endif Index: apps/menus/sound_menu.c =================================================================== --- apps/menus/sound_menu.c (revision 18043) +++ apps/menus/sound_menu.c (working copy) @@ -89,6 +89,8 @@ MENUITEM_SETTING(dithering_enabled, &global_settings.dithering_enabled, lowlatency_callback); + MENUITEM_SETTING(sound_speed, &global_settings.sound_speed, + lowlatency_callback); #endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) @@ -116,7 +118,7 @@ #endif &balance,&channel_config,&stereo_width #if CONFIG_CODEC == SWCODEC - ,&crossfeed_menu, &equalizer_menu, &dithering_enabled + ,&crossfeed_menu, &equalizer_menu, &dithering_enabled, &sound_speed #endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) ,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength Index: apps/dsp.c =================================================================== --- apps/dsp.c (revision 18043) +++ apps/dsp.c (working copy) @@ -32,6 +32,7 @@ #include "replaygain.h" #include "misc.h" #include "debug.h" +#include "tdspeed.h" /* 16-bit samples are scaled based on these constants. The shift should be * no more than 15. @@ -41,8 +42,14 @@ #define NATIVE_DEPTH 16 /* If the buffer sizes change, check the assembly code! */ -#define SAMPLE_BUF_COUNT 256 -#define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ +#define SMALL_SAMPLE_BUF_COUNT 256 +#define SMALL_RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ +#define BIG_SAMPLE_BUF_COUNT 4096 +#define BIG_RESAMPLE_BUF_COUNT (4096 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ +int sample_buf_count; +int resample_buf_count; +#define SAMPLE_BUF_COUNT sample_buf_count +#define RESAMPLE_BUF_COUNT resample_buf_count #define DEFAULT_GAIN 0x01000000 #define SAMPLE_BUF_LEFT_CHANNEL 0 #define SAMPLE_BUF_RIGHT_CHANNEL (SAMPLE_BUF_COUNT/2) @@ -163,6 +170,8 @@ int sample_depth; int sample_bytes; int stereo_mode; + bool tdspeed_active; + int tdspeed_factor; /* % */ int frac_bits; #ifdef HAVE_SW_TONE_CONTROLS /* Filter struct for software bass/treble controls */ @@ -226,8 +235,12 @@ * of copying needed is minimized for that case. */ -int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; -static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; +int32_t small_sample_buf[SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR; +static int32_t small_resample_buf[SMALL_RESAMPLE_BUF_COUNT] IBSS_ATTR; +int32_t big_sample_buf[BIG_SAMPLE_BUF_COUNT]; +static int32_t big_resample_buf[BIG_RESAMPLE_BUF_COUNT]; +int32_t *sample_buf; +static int32_t *resample_buf; #if 0 /* Clip sample to arbitrary limits where range > 0 and min + range = max */ @@ -264,6 +277,30 @@ audio_dsp.codec_frequency); } +void tdspeed_setup(struct dsp_config *dspc) +{ + if(dspc == &dsp_conf[CODEC_IDX_AUDIO]) { +#if 0 + mylog("tdspeed_setup: CODEC_IDX_AUDIO, factor %d, %d, %d\n", + dspc->tdspeed_factor, dspc->codec_frequency, + dspc->stereo_mode != STEREO_MONO); +#endif + if(dspc->tdspeed_factor == 0 || dspc->tdspeed_factor == 100) + dspc->tdspeed_active = false; + else dspc->tdspeed_active + = tdspeed_init(dspc->codec_frequency == 0 ? NATIVE_FREQUENCY + : dspc->codec_frequency, + dspc->stereo_mode != STEREO_MONO, + dspc->tdspeed_factor); + } +} + +void dsp_set_speed(int percent) +{ + dsp_conf[CODEC_IDX_AUDIO].tdspeed_factor = percent; + tdspeed_setup(&dsp_conf[CODEC_IDX_AUDIO]); +} + /* Convert count samples to the internal format, if needed. Updates src * to point past the samples "consumed" and dst is set to point to the * samples to consume. Note that for mono, dst[0] equals dst[1], as there @@ -1137,6 +1174,9 @@ dsp->input_samples(samples, src, tmp); + if(dsp->tdspeed_active) + samples = tdspeed_doit(tmp, samples); + if (dsp->apply_gain) dsp->apply_gain(samples, &dsp->data, tmp); @@ -1188,6 +1228,19 @@ /* dsp_input_size MUST be called afterwards */ int dsp_output_count(struct dsp_config *dsp, int count) { + if(!dsp->tdspeed_active) { + sample_buf = small_sample_buf; + resample_buf = small_resample_buf; + sample_buf_count = SMALL_SAMPLE_BUF_COUNT; + resample_buf_count = SMALL_RESAMPLE_BUF_COUNT; + } else { + sample_buf = big_sample_buf; + resample_buf = big_resample_buf; + sample_buf_count = BIG_SAMPLE_BUF_COUNT; + resample_buf_count = BIG_RESAMPLE_BUF_COUNT; + } + if(dsp->tdspeed_active) + count = tdspeed_est_output_size(count); if (dsp->resample) { count = (int)(((unsigned long)count * NATIVE_FREQUENCY @@ -1221,6 +1274,9 @@ dsp->data.resample_data.delta) >> 16); } + if(dsp->tdspeed_active) + count = tdspeed_est_input_size(count); + return count; } @@ -1268,6 +1324,7 @@ dsp->frequency = dsp->codec_frequency; resampler_new_delta(dsp); + tdspeed_setup(dsp); break; case DSP_SET_SAMPLE_DEPTH: @@ -1297,6 +1354,7 @@ dsp->stereo_mode = value; dsp->data.num_channels = value == STEREO_MONO ? 1 : 2; dsp_update_functions(dsp); + tdspeed_setup(dsp); break; case DSP_RESET: @@ -1321,6 +1379,7 @@ dsp_update_functions(dsp); resampler_new_delta(dsp); + tdspeed_setup(dsp); break; case DSP_FLUSH: @@ -1328,6 +1387,7 @@ sizeof (dsp->data.resample_data)); resampler_new_delta(dsp); dither_init(dsp); + tdspeed_setup(dsp); break; case DSP_SET_TRACK_GAIN: Index: apps/dsp.h =================================================================== --- apps/dsp.h (revision 18043) +++ apps/dsp.h (working copy) @@ -165,5 +165,6 @@ int sound_get_pitch(void); int dsp_callback(int msg, intptr_t param); void dsp_dither_enable(bool enable); +void dsp_set_speed(int speed); #endif Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 18043) +++ apps/settings_list.c (working copy) @@ -1100,6 +1100,9 @@ /* dithering */ OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false, "dithering enabled", dsp_dither_enable), + INT_SETTING(0, sound_speed, LANG_SPEED, 100, "speed", + UNIT_INT, 35, 250, 5, + NULL, NULL, dsp_set_speed), #endif #ifdef HAVE_WM8758 SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF, Index: apps/SOURCES =================================================================== --- apps/SOURCES (revision 18043) +++ apps/SOURCES (working copy) @@ -198,3 +198,4 @@ #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD keymaps/keymap-hdd1630.c #endif +tdspeed.c