forked from len0rd/rockbox
Add timestretching from FS#8894, as written by Stephane Doyon based on work by Nicolas Pitre. Shouldn't affect playback unless it's explicitly enabled, but let me know if it does. Currently has a dedicated setting, but maybe inclusion of the code will inspire someone to integrate this with the pitch screen...
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18446 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b82449a513
commit
f6982346a1
9 changed files with 89 additions and 5 deletions
|
|
@ -201,3 +201,4 @@ keymaps/keymap-hdd1630.c
|
||||||
#elif CONFIG_KEYPAD == IAUDIO67_PAD
|
#elif CONFIG_KEYPAD == IAUDIO67_PAD
|
||||||
keymaps/keymap-iaudio67.c
|
keymaps/keymap-iaudio67.c
|
||||||
#endif
|
#endif
|
||||||
|
tdspeed.c
|
||||||
|
|
|
||||||
68
apps/dsp.c
68
apps/dsp.c
|
|
@ -32,6 +32,7 @@
|
||||||
#include "replaygain.h"
|
#include "replaygain.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "tdspeed.h"
|
||||||
|
|
||||||
/* 16-bit samples are scaled based on these constants. The shift should be
|
/* 16-bit samples are scaled based on these constants. The shift should be
|
||||||
* no more than 15.
|
* no more than 15.
|
||||||
|
|
@ -41,8 +42,14 @@
|
||||||
|
|
||||||
#define NATIVE_DEPTH 16
|
#define NATIVE_DEPTH 16
|
||||||
/* If the buffer sizes change, check the assembly code! */
|
/* If the buffer sizes change, check the assembly code! */
|
||||||
#define SAMPLE_BUF_COUNT 256
|
#define SMALL_SAMPLE_BUF_COUNT 256
|
||||||
#define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/
|
#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 DEFAULT_GAIN 0x01000000
|
||||||
#define SAMPLE_BUF_LEFT_CHANNEL 0
|
#define SAMPLE_BUF_LEFT_CHANNEL 0
|
||||||
#define SAMPLE_BUF_RIGHT_CHANNEL (SAMPLE_BUF_COUNT/2)
|
#define SAMPLE_BUF_RIGHT_CHANNEL (SAMPLE_BUF_COUNT/2)
|
||||||
|
|
@ -163,6 +170,8 @@ struct dsp_config
|
||||||
int sample_depth;
|
int sample_depth;
|
||||||
int sample_bytes;
|
int sample_bytes;
|
||||||
int stereo_mode;
|
int stereo_mode;
|
||||||
|
bool tdspeed_active;
|
||||||
|
int tdspeed_factor; /* % */
|
||||||
int frac_bits;
|
int frac_bits;
|
||||||
#ifdef HAVE_SW_TONE_CONTROLS
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
/* Filter struct for software bass/treble controls */
|
/* Filter struct for software bass/treble controls */
|
||||||
|
|
@ -226,8 +235,12 @@ static bool crossfeed_enabled;
|
||||||
* of copying needed is minimized for that case.
|
* of copying needed is minimized for that case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR;
|
int32_t small_sample_buf[SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR;
|
||||||
static int32_t resample_buf[RESAMPLE_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
|
#if 0
|
||||||
/* Clip sample to arbitrary limits where range > 0 and min + range = max */
|
/* 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);
|
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
|
/* 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
|
* 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
|
* 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);
|
dsp->input_samples(samples, src, tmp);
|
||||||
|
|
||||||
|
if(dsp->tdspeed_active)
|
||||||
|
samples = tdspeed_doit(tmp, samples);
|
||||||
|
|
||||||
if (dsp->apply_gain)
|
if (dsp->apply_gain)
|
||||||
dsp->apply_gain(samples, &dsp->data, tmp);
|
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 */
|
/* dsp_input_size MUST be called afterwards */
|
||||||
int dsp_output_count(struct dsp_config *dsp, int count)
|
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)
|
if (dsp->resample)
|
||||||
{
|
{
|
||||||
count = (int)(((unsigned long)count * NATIVE_FREQUENCY
|
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);
|
dsp->data.resample_data.delta) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dsp->tdspeed_active)
|
||||||
|
count = tdspeed_est_input_size(count);
|
||||||
|
|
||||||
return 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;
|
dsp->frequency = dsp->codec_frequency;
|
||||||
|
|
||||||
resampler_new_delta(dsp);
|
resampler_new_delta(dsp);
|
||||||
|
tdspeed_setup(dsp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_SET_SAMPLE_DEPTH:
|
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->stereo_mode = value;
|
||||||
dsp->data.num_channels = value == STEREO_MONO ? 1 : 2;
|
dsp->data.num_channels = value == STEREO_MONO ? 1 : 2;
|
||||||
dsp_update_functions(dsp);
|
dsp_update_functions(dsp);
|
||||||
|
tdspeed_setup(dsp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_RESET:
|
case DSP_RESET:
|
||||||
|
|
@ -1321,6 +1379,7 @@ intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
|
||||||
|
|
||||||
dsp_update_functions(dsp);
|
dsp_update_functions(dsp);
|
||||||
resampler_new_delta(dsp);
|
resampler_new_delta(dsp);
|
||||||
|
tdspeed_setup(dsp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_FLUSH:
|
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));
|
sizeof (dsp->data.resample_data));
|
||||||
resampler_new_delta(dsp);
|
resampler_new_delta(dsp);
|
||||||
dither_init(dsp);
|
dither_init(dsp);
|
||||||
|
tdspeed_setup(dsp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_SET_TRACK_GAIN:
|
case DSP_SET_TRACK_GAIN:
|
||||||
|
|
|
||||||
|
|
@ -165,5 +165,6 @@ void sound_set_pitch(int r);
|
||||||
int sound_get_pitch(void);
|
int sound_get_pitch(void);
|
||||||
int dsp_callback(int msg, intptr_t param);
|
int dsp_callback(int msg, intptr_t param);
|
||||||
void dsp_dither_enable(bool enable);
|
void dsp_dither_enable(bool enable);
|
||||||
|
void dsp_set_speed(int speed);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12037,3 +12037,17 @@
|
||||||
recording: ""
|
recording: ""
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SPEED
|
||||||
|
desc: time-domain speed compress/stretch
|
||||||
|
user:
|
||||||
|
<source>
|
||||||
|
*: "Speed"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "Speed"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "Speed"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,8 @@ MENUITEM_SETTING(stereo_width, &global_settings.stereo_width,
|
||||||
|
|
||||||
MENUITEM_SETTING(dithering_enabled,
|
MENUITEM_SETTING(dithering_enabled,
|
||||||
&global_settings.dithering_enabled, lowlatency_callback);
|
&global_settings.dithering_enabled, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(sound_speed, &global_settings.sound_speed,
|
||||||
|
lowlatency_callback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
|
|
@ -116,7 +118,7 @@ MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, Icon_Audio,
|
||||||
#endif
|
#endif
|
||||||
&balance,&channel_config,&stereo_width
|
&balance,&channel_config,&stereo_width
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
|
,&crossfeed_menu, &equalizer_menu, &dithering_enabled, &sound_speed
|
||||||
#endif
|
#endif
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength
|
,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength
|
||||||
|
|
|
||||||
|
|
@ -913,6 +913,7 @@ void settings_apply(bool read_disk)
|
||||||
}
|
}
|
||||||
|
|
||||||
dsp_dither_enable(global_settings.dithering_enabled);
|
dsp_dither_enable(global_settings.dithering_enabled);
|
||||||
|
dsp_set_speed(global_settings.sound_speed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SPDIF_POWER
|
#ifdef HAVE_SPDIF_POWER
|
||||||
|
|
|
||||||
|
|
@ -633,6 +633,7 @@ struct user_settings
|
||||||
int eq_band4_gain; /* +/- dB */
|
int eq_band4_gain; /* +/- dB */
|
||||||
|
|
||||||
bool dithering_enabled;
|
bool dithering_enabled;
|
||||||
|
int sound_speed;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1106,6 +1106,9 @@ const struct settings_list settings[] = {
|
||||||
/* dithering */
|
/* dithering */
|
||||||
OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false,
|
OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false,
|
||||||
"dithering enabled", dsp_dither_enable),
|
"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
|
#endif
|
||||||
#ifdef HAVE_WM8758
|
#ifdef HAVE_WM8758
|
||||||
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
|
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ Florin Popescu
|
||||||
Volker Mische
|
Volker Mische
|
||||||
Vitja Makarov
|
Vitja Makarov
|
||||||
Francisco Vila
|
Francisco Vila
|
||||||
|
Nicolas Pitre
|
||||||
|
|
||||||
The libmad team
|
The libmad team
|
||||||
The wavpack team
|
The wavpack team
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue