summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2011-01-02 18:27:54 +0100
committerGravatar waker <wakeroid@gmail.com>2011-01-02 18:27:54 +0100
commit915c9c218574207a7954e53b9747045a6ae34282 (patch)
treee7f4e81d5b23a13d9ca581f2713d11f0f62435bb
parentd5a14f3678d81f609278c2b5019ff1c3c3a9ce53 (diff)
added bounds checking and output ratio to dsp plugin API;
fixed all existing dsp plugins for the new API; dsp_soundtouch can now be used as a resampler
-rw-r--r--deadbeef.h16
-rw-r--r--plugins/dsp_libsrc/src.c5
-rw-r--r--plugins/dsp_soundtouch/plugin.c61
-rw-r--r--plugins/supereq/supereq.c2
-rw-r--r--streamer.c20
5 files changed, 76 insertions, 28 deletions
diff --git a/deadbeef.h b/deadbeef.h
index bc629684..b3cf7d17 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -750,6 +750,7 @@ typedef struct DB_output_s {
} DB_output_t;
// dsp plugin
+// see also: examples/dsp_template.c in git
#define DDB_INIT_DSP_CONTEXT(var,type,plug) {\
memset(var,0,sizeof(type));\
var->ctx.plugin=plug;\
@@ -775,11 +776,11 @@ typedef struct DB_dsp_s {
void (*close) (ddb_dsp_context_t *ctx);
// samples are always interleaved floating point
- // returned value is number of output frames
- // can change channels, samplerate, channelmask
- // buffer size should always have reserved space for upsampling/upmixing
- // TODO: decide on buffer size
- int (*process) (ddb_dsp_context_t *ctx, float *samples, int frames, ddb_waveformat_t *fmt);
+ // returned value is number of output frames (multichannel samples)
+ // plugins are allowed to modify channels, samplerate, channelmask in the fmt structure
+ // buffer size can fit up to maxframes frames
+ // by default ratio=1, and plugins don't need to touch it unless they have to
+ int (*process) (ddb_dsp_context_t *ctx, float *samples, int frames, int maxframes, ddb_waveformat_t *fmt, float *ratio);
void (*reset) (ddb_dsp_context_t *ctx);
@@ -791,11 +792,12 @@ typedef struct DB_dsp_s {
// param names are for display-only, and are allowed to contain spaces
int (*num_params) (void);
const char *(*get_param_name) (int p);
-
void (*set_param) (ddb_dsp_context_t *ctx, int p, const char *val);
void (*get_param) (ddb_dsp_context_t *ctx, int p, char *str, int len);
- const char *configdialog; // separate dialog per dsp context
+ // config dialog implementation uses set/get param, so they must be
+ // implemented if this is nonzero
+ const char *configdialog;
} DB_dsp_t;
// misc plugin
diff --git a/plugins/dsp_libsrc/src.c b/plugins/dsp_libsrc/src.c
index 09e5897f..9c5e6fdc 100644
--- a/plugins/dsp_libsrc/src.c
+++ b/plugins/dsp_libsrc/src.c
@@ -87,7 +87,7 @@ ddb_src_set_ratio (ddb_dsp_context_t *_src, float ratio) {
}
int
-ddb_src_process (ddb_dsp_context_t *_src, float *samples, int nframes, ddb_waveformat_t *fmt) {
+ddb_src_process (ddb_dsp_context_t *_src, float *samples, int nframes, int maxframes, ddb_waveformat_t *fmt, float *r) {
ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
if (fmt->samplerate == src->samplerate) {
@@ -111,6 +111,9 @@ ddb_src_process (ddb_dsp_context_t *_src, float *samples, int nframes, ddb_wavef
fmt->samplerate = src->samplerate;
int numoutframes = nframes * src->srcdata.src_ratio;
+ if (numoutframes > maxframes) {
+ numoutframes = maxframes;
+ }
float outbuf[numoutframes*fmt->channels];
memset (outbuf, 0, sizeof (outbuf));
int buffersize = sizeof (outbuf);
diff --git a/plugins/dsp_soundtouch/plugin.c b/plugins/dsp_soundtouch/plugin.c
index 9b67a090..6997a629 100644
--- a/plugins/dsp_soundtouch/plugin.c
+++ b/plugins/dsp_soundtouch/plugin.c
@@ -31,6 +31,7 @@ enum {
ST_PARAM_USE_QUICKSEEK,
ST_PARAM_SEQUENCE_MS,
ST_PARAM_SEEKWINDOW_MS,
+ ST_PARAM_SET_OUTPUT_SAMPLERATE,
ST_PARAM_COUNT
};
@@ -48,6 +49,7 @@ typedef struct {
int use_quickseek;
int sequence_ms;
int seekwindow_ms;
+ int set_output_samplerate;
int changed;
} ddb_soundtouch_t;
@@ -84,10 +86,17 @@ st_reset (ddb_dsp_context_t *_src) {
}
int
-st_process (ddb_dsp_context_t *_src, float *samples, int nframes, ddb_waveformat_t *fmt) {
+st_process (ddb_dsp_context_t *_src, float *samples, int nframes, int maxframes, ddb_waveformat_t *fmt, float *ratio) {
ddb_soundtouch_t *st = (ddb_soundtouch_t *)_src;
if (st->changed) {
- st_set_rate_change (st->st, st->rate);
+ if (st->set_output_samplerate > 0) {
+ st_set_rate_change (st->st, 0);
+ st_set_rate (st->st, fmt->samplerate / (float)st->set_output_samplerate);
+ }
+ else {
+ st_set_rate (st->st, 1);
+ st_set_rate_change (st->st, st->rate);
+ }
st_set_pitch_semi_tones (st->st, st->pitch);
st_set_tempo_change (st->st, st->tempo);
st_set_setting (st->st, SETTING_USE_AA_FILTER, st->use_aa_filter);
@@ -97,17 +106,24 @@ st_process (ddb_dsp_context_t *_src, float *samples, int nframes, ddb_waveformat
st_set_setting (st->st, SETTING_SEEKWINDOW_MS, st->seekwindow_ms);
st->changed = 0;
}
+ *ratio = (1.f + 0.01f * st->tempo);
+
+ if (st->set_output_samplerate > 0) {
+ fmt->samplerate = st->set_output_samplerate;
+ }
+ else {
+ *ratio *= (1.f + 0.01f * st->rate);
+ }
st_set_sample_rate (st->st, fmt->samplerate);
st_set_channels (st->st, fmt->channels);
st_put_samples (st->st, samples, nframes);
int nout = 0;
- int nmax = nframes * 24;
int n = 0;
do {
- n = st_receive_samples (st->st, samples, nmax);
- nmax -= n;
+ n = st_receive_samples (st->st, samples, maxframes);
+ maxframes -= n;
samples += n * fmt->channels;
nout += n;
} while (n != 0);
@@ -134,6 +150,8 @@ st_get_param_name (int p) {
return "Time Stretch Sequence Length (ms)";
case ST_PARAM_SEEKWINDOW_MS:
return "Time Stretch Seek Window Length (ms)";
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ return "Set Output Samplerate";
default:
fprintf (stderr, "st_param_name: invalid param index (%d)\n", p);
}
@@ -175,9 +193,20 @@ st_set_param (ddb_dsp_context_t *ctx, int p, const char *val) {
break;
case ST_PARAM_SEQUENCE_MS:
st->sequence_ms = atoi (val);
+ st->changed = 1;
break;
case ST_PARAM_SEEKWINDOW_MS:
st->seekwindow_ms = atoi (val);
+ st->changed = 1;
+ break;
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ st->set_output_samplerate = atoi (val);
+ if (st->set_output_samplerate < 8000) {
+ st->set_output_samplerate = 0;
+ }
+ else if (st->set_output_samplerate > 192000) {
+ st->set_output_samplerate = 192000;
+ }
break;
default:
fprintf (stderr, "st_param: invalid param index (%d)\n", p);
@@ -189,28 +218,31 @@ st_get_param (ddb_dsp_context_t *ctx, int p, char *val, int sz) {
ddb_soundtouch_t *st = (ddb_soundtouch_t *)ctx;
switch (p) {
case ST_PARAM_TEMPO:
- snprintf (val, sizeof (val), "%f", st->tempo);
+ snprintf (val, sz, "%f", st->tempo);
break;
case ST_PARAM_PITCH:
- snprintf (val, sizeof (val), "%f", st->pitch);
+ snprintf (val, sz, "%f", st->pitch);
break;
case ST_PARAM_RATE:
- snprintf (val, sizeof (val), "%f", st->rate);
+ snprintf (val, sz, "%f", st->rate);
break;
case ST_PARAM_USE_AA_FILTER:
- snprintf (val, sizeof (val), "%d", st->use_aa_filter);
+ snprintf (val, sz, "%d", st->use_aa_filter);
break;
case ST_PARAM_AA_FILTER_LENGTH:
- snprintf (val, sizeof (val), "%d", st->aa_filter_length);
+ snprintf (val, sz, "%d", st->aa_filter_length);
break;
case ST_PARAM_USE_QUICKSEEK:
- snprintf (val, sizeof (val), "%d", st->use_quickseek);
+ snprintf (val, sz, "%d", st->use_quickseek);
break;
case ST_PARAM_SEQUENCE_MS:
- snprintf (val, sizeof (val), "%d", st->sequence_ms);
+ snprintf (val, sz, "%d", st->sequence_ms);
break;
case ST_PARAM_SEEKWINDOW_MS:
- snprintf (val, sizeof (val), "%d", st->seekwindow_ms);
+ snprintf (val, sz, "%d", st->seekwindow_ms);
+ break;
+ case ST_PARAM_SET_OUTPUT_SAMPLERATE:
+ snprintf (val, sz, "%d", st->set_output_samplerate);
break;
default:
fprintf (stderr, "st_get_param: invalid param index (%d)\n", p);
@@ -220,7 +252,8 @@ st_get_param (ddb_dsp_context_t *ctx, int p, char *val, int sz) {
static const char settings_dlg[] =
"property \"Tempo Change (%)\" spinbtn[-200,200,1] 0 0;\n"
"property \"Pitch Change (semi-tones)\" spinbtn[-24,24,1] 1 0;\n"
- "property \"Rate Change (%)\" spinbtn[-200,200,1] 2 0;\n"
+ "property \"Playback Rate Change (%)\" spinbtn[-200,200,1] 2 0;\n"
+ "property \"Absolute Samplerate (overrides Rate Change if nonzero)\" spinbtn[0,192000,1] 8 0;\n"
"property \"Use AA Filter\" checkbox 3 0;\n"
"property \"AA Filter Length\" spinbtn[16,64,1] 4 32;\n"
"property \"Use Quickseek\" checkbox 5 0;\n"
diff --git a/plugins/supereq/supereq.c b/plugins/supereq/supereq.c
index 7c67abc1..558cbd5d 100644
--- a/plugins/supereq/supereq.c
+++ b/plugins/supereq/supereq.c
@@ -77,7 +77,7 @@ supereq_plugin_stop (void) {
}
int
-supereq_process (ddb_dsp_context_t *ctx, float *samples, int frames, ddb_waveformat_t *fmt) {
+supereq_process (ddb_dsp_context_t *ctx, float *samples, int frames, int maxframes, ddb_waveformat_t *fmt, float *r) {
ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
if (supereq->enabled != ctx->enabled) {
if (ctx->enabled && !supereq->enabled) {
diff --git a/streamer.c b/streamer.c
index 6ad348b7..a6bc924d 100644
--- a/streamer.c
+++ b/streamer.c
@@ -49,6 +49,7 @@ FILE *out;
static intptr_t streamer_tid;
static ddb_dsp_context_t *dsp_chain;
+static float dsp_ratio = 1;
static DB_dsp_t *eqplug;
static ddb_dsp_context_t *eq;
@@ -1074,13 +1075,16 @@ streamer_thread (void *ctx) {
}
int bytesread = 0;
- while (bytesread < sz-100) {
+ do {
int nb = streamer_read_async (readbuffer+bytesread,sz-bytesread);
- if (nb == 0) {
+ struct timeval tm2;
+ gettimeofday (&tm2, NULL);
+ int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+ if (ms >= alloc_time) {
break;
}
bytesread += nb;
- }
+ } while (bytesread < sz-100);
streamer_lock ();
if (bytesread > 0) {
@@ -1526,12 +1530,18 @@ streamer_read_async (char *bytes, int size) {
int nframes = inputsize / inputsamplesize;
ddb_dsp_context_t *dsp = dsp_chain;
dspfmt.samplerate = fileinfo->fmt.samplerate;
+ float ratio = 1.f;
+ int maxframes = sizeof (tempbuf) / dspsamplesize;
while (dsp) {
if (dsp->enabled) {
- nframes = dsp->plugin->process (dsp, (float *)tempbuf, nframes, &dspfmt);
+ float r = 1;
+ nframes = dsp->plugin->process (dsp, (float *)tempbuf, nframes, maxframes, &dspfmt, &r);
+ ratio *= r;
}
dsp = dsp->next;
}
+ dsp_ratio = ratio;
+
int n = pcm_convert (&dspfmt, tempbuf, &output->fmt, bytes, nframes * dspsamplesize);
bytesread = n;
@@ -1622,7 +1632,7 @@ streamer_read (char *bytes, int size) {
int sz = min (size, streamer_ringbuf.remaining);
if (sz) {
ringbuf_read (&streamer_ringbuf, bytes, sz);
- playpos += (float)sz/output->fmt.samplerate/((output->fmt.bps>>3)*output->fmt.channels);
+ playpos += (float)sz/output->fmt.samplerate/((output->fmt.bps>>3)*output->fmt.channels) * dsp_ratio;
playing_track->playtime += (float)sz/output->fmt.samplerate/((output->fmt.bps>>3)*output->fmt.channels);
if (playlist_track) {
playing_track->filetype = playlist_track->filetype;