Index: docs/CREDITS
===================================================================
--- docs/CREDITS (revision 20101)
+++ docs/CREDITS (working copy)
@@ -450,6 +450,8 @@
Eric Shattow
Joshua Simmons
Sei Aoyumi
+Nicolas Pitre
+Bryan Vandyke
The libmad team
Index: apps/settings.c
===================================================================
--- apps/settings.c (revision 20101)
+++ apps/settings.c (working copy)
@@ -929,6 +929,8 @@
}
dsp_dither_enable(global_settings.dithering_enabled);
+ dsp_timestretch_enable(global_settings.timestretch_enabled);
+ dsp_set_timestretch(global_settings.timestretch_percent);
#endif
#ifdef HAVE_SPDIF_POWER
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang (revision 20101)
+++ apps/lang/english.lang (working copy)
@@ -12359,3 +12359,31 @@
*: "Credits"
+
+ id: LANG_TIMESTRETCH
+ desc: timestretch enable
+ user:
+
+ *: "Timestretch Enabled"
+
+
+ *: "Timestretch Enabled"
+
+
+ *: "Timestretch Enabled"
+
+
+
+ id: LANG_TIMESTRETCH_PERCENT
+ desc: timestretch percentage
+ user:
+
+ *: "Timestretch Percentage"
+
+
+ *: "Timestretch Percentage"
+
+
+ *: "Timestretch Percentage"
+
+
Index: apps/settings.h
===================================================================
--- apps/settings.h (revision 20101)
+++ apps/settings.h (working copy)
@@ -387,6 +387,8 @@
int keyclick; /* keyclick volume */
int keyclick_repeats; /* keyclick on repeats */
bool dithering_enabled;
+ bool timestretch_enabled;
+ int timestretch_percent; /* timestretching speed percentage */
#endif /* CONFIG_CODEC == SWCODEC */
#ifdef HAVE_RECORDING
Index: apps/menus/sound_menu.c
===================================================================
--- apps/menus/sound_menu.c (revision 20101)
+++ apps/menus/sound_menu.c (working copy)
@@ -32,6 +32,9 @@
#include "eq_menu.h"
#include "exported_menus.h"
#include "menu_common.h"
+#include "splash.h"
+#include "kernel.h"
+#include "dsp.h"
/***********************************/
/* SOUND MENU */
@@ -89,6 +92,22 @@
MENUITEM_SETTING(dithering_enabled,
&global_settings.dithering_enabled, lowlatency_callback);
+static int timestretch_callback(int action,const struct menu_item_ex *this_item)
+{
+ switch (action)
+ {
+ case ACTION_EXIT_MENUITEM: /* on exit */
+ if (global_settings.timestretch_enabled && dsp_timestretch_needs_reboot())
+ splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
+ break;
+ }
+ lowlatency_callback(action, this_item);
+ return action;
+}
+ MENUITEM_SETTING(timestretch_enabled,
+ &global_settings.timestretch_enabled, timestretch_callback);
+ MENUITEM_SETTING(timestretch_percent, &global_settings.timestretch_percent,
+ lowlatency_callback);
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
@@ -116,7 +135,8 @@
#endif
&balance,&channel_config,&stereo_width
#if CONFIG_CODEC == SWCODEC
- ,&crossfeed_menu, &equalizer_menu, &dithering_enabled
+ ,&crossfeed_menu, &equalizer_menu, &dithering_enabled
+ ,×tretch_enabled, ×tretch_percent
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength
Index: apps/dsp.c
===================================================================
--- apps/dsp.c (revision 20101)
+++ apps/dsp.c (working copy)
@@ -32,6 +32,8 @@
#include "replaygain.h"
#include "misc.h"
#include "debug.h"
+#include "tdspeed.h"
+#include "buffer.h"
/* 16-bit samples are scaled based on these constants. The shift should be
* no more than 15.
@@ -41,13 +43,11 @@
#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*/
#define DEFAULT_GAIN 0x01000000
-#define SAMPLE_BUF_LEFT_CHANNEL 0
-#define SAMPLE_BUF_RIGHT_CHANNEL (SAMPLE_BUF_COUNT/2)
-#define RESAMPLE_BUF_LEFT_CHANNEL 0
-#define RESAMPLE_BUF_RIGHT_CHANNEL (RESAMPLE_BUF_COUNT/2)
/* enums to index conversion properly with stereo mode and other settings */
enum
@@ -163,6 +163,9 @@
int sample_depth;
int sample_bytes;
int stereo_mode;
+ bool tdspeed_enabled; /* User has enabled timstretch */
+ int tdspeed_percent; /* % */
+ bool tdspeed_active; /* Timestretch is initialised ok */
int frac_bits;
#ifdef HAVE_SW_TONE_CONTROLS
/* Filter struct for software bass/treble controls */
@@ -226,9 +229,24 @@
* 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;
+static int32_t small_sample_buf[SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR;
+static int32_t small_resample_buf[SMALL_RESAMPLE_BUF_COUNT] IBSS_ATTR;
+static int32_t *big_sample_buf = NULL;
+static int32_t *big_resample_buf = NULL;
+static int big_sample_buf_count = -1; /* -1=unknown */
+static int big_resample_buf_count = -1; /* -1=unknown */
+
+static int sample_buf_count;
+static int resample_buf_count;
+static int32_t *sample_buf;
+static int32_t *resample_buf;
+
+#define SAMPLE_BUF_LEFT_CHANNEL 0
+#define SAMPLE_BUF_RIGHT_CHANNEL (sample_buf_count/2)
+#define RESAMPLE_BUF_LEFT_CHANNEL 0
+#define RESAMPLE_BUF_RIGHT_CHANNEL (resample_buf_count/2)
+
#if 0
/* Clip sample to arbitrary limits where range > 0 and min + range = max */
static inline long clip_sample(int32_t sample, int32_t min, int32_t range)
@@ -264,6 +282,64 @@
audio_dsp.codec_frequency);
}
+void tdspeed_setup(struct dsp_config *dspc)
+{
+ if(dspc == &dsp_conf[CODEC_IDX_AUDIO])
+ {
+ if (!dspc->tdspeed_enabled ||
+ dspc->tdspeed_percent == 0 ||
+ dspc->tdspeed_percent == 100 ||
+ big_sample_buf_count <= 0 ||
+ big_resample_buf_count <= 0)
+ 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_percent);
+ }
+}
+
+void dsp_timestretch_enable(bool enable)
+{
+ if (enable)
+ {
+ /* Set up timestretch buffers on first enable */
+ if (big_sample_buf_count < 0)
+ {
+ big_sample_buf = buffer_alloc(big_sample_buf_count);
+ big_sample_buf_count = BIG_SAMPLE_BUF_COUNT;
+ }
+ if (big_resample_buf_count < 0)
+ {
+ big_resample_buf = buffer_alloc(big_resample_buf_count);
+ big_resample_buf_count = BIG_RESAMPLE_BUF_COUNT;
+ }
+ }
+ else
+ {
+ /* If not enabled at startup, buffers will never be available */
+ if (big_sample_buf_count < 0)
+ big_sample_buf_count = 0;
+ if (big_resample_buf_count < 0)
+ big_resample_buf_count = 0;
+ }
+ dsp_conf[CODEC_IDX_AUDIO].tdspeed_enabled = enable;
+ tdspeed_setup(&dsp_conf[CODEC_IDX_AUDIO]);
+}
+
+void dsp_set_timestretch(int percent)
+{
+ dsp_conf[CODEC_IDX_AUDIO].tdspeed_percent = percent;
+ tdspeed_setup(&dsp_conf[CODEC_IDX_AUDIO]);
+}
+
+bool dsp_timestretch_needs_reboot()
+{
+ return (dsp_conf[CODEC_IDX_AUDIO].tdspeed_enabled &&
+ (big_sample_buf_count <= 0 || big_resample_buf_count <= 0));
+}
+
/* 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
@@ -604,7 +680,7 @@
do
{
/* Should always be able to output a sample for a ratio up to
- RESAMPLE_BUF_COUNT / SAMPLE_BUF_COUNT. */
+ resample_buf_count / sample_buf_count. */
int32_t *s = src[ch];
int32_t last = data->resample_data.last_sample[ch];
@@ -1069,7 +1145,8 @@
*/
int dsp_callback(int msg, intptr_t param)
{
- switch (msg) {
+ switch (msg)
+ {
#ifdef HAVE_SW_TONE_CONTROLS
case DSP_CALLBACK_SET_PRESCALE:
prescale = param;
@@ -1132,7 +1209,7 @@
will be preloaded to be used for the call if not. */
while (count > 0)
{
- samples = MIN(SAMPLE_BUF_COUNT/2, count);
+ samples = MIN(sample_buf_count/2, count);
count -= samples;
dsp->input_samples(samples, src, tmp);
@@ -1140,6 +1217,9 @@
if (dsp->apply_gain)
dsp->apply_gain(samples, &dsp->data, tmp);
+ if (dsp->tdspeed_active && (samples = tdspeed_doit(tmp, samples)) <= 0)
+ break;
+
if (dsp->resample && (samples = resample(dsp, samples, tmp)) <= 0)
break; /* I'm pretty sure we're downsampling here */
@@ -1188,6 +1268,22 @@
/* 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;
+ sample_buf_count = big_sample_buf_count;
+ resample_buf = big_resample_buf;
+ 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
@@ -1195,12 +1291,12 @@
}
/* Now we have the resampled sample count which must not exceed
- * RESAMPLE_BUF_COUNT/2 to avoid resample buffer overflow. One
+ * resample_buf_count/2 to avoid resample buffer overflow. One
* must call dsp_input_count() to get the correct input sample
* count.
*/
- if (count > RESAMPLE_BUF_COUNT/2)
- count = RESAMPLE_BUF_COUNT/2;
+ if (count > resample_buf_count/2)
+ count = resample_buf_count/2;
return count;
}
@@ -1221,6 +1317,9 @@
dsp->data.resample_data.delta) >> 16);
}
+ if(dsp->tdspeed_active)
+ count = tdspeed_est_input_size(count);
+
return count;
}
@@ -1268,6 +1367,7 @@
dsp->frequency = dsp->codec_frequency;
resampler_new_delta(dsp);
+ tdspeed_setup(dsp);
break;
case DSP_SET_SAMPLE_DEPTH:
@@ -1297,6 +1397,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 +1422,7 @@
dsp_update_functions(dsp);
resampler_new_delta(dsp);
+ tdspeed_setup(dsp);
break;
case DSP_FLUSH:
@@ -1328,6 +1430,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 20101)
+++ apps/dsp.h (working copy)
@@ -164,5 +164,8 @@
int sound_get_pitch(void);
int dsp_callback(int msg, intptr_t param);
void dsp_dither_enable(bool enable);
+void dsp_timestretch_enable(bool enable);
+void dsp_set_timestretch(int percent);
+bool dsp_timestretch_needs_reboot(void);
#endif
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c (revision 20101)
+++ apps/settings_list.c (working copy)
@@ -1178,6 +1178,13 @@
/* dithering */
OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false,
"dithering enabled", dsp_dither_enable),
+
+ /* timestretch */
+ OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false,
+ "timestretch enabled", dsp_timestretch_enable),
+ INT_SETTING(0, timestretch_percent, LANG_TIMESTRETCH_PERCENT, 100, "timestretch percentage",
+ UNIT_INT, 35, 250, 5,
+ NULL, NULL, dsp_set_timestretch),
#endif
#ifdef HAVE_WM8758
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
Index: apps/tdspeed.c
===================================================================
--- apps/tdspeed.c (revision 0)
+++ apps/tdspeed.c (revision 0)
@@ -0,0 +1,333 @@
+/*
+ * Audio time domain speed scaling / time compression/stretch.
+ *
+ * Copyright (C) 2006 by Nicolas Pitre
+ *
+ * Modified by Stéphane Doyon to adapt to Rockbox
+ * Copyright (C) 2006-2007 by Stéphane Doyon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+#include
+#include "system.h"
+#include "tdspeed.h"
+
+#define mylog(...)
+#define assert(...)
+
+#if 0
+#define assert(cond) \
+ if(!(cond)) { \
+ badlog("Assertion failed in %s at line %d: %s\n", \
+ __FUNCTION__, __LINE__, #cond); \
+ }
+#endif
+
+#define MIN_RATE 8000
+#define MAX_RATE 48000 /* double buffer for double rate */
+#define MIN_FACTOR 35
+#define MAX_FACTOR 250
+
+//#define FIXED_BUFSIZE 3072 /* 48KHz factor 3.0 */
+#define FIXED_BUFSIZE 3524 /* worse seen, not sure how to calc */
+
+struct tdspeed_state_s {
+ bool stereo;
+ int shift_max; /* maximum displacement on a frame */
+ int src_step; /* source window pace */
+ int dst_step; /* destination window pace */
+ int dst_order; /* power of two for dst_step */
+ int ovl_shift; /* overlap buffer frame shift */
+ int ovl_size; /* overlap buffer used size */
+ int ovl_space; /* overlap buffer size */
+ int32_t *ovl_buff[2]; /* overlap buffer */
+};
+static struct tdspeed_state_s tdspeed_state;
+
+static int32_t overlap_buffer[2][FIXED_BUFSIZE];
+static int32_t outbuf[2][TDSPEED_OUTBUFSIZE];
+
+bool tdspeed_init(int samplerate, bool stereo, int factor)
+{
+ struct tdspeed_state_s *st = &tdspeed_state;
+ int src_frame_sz;
+
+ if(factor == 100)
+ return false;
+ if (samplerate < MIN_RATE || samplerate > MAX_RATE)
+ return false;
+ if(factor MAX_FACTOR)
+ return false;
+
+ st->stereo = !!stereo;
+
+#define MINFREQ 100
+ st->dst_step = samplerate / MINFREQ;
+
+ if (factor > 100)
+ st->dst_step = st->dst_step *100 /factor;
+ st->dst_order = 1;
+
+ while (st->dst_step >>= 1)
+ st->dst_order++;
+ st->dst_step = (1 << st->dst_order);
+ st->src_step = st->dst_step * factor /100;
+ st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step;
+
+ src_frame_sz = st->shift_max + st->dst_step;
+ if (st->dst_step > st->src_step)
+ src_frame_sz += st->dst_step - st->src_step;
+ st->ovl_space = ((src_frame_sz - 2)/st->src_step) * st->src_step
+ + src_frame_sz;
+ if (st->src_step > st->dst_step)
+ st->ovl_space += 2*st->src_step - st->dst_step;
+
+ mylog(
+ "shift_max %d, src_step %d, dst_step %d, dst_order %d, src_frame_sz %d, ovl_space %d\n",
+ st->shift_max, st->src_step, st->dst_step, st->dst_order, src_frame_sz, st->ovl_space);
+
+ assert(st->ovl_space <= FIXED_BUFSIZE);
+
+ st->ovl_size = 0;
+ st->ovl_shift = 0;
+
+ st->ovl_buff[0] = overlap_buffer[0];
+ if(stereo)
+ st->ovl_buff[1] = overlap_buffer[1];
+ else st->ovl_buff[1] = st->ovl_buff[0];
+
+ return true;
+}
+
+int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], int data_len,
+ int last, int out_size)
+/* data_len in samples */
+{
+ struct tdspeed_state_s *st = &tdspeed_state;
+ int32_t *curr, *prev, *dest[2], *d;
+ int i, j, next_frame, prev_frame, shift, src_frame_sz;
+ bool stereo = buf_in[0] != buf_in[1];
+ assert(stereo == st->stereo);
+
+ src_frame_sz = st->shift_max + st->dst_step;
+ if (st->dst_step > st->src_step)
+ src_frame_sz += st->dst_step - st->src_step;
+
+ /* deal with overlap data first, if any */
+ if (st->ovl_size) {
+ int have, copy, steps;
+ have = st->ovl_size;
+ if (st->ovl_shift > 0)
+ have -= st->ovl_shift;
+ /* append just enough data to have all of the overlap buffer consumed*/
+ steps = (have - 1) / st->src_step;
+ copy = steps * st->src_step + src_frame_sz - have;
+ if (copy < src_frame_sz - st->dst_step)
+ copy += st->src_step; /* one more step to allow for pregap data */
+ if (copy > data_len) copy = data_len;
+ assert(st->ovl_size +copy <= FIXED_BUFSIZE);
+ memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0],
+ copy * sizeof(int32_t));
+ if(stereo)
+ memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1],
+ copy * sizeof(int32_t));
+ if (!last && have + copy < src_frame_sz) {
+ /* still not enough to process at least one frame */
+ st->ovl_size += copy;
+ return 0;
+ }
+ /* recursively call ourselves to process the overlap buffer */
+ have = st->ovl_size;
+ st->ovl_size = 0;
+ if (copy == data_len) {
+ assert( (have+copy) <= FIXED_BUFSIZE);
+ return tdspeed_apply(buf_out, st->ovl_buff, have+copy, last,
+ out_size);
+ }
+ assert( (have+copy) <= FIXED_BUFSIZE);
+ i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, -1, out_size);
+ dest[0] = buf_out[0] + i;
+ dest[1] = buf_out[1] + i;
+ /* readjust pointers to account for data already consumed */
+ next_frame = copy - src_frame_sz + st->src_step;
+ prev_frame = next_frame - st->ovl_shift;
+ } else {
+ dest[0] = buf_out[0];
+ dest[1] = buf_out[1];
+ next_frame = prev_frame = 0;
+ if (st->ovl_shift > 0)
+ next_frame += st->ovl_shift;
+ else
+ prev_frame += -st->ovl_shift;
+ }
+ st->ovl_shift = 0;
+
+ /* process all complete frames */
+ while (data_len -next_frame >= src_frame_sz) {
+ /* find frame overlap by autocorelation */
+ long long min_delta = ~(1ll << 63); /* most positive */
+ shift = 0;
+#define INC1 8
+#define INC2 32
+ /* Power of 2 of a 28bit number requires 56bits, can accumulate
+ 256times in a 64bit variable. */
+ assert(st->dst_step /INC2 <= 256);
+ assert(next_frame+st->shift_max-1 +st->dst_step-1 < data_len);
+ assert(prev_frame +st->dst_step-1 < data_len);
+ for (i = 0; i < st->shift_max; i += INC1) {
+ long long delta = 0;
+ curr = buf_in[0] +next_frame + i;
+ prev = buf_in[0] +prev_frame;
+ for (j = 0; j < st->dst_step;
+ j += INC2, curr += INC2, prev += INC2) {
+ int32_t diff = *curr - *prev;
+ delta += (long long)diff * diff;
+ if (delta >= min_delta)
+ goto skip;
+ }
+ if(stereo) {
+ curr = buf_in[1] +next_frame + i;
+ prev = buf_in[1] +prev_frame;
+ for (j = 0; j < st->dst_step;
+ j += INC2, curr += INC2, prev += INC2) {
+ int32_t diff = *curr - *prev;
+ delta += (long long)diff * diff;
+ if (delta >= min_delta)
+ goto skip;
+ }
+ }
+ min_delta = delta;
+ shift = i;
+ skip:;
+ }
+
+ /* overlap fading-out previous frame with fading-in current frame */
+ curr = buf_in[0] +next_frame + shift;
+ prev = buf_in[0] +prev_frame;
+ d = dest[0];
+ assert(next_frame+shift +st->dst_step-1 < data_len);
+ assert(prev_frame +st->dst_step-1 < data_len);
+ assert(dest[0]-buf_out[0] +st->dst_step-1 < out_size);
+ for (i = 0, j = st->dst_step; j; i++, j--) {
+ *d++ = (*curr++ * (long long)i
+ + *prev++ * (long long)j) >> st->dst_order;
+ }
+ dest[0] = d;
+ if(stereo) {
+ curr = buf_in[1] +next_frame + shift;
+ prev = buf_in[1] +prev_frame;
+ d = dest[1];
+ for (i = 0, j = st->dst_step; j; i++, j--) {
+ assert(d < buf_out[1] +out_size);
+ *d++ = (*curr++ * (long long)i
+ + *prev++ * (long long)j) >> st->dst_order;
+ }
+ dest[1] = d;
+ }
+
+ /* adjust pointers for next frame */
+ prev_frame = next_frame + shift + st->dst_step;
+ //assert(prev_frame == curr[0] -buf_in[0]);
+ next_frame += st->src_step;
+ /* here next_frame - prev_frame = src_step - dst_step - shift */
+ assert(next_frame - prev_frame == st->src_step - st->dst_step - shift);
+ }
+
+ /* now deal with remaining partial frames */
+ if (last == -1) {
+ /* special overlap buffer processing: remember frame shift only */
+ st->ovl_shift = next_frame - prev_frame;
+ } else if (last != 0) {
+ /* last call: purge all remaining data to output buffer */
+ i = data_len -prev_frame;
+ assert(dest[0] +i <= buf_out[0] +out_size);
+ memcpy(dest[0], buf_in[0] +prev_frame, i * sizeof(int32_t));
+ dest[0] += i;
+ if(stereo) {
+ assert(dest[1] +i <= buf_out[1] +out_size);
+ memcpy(dest[1], buf_in[1] +prev_frame, i * sizeof(int32_t));
+ dest[1] += i;
+ }
+ } else {
+ /* preserve remaining data + needed overlap data for next call */
+ st->ovl_shift = next_frame - prev_frame;
+ i = (st->ovl_shift < 0) ? next_frame : prev_frame;
+ st->ovl_size = data_len - i;
+ assert(st->ovl_size <= FIXED_BUFSIZE);
+ memcpy(st->ovl_buff[0], buf_in[0]+i, st->ovl_size * sizeof(int32_t));
+ if(stereo)
+ memcpy(st->ovl_buff[1], buf_in[1]+i, st->ovl_size * sizeof(int32_t));
+ }
+
+ return dest[0] - buf_out[0];
+}
+
+#if 0
+static int tdspeed_next_required_space(int data_len, int last)
+{
+ struct tdspeed_state_s *st = &tdspeed_state;
+ int src_frame_sz, src_size, nb_frames, dst_space;
+
+ src_frame_sz = st->shift_max + st->dst_step;
+ if (st->dst_step > st->src_step)
+ src_frame_sz += st->dst_step - st->src_step;
+ src_size = data_len + st->ovl_size;
+ if (st->ovl_shift > 0)
+ src_size -= st->ovl_shift;
+ if (src_size < src_frame_sz) {
+ if (!last)
+ return 0;
+ dst_space = data_len + st->ovl_size;
+ if (st->ovl_shift < 0)
+ dst_space += st->ovl_shift;
+ } else {
+ nb_frames = (src_size - src_frame_sz) / st->src_step + 1;
+ dst_space = nb_frames * st->dst_step;
+ if (last) {
+ dst_space += src_size - nb_frames * st->src_step;
+ dst_space += st->src_step - st->dst_step;
+ }
+ }
+ return dst_space;
+}
+#endif
+
+long tdspeed_est_output_size(long size)
+{
+ //int _size = size;
+#if 0
+ size = tdspeed_next_required_space(size, false);
+ if(size > TDSPEED_OUTBUFSIZE)
+ size = TDSPEED_OUTBUFSIZE;
+#else
+ size = TDSPEED_OUTBUFSIZE;
+#endif
+ mylog("tdspeed_est_output_size of %d -> %d\n", _size, size);
+ return size;
+}
+long tdspeed_est_input_size(long size)
+{
+ struct tdspeed_state_s *st = &tdspeed_state;
+ //int _size = size;
+ size = (size -st->ovl_size) *st->src_step /st->dst_step;
+ if(size <0)
+ size = 0;
+ else size = size;
+ mylog("tdspeed_est_input_size of %d -> %d\n", _size, size);
+ return size;
+}
+
+int tdspeed_doit(int32_t *src[], int count)
+{
+ count = tdspeed_apply( (int32_t *[2]) { outbuf[0], outbuf[1] },
+ src, count, 0, TDSPEED_OUTBUFSIZE);
+ src[0] = outbuf[0];
+ src[1] = outbuf[1];
+ return count;
+}
Index: apps/tdspeed.h
===================================================================
--- apps/tdspeed.h (revision 0)
+++ apps/tdspeed.h (revision 0)
@@ -0,0 +1,9 @@
+#define TDSPEED_OUTBUFSIZE 4096
+
+bool tdspeed_init(int samplerate, bool stereo, int factor);
+int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2], int data_len,
+ int last, int out_size);
+
+long tdspeed_est_output_size(long size);
+long tdspeed_est_input_size(long size);
+int tdspeed_doit(int32_t *src[], int count);
Index: apps/SOURCES
===================================================================
--- apps/SOURCES (revision 20101)
+++ apps/SOURCES (working copy)
@@ -224,3 +224,4 @@
#elif CONFIG_KEYPAD == ONDAVX747_PAD
keymaps/keymap-ondavx747.c
#endif
+tdspeed.c