diff --git a/apps/SOURCES b/apps/SOURCES index 419d24d7a8..abf373e77e 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -201,3 +201,4 @@ keymaps/keymap-hdd1630.c #elif CONFIG_KEYPAD == IAUDIO67_PAD keymaps/keymap-iaudio67.c #endif +tdspeed.c diff --git a/apps/dsp.c b/apps/dsp.c index cbae49ab69..4c1dc1f4e7 100644 --- a/apps/dsp.c +++ b/apps/dsp.c @@ -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 @@ struct dsp_config 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 @@ static bool crossfeed_enabled; * 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 @@ void sound_set_pitch(int permille) 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 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) 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 @@ int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count) /* 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 @@ int dsp_input_count(struct dsp_config *dsp, int count) dsp->data.resample_data.delta) >> 16); } + if(dsp->tdspeed_active) + count = tdspeed_est_input_size(count); + return count; } @@ -1268,6 +1324,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) dsp->frequency = dsp->codec_frequency; resampler_new_delta(dsp); + tdspeed_setup(dsp); break; case DSP_SET_SAMPLE_DEPTH: @@ -1297,6 +1354,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) 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 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) dsp_update_functions(dsp); resampler_new_delta(dsp); + tdspeed_setup(dsp); break; case DSP_FLUSH: @@ -1328,6 +1387,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value) sizeof (dsp->data.resample_data)); resampler_new_delta(dsp); dither_init(dsp); + tdspeed_setup(dsp); break; case DSP_SET_TRACK_GAIN: diff --git a/apps/dsp.h b/apps/dsp.h index 1746a5cccc..d12c877d05 100644 --- a/apps/dsp.h +++ b/apps/dsp.h @@ -165,5 +165,6 @@ void sound_set_pitch(int r); 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 diff --git a/apps/lang/english.lang b/apps/lang/english.lang index ea232df169..2d1c5f2801 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12037,3 +12037,17 @@ recording: "" + + id: LANG_SPEED + desc: time-domain speed compress/stretch + user: + + *: "Speed" + + + *: "Speed" + + + *: "Speed" + + diff --git a/apps/menus/sound_menu.c b/apps/menus/sound_menu.c index d953db93b3..8d80e3862d 100644 --- a/apps/menus/sound_menu.c +++ b/apps/menus/sound_menu.c @@ -89,6 +89,8 @@ MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, 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 @@ MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, Icon_Audio, #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 diff --git a/apps/settings.c b/apps/settings.c index b681471ef1..b13037af61 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -913,6 +913,7 @@ void settings_apply(bool read_disk) } dsp_dither_enable(global_settings.dithering_enabled); + dsp_set_speed(global_settings.sound_speed); #endif #ifdef HAVE_SPDIF_POWER diff --git a/apps/settings.h b/apps/settings.h index 9ef8323276..69d476f486 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -633,6 +633,7 @@ struct user_settings int eq_band4_gain; /* +/- dB */ bool dithering_enabled; + int sound_speed; #endif diff --git a/apps/settings_list.c b/apps/settings_list.c index 0addf5ceff..b72be2465a 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1106,6 +1106,9 @@ const struct settings_list settings[] = { /* 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, diff --git a/docs/CREDITS b/docs/CREDITS index 8571aa368a..a439689721 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -418,6 +418,7 @@ Florin Popescu Volker Mische Vitja Makarov Francisco Vila +Nicolas Pitre The libmad team The wavpack team