From 2d0b6eda861e5bfcdce1ca43afb013d15b9d73b5 Mon Sep 17 00:00:00 2001 From: waker Date: Thu, 30 Dec 2010 20:23:23 +0100 Subject: streamer dsp chain WIP --- deadbeef.h | 2 - plugins.c | 1 + plugins/converter/converter.c | 2 +- plugins/dsp_libsrc/src.c | 1 + plugins/gtkui/dspconfig.c | 10 ++ plugins/gtkui/eq.c | 11 +- plugins/supereq/supereq.c | 33 ++-- streamer.c | 398 ++++++++++++++++++++++++++++++------------ streamer.h | 3 + 9 files changed, 320 insertions(+), 141 deletions(-) diff --git a/deadbeef.h b/deadbeef.h index cce2d13b..605508e4 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -789,8 +789,6 @@ typedef struct DB_dsp_s { void (*reset) (ddb_dsp_context_t *ctx); - void (*enable) (ddb_dsp_context_t *ctx, int e); - // num_params can be NULL, to indicate that plugin doesn't expose any params // // if num_params is non-NULL -- get_param_name, set_param and get_param must diff --git a/plugins.c b/plugins.c index 0e4609d1..5c2f5d97 100644 --- a/plugins.c +++ b/plugins.c @@ -89,6 +89,7 @@ static DB_functions_t deadbeef_api = { .streamer_get_current_fileinfo = streamer_get_current_fileinfo, .streamer_get_current_playlist = streamer_get_current_playlist, .streamer_get_dsp_chain = streamer_get_dsp_chain, + .streamer_set_dsp_chain = streamer_set_dsp_chain, // folders .get_config_dir = plug_get_config_dir, .get_prefix = plug_get_prefix, diff --git a/plugins/converter/converter.c b/plugins/converter/converter.c index 061306b6..78c25d40 100644 --- a/plugins/converter/converter.c +++ b/plugins/converter/converter.c @@ -390,7 +390,7 @@ dsp_preset_save (ddb_dsp_preset_t *p, int overwrite) { } } - FILE *fp = fopen (path, "w+b"); + FILE *fp = fopen (path, "w+t"); if (!fp) { return -1; } diff --git a/plugins/dsp_libsrc/src.c b/plugins/dsp_libsrc/src.c index fdb96d14..1909fa6e 100644 --- a/plugins/dsp_libsrc/src.c +++ b/plugins/dsp_libsrc/src.c @@ -177,6 +177,7 @@ ddb_src_process (ddb_dsp_context_t *_src, float *samples, int nframes, ddb_wavef //} //fwrite (input, 1, numoutframes*sizeof(float)*(*nchannels), out); + fmt->samplerate = src->samplerate; return numoutframes; } diff --git a/plugins/gtkui/dspconfig.c b/plugins/gtkui/dspconfig.c index ad2e34a1..6853e8a7 100644 --- a/plugins/gtkui/dspconfig.c +++ b/plugins/gtkui/dspconfig.c @@ -47,6 +47,7 @@ dsp_clone (ddb_dsp_context_t *from) { dsp->plugin->set_param (dsp, i, param); } } + dsp->enabled = from->enabled; return dsp; } @@ -114,6 +115,11 @@ fill_dsp_plugin_list (GtkListStore *mdl) { } } +static void +update_streamer (void) { + deadbeef->streamer_set_dsp_chain (chain); +} + void on_dsp_add_clicked (GtkButton *button, gpointer user_data) @@ -161,6 +167,7 @@ on_dsp_add_clicked (GtkButton *button, GtkListStore *mdl = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list))); gtk_list_store_clear (mdl); fill_dsp_chain (mdl); + update_streamer (); } else { fprintf (stderr, "prefwin: failed to add DSP plugin to chain\n"); @@ -216,6 +223,7 @@ on_dsp_remove_clicked (GtkButton *button, GtkTreeViewColumn *col; gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE); gtk_tree_path_free (path); + update_streamer (); } } @@ -327,6 +335,7 @@ on_dsp_up_clicked (GtkButton *button, GtkTreeViewColumn *col; gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE); gtk_tree_path_free (path); + update_streamer (); } @@ -347,5 +356,6 @@ on_dsp_down_clicked (GtkButton *button, GtkTreeViewColumn *col; gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, col, FALSE); gtk_tree_path_free (path); + update_streamer (); } diff --git a/plugins/gtkui/eq.c b/plugins/gtkui/eq.c index 1917e871..a985cf50 100644 --- a/plugins/gtkui/eq.c +++ b/plugins/gtkui/eq.c @@ -57,14 +57,6 @@ set_param (ddb_dsp_context_t *eq, int i, float v) { char fv[100]; snprintf (fv, sizeof (fv), "%f", v); eq->plugin->set_param (eq, i, fv); - if (i == 0) { - deadbeef->conf_set_float ("eq.preamp", v); - } - else { - char s[100]; - snprintf (s, sizeof (s), "eq.band%d", i-1); - deadbeef->conf_set_float (s, v); - } } void @@ -85,8 +77,7 @@ on_enable_toggled (GtkToggleButton *togglebutton, ddb_dsp_context_t *eq = get_supereq (); if (eq) { int enabled = gtk_toggle_button_get_active (togglebutton) ? 1 : 0; - eq->plugin->enable (eq, enabled); - deadbeef->conf_set_int ("eq.enable", enabled); + eq->enabled = enabled; } } diff --git a/plugins/supereq/supereq.c b/plugins/supereq/supereq.c index 9e957116..79a0bd5d 100644 --- a/plugins/supereq/supereq.c +++ b/plugins/supereq/supereq.c @@ -37,6 +37,7 @@ typedef struct { int params_changed; uintptr_t mutex; SuperEqState state; + int enabled; } ddb_supereq_ctx_t; void supereq_reset (ddb_dsp_context_t *ctx); @@ -78,6 +79,19 @@ supereq_plugin_stop (void) { int supereq_process (ddb_dsp_context_t *ctx, float *samples, int frames, ddb_waveformat_t *fmt) { ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx; + if (supereq->enabled != ctx->enabled) { + if (ctx->enabled && !supereq->enabled) { + supereq_reset (ctx); + } + supereq->enabled = ctx->enabled; + + DB_playItem_t *it = deadbeef->streamer_get_playing_track (); + if (it) { + float playpos = deadbeef->streamer_get_playpos (); + deadbeef->streamer_seek (playpos); + deadbeef->pl_item_unref (it); + } + } if (supereq->params_changed) { recalc_table (supereq); supereq->params_changed = 0; @@ -138,24 +152,6 @@ supereq_reset (ddb_dsp_context_t *ctx) { deadbeef->mutex_unlock (supereq->mutex); } -void -supereq_enable (ddb_dsp_context_t *ctx, int e) { - ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx; - if (e != supereq->ctx.enabled) { - if (e && !supereq->ctx.enabled) { - supereq_reset (ctx); - } - supereq->ctx.enabled = e; - } - - DB_playItem_t *it = deadbeef->streamer_get_playing_track (); - if (it) { - float playpos = deadbeef->streamer_get_playpos (); - deadbeef->streamer_seek (playpos); - deadbeef->pl_item_unref (it); - } -} - int supereq_num_params (void) { return 19; @@ -303,7 +299,6 @@ static DB_dsp_t plugin = { .close = supereq_close, .process = supereq_process, .reset = supereq_reset, - .enable = supereq_enable, .num_params = supereq_num_params, .get_param_name = supereq_get_param_name, .set_param = supereq_set_param, diff --git a/streamer.c b/streamer.c index a88dd639..7dcd28ad 100644 --- a/streamer.c +++ b/streamer.c @@ -36,7 +36,6 @@ #include "volume.h" #include "vfs.h" #include "premix.h" -#include "plugins/dsp_libsrc/src.h" #include "ringbuf.h" //#define trace(...) { fprintf(stderr, __VA_ARGS__); } @@ -49,10 +48,9 @@ FILE *out; #endif static intptr_t streamer_tid; -static DB_dsp_t *srcplug; -static DB_dsp_t *eqplug; static ddb_dsp_context_t *dsp_chain; -static ddb_dsp_context_t *src; + +static DB_dsp_t *eqplug; static ddb_dsp_context_t *eq; static int conf_replaygain_mode = 0; @@ -83,7 +81,9 @@ static playlist_t *streamer_playlist; static playItem_t *playing_track; static playItem_t *streaming_track; static playItem_t *playlist_track; -static ddb_waveformat_t prevformat; + +static ddb_waveformat_t output_format; +static int formatchanged; static DB_fileinfo_t *fileinfo; @@ -655,8 +655,6 @@ streamer_set_current (playItem_t *it) { mutex_unlock (decodemutex); trace ("bps=%d, channels=%d, samplerate=%d\n", fileinfo->fmt.bps, fileinfo->fmt.channels, fileinfo->fmt.samplerate); } -// FIXME: that might break streaming at boundaries between 2 different samplerates -// streamer_reset (0); // reset SRC } else { trace ("no decoder in playitem!\n"); @@ -809,11 +807,11 @@ streamer_start_new_song (void) { avg_bitrate = -1; if (output->state () != OUTPUT_STATE_PLAYING) { streamer_reset (1); - if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { - memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t)); - plug_get_output ()->setformat (&fileinfo->fmt); + if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { + memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t)); + plug_get_output ()->setformat (&output_format); } - if (output->play () < 0) { + if (0 != output->play ()) { fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); streamer_set_nextsong (-2, 0); } @@ -824,14 +822,9 @@ streamer_start_new_song (void) { last_bitrate = -1; avg_bitrate = -1; streamer_reset (1); - if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { - memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t)); - plug_get_output ()->setformat (&fileinfo->fmt); - } - if (output->play () < 0) { - fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); - streamer_set_nextsong (-2, 0); - return; + if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { + memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t)); + formatchanged = 1; } } output->pause (); @@ -920,53 +913,45 @@ streamer_thread (void *ctx) { playpos = 0; seekpos = -1; - // try to switch samplerate to the closest supported by output plugin - if (conf_get_int ("playback.dynsamplerate", 0)) { - - // don't switch if unchanged - ddb_waveformat_t prevfmt; - memcpy (&prevfmt, &output->fmt, sizeof (ddb_waveformat_t)); - if (memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { - memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t)); - output->setformat (&fileinfo->fmt); - // check if the format actually changed - if (memcmp (&output->fmt, &prevfmt, sizeof (ddb_waveformat_t))) { - // restart streaming of current track - trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevfmt.samplerate, output->fmt.samplerate); - mutex_lock (decodemutex); - fileinfo->plugin->free (fileinfo); - fileinfo = NULL; - DB_decoder_t *dec = NULL; - dec = plug_get_decoder_for_id (streaming_track->decoder_id); - if (dec) { - fileinfo = dec->open (0); - if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) < 0) { - dec->free (fileinfo); - fileinfo = NULL; - } - } - if (!dec || !fileinfo) { - // FIXME: handle error +#if 0 + // don't switch if unchanged + ddb_waveformat_t prevfmt; + memcpy (&prevfmt, &output->fmt, sizeof (ddb_waveformat_t)); + if (memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { + memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t)); + output->setformat (&fileinfo->fmt); + // check if the format actually changed + if (memcmp (&output->fmt, &prevfmt, sizeof (ddb_waveformat_t))) { + // restart streaming of current track + trace ("streamer: output samplerate changed from %d to %d; restarting track\n", prevfmt.samplerate, output->fmt.samplerate); + mutex_lock (decodemutex); + fileinfo->plugin->free (fileinfo); + fileinfo = NULL; + DB_decoder_t *dec = NULL; + dec = plug_get_decoder_for_id (streaming_track->decoder_id); + if (dec) { + fileinfo = dec->open (0); + if (fileinfo && dec->init (fileinfo, DB_PLAYITEM (streaming_track)) < 0) { + dec->free (fileinfo); + fileinfo = NULL; } - mutex_unlock (decodemutex); - bytes_until_next_song = -1; - streamer_buffering = 1; - streamer_reset (1); } + if (!dec || !fileinfo) { + // FIXME: handle error + } + mutex_unlock (decodemutex); + bytes_until_next_song = -1; + streamer_buffering = 1; + streamer_reset (1); } + } +#endif - // output plugin may stop playback before switching samplerate - if (output->state () != OUTPUT_STATE_PLAYING) { - if (fileinfo && memcmp (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { - memcpy (&prevformat, &fileinfo->fmt, sizeof (ddb_waveformat_t)); - plug_get_output ()->setformat (&fileinfo->fmt); - } - if (output->play () < 0) { - fprintf (stderr, "streamer: failed to start playback after samplerate change; output plugin doesn't work\n"); - streamer_set_nextsong (-2, 0); - streamer_unlock (); - continue; - } + // output plugin may stop playback before switching samplerate + if (output->state () != OUTPUT_STATE_PLAYING) { + if (fileinfo && memcmp (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t))) { + memcpy (&output_format, &fileinfo->fmt, sizeof (ddb_waveformat_t)); + formatchanged = 1; } } streamer_unlock (); @@ -1128,44 +1113,185 @@ streamer_thread (void *ctx) { mutex_unlock (decodemutex); } -int -streamer_init (void) { -#if WRITE_DUMP - out = fopen ("out.raw", "w+b"); -#endif - mutex = mutex_create (); - decodemutex = mutex_create (); +void +streamer_dsp_chain_free (ddb_dsp_context_t *dsp_chain) { + while (dsp_chain) { + ddb_dsp_context_t *next = dsp_chain->next; + dsp_chain->plugin->close (dsp_chain); + dsp_chain = next; + } +} - ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE); +ddb_dsp_context_t * +streamer_dsp_chain_load (const char *fname) { + int err = 1; + FILE *fp = fopen (fname, "rt"); + if (!fp) { + return NULL; + } + + char temp[100]; + ddb_dsp_context_t *chain = NULL; + ddb_dsp_context_t *tail = NULL; + for (;;) { + // plugin enabled { + int enabled = 0; + int err = fscanf (fp, "%100s %d {\n", temp, &enabled); + if (err == EOF) { + break; + } + else if (2 != err) { + fprintf (stderr, "error plugin name\n"); + goto error; + } - pl_set_order (conf_get_int ("playback.order", 0)); + DB_dsp_t *plug = (DB_dsp_t *)deadbeef->plug_get_for_id (temp); + if (!plug) { + fprintf (stderr, "streamer_dsp_chain_load: plugin %s not found. preset will not be loaded\n", temp); + goto error; + } + ddb_dsp_context_t *ctx = plug->open (); + if (!ctx) { + fprintf (stderr, "streamer_dsp_chain_load: failed to open ctxance of plugin %s\n", temp); + goto error; + } + + if (tail) { + tail->next = ctx; + tail = ctx; + } + else { + tail = chain = ctx; + } + + int n = 0; + for (;;) { + char value[1000]; + if (!fgets (temp, sizeof (temp), fp)) { + fprintf (stderr, "streamer_dsp_chain_load: unexpected eof while reading plugin params\n"); + goto error; + } + if (!strcmp (temp, "}\n")) { + break; + } + else if (1 != sscanf (temp, "\t%1000[^\n]\n", value)) { + fprintf (stderr, "streamer_dsp_chain_load: error loading param %d\n", n); + goto error; + } + if (plug->num_params) { + plug->set_param (ctx, n, value); + } + n++; + } + ctx->enabled = enabled; + } - // find src plugin, and use it if found - srcplug = (DB_dsp_t*)plug_get_for_id ("SRC"); - if (srcplug) { - src = srcplug->open (); - srcplug->set_param (src, SRC_PARAM_QUALITY, conf_get_str ("src_quality", "2")); - src->next = dsp_chain; - dsp_chain = src; + err = 0; +error: + if (err) { + fprintf (stderr, "streamer_dsp_chain_load: error loading %s\n", fname); } + if (fp) { + fclose (fp); + } + if (err && chain) { + streamer_dsp_chain_free (chain); + chain = NULL; + } + return chain; +} + +int +streamer_dsp_chain_save (const char *fname, ddb_dsp_context_t *chain) { + FILE *fp = fopen (fname, "w+t"); + if (!fp) { + return -1; + } + + ddb_dsp_context_t *ctx = chain; + while (ctx) { + fprintf (fp, "%s %d {\n", ctx->plugin->plugin.id, (int)ctx->enabled); + if (ctx->plugin->num_params) { + int n = ctx->plugin->num_params (); + int i; + for (i = 0; i < n; i++) { + char v[1000]; + ctx->plugin->get_param (ctx, i, v, sizeof (v)); + fprintf (fp, "\t%s\n", v); + } + } + fprintf (fp, "}\n"); + ctx = ctx->next; + } + + fclose (fp); + return 0; +} + +void +streamer_dsp_postinit (void) { + // note about EQ hack: + // we 1st check if there's an EQ in dsp chain, and just use it + // if not -- we add our own // eq plug - eqplug = (DB_dsp_t *)plug_get_for_id ("supereq"); if (eqplug) { - eq = eqplug->open (); + ddb_dsp_context_t *p; + + for (p = dsp_chain; p; p = p->next) { + if (!strcmp (p->plugin->plugin.id, "supereq")) { + break; + } + } + if (p) { + eq = p; + } + else { + eq = eqplug->open (); + eq->next = dsp_chain; + dsp_chain = eq; + } + + } +} + +void +streamer_dsp_init (void) { + // load dsp chain from file + char fname[PATH_MAX]; + snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ()); + dsp_chain = streamer_dsp_chain_load (fname); + + eqplug = (DB_dsp_t *)plug_get_for_id ("supereq"); + streamer_dsp_postinit (); - // load settings - eqplug->enable (eq, deadbeef->conf_get_int ("eq.enable", 0)); - eqplug->set_param (eq, 0, conf_get_str ("eq.preamp", "1")); + // load legacy eq settings from pre-0.5 + if (conf_find ("eq.", NULL)) { + eq->enabled = deadbeef->conf_get_int ("eq.enable", 0); + eqplug->set_param (eq, 0, conf_get_str ("eq.preamp", "0")); for (int i = 0; i < 18; i++) { char key[100]; snprintf (key, sizeof (key), "eq.band%d", i); - eqplug->set_param (eq, 1+i, conf_get_str (key, "1")); + eqplug->set_param (eq, 1+i, conf_get_str (key, "0")); } - - eq->next = dsp_chain; - dsp_chain = eq; + // delete obsolete settings + conf_remove_items ("eq."); } +} + +int +streamer_init (void) { +#if WRITE_DUMP + out = fopen ("out.raw", "w+b"); +#endif + mutex = mutex_create (); + decodemutex = mutex_create (); + + ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE); + + pl_set_order (conf_get_int ("playback.order", 0)); + + streamer_dsp_init (); conf_replaygain_mode = conf_get_int ("replaygain_mode", 0); conf_replaygain_scale = conf_get_int ("replaygain_scale", 1); @@ -1198,16 +1324,16 @@ streamer_free (void) { decodemutex = 0; mutex_free (mutex); mutex = 0; - if (srcplug && src) { - srcplug->close (src); - srcplug = NULL; - src = NULL; - } - if (eqplug && eq) { - eqplug->close (eq); - eqplug = NULL; - eq = NULL; - } + + char fname[PATH_MAX]; + snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ()); + streamer_dsp_chain_save (fname, dsp_chain); + + streamer_dsp_chain_free (dsp_chain); + dsp_chain = NULL; + + eqplug = NULL; + eq = NULL; } void @@ -1385,14 +1511,6 @@ streamer_read_async (char *bytes, int size) { // convert to float int tempsize = pcm_convert (&fileinfo->fmt, input, &dspfmt, tempbuf, inputsize); - if (srcplug) { - // FIXME: update on change only, conversion from float to - // str and back is slow - char s[100]; - snprintf (s, sizeof (s), "%d", dspfmt.samplerate); - srcplug->set_param (src, SRC_PARAM_SAMPLERATE, s); - } - int nframes = inputsize / inputsamplesize; ddb_dsp_context_t *dsp = dsp_chain; dspfmt.samplerate = fileinfo->fmt.samplerate; @@ -1405,6 +1523,17 @@ streamer_read_async (char *bytes, int size) { int n = pcm_convert (&dspfmt, tempbuf, &output->fmt, bytes, nframes * dspsamplesize); bytesread = n; + + ddb_waveformat_t outfmt; + outfmt.bps = output->fmt.bps; + outfmt.is_float = output->fmt.is_float; + outfmt.channels = dspfmt.channels; + outfmt.samplerate = dspfmt.samplerate; + outfmt.channelmask = dspfmt.channelmask; + if (memcmp (&output_format, &outfmt, sizeof (ddb_waveformat_t))) { + memcpy (&output_format, &outfmt, sizeof (ddb_waveformat_t)); + formatchanged = 1; + } } } else { @@ -1468,6 +1597,15 @@ streamer_read (char *bytes, int size) { return -1; } DB_output_t *output = plug_get_output (); + if (formatchanged && bytes_until_next_song <= 0) { + formatchanged = 0; + plug_get_output ()->setformat (&output_format); + if (0 != output->play ()) { + fprintf (stderr, "streamer: failed to start playback; output plugin doesn't work\n"); + streamer_set_nextsong (-2, 0); + return -1; + } + } streamer_lock (); int sz = min (size, streamer_ringbuf.remaining); if (sz) { @@ -1593,10 +1731,6 @@ streamer_configchanged (void) { conf_replaygain_mode = conf_get_int ("replaygain_mode", 0); conf_replaygain_scale = conf_get_int ("replaygain_scale", 1); pl_set_order (conf_get_int ("playback.order", 0)); - - if (srcplug) { - srcplug->set_param (src, SRC_PARAM_QUALITY, conf_get_str ("src_quality", "2")); - } } void @@ -1662,3 +1796,49 @@ ddb_dsp_context_t * streamer_get_dsp_chain (void) { return dsp_chain; } + +static ddb_dsp_context_t * +dsp_clone (ddb_dsp_context_t *from) { + ddb_dsp_context_t *dsp = from->plugin->open (); + char param[2000]; + if (from->plugin->num_params) { + int n = from->plugin->num_params (); + for (int i = 0; i < n; i++) { + from->plugin->get_param (from, i, param, sizeof (param)); + dsp->plugin->set_param (dsp, i, param); + } + } + dsp->enabled = from->enabled; + return dsp; +} + +void +streamer_set_dsp_chain (ddb_dsp_context_t *chain) { + mutex_lock (decodemutex); + streamer_dsp_chain_free (dsp_chain); + + dsp_chain = NULL; + eq = NULL; + + ddb_dsp_context_t *tail = NULL; + while (chain) { + printf ("copy %s\n", chain->plugin->plugin.id); + ddb_dsp_context_t *new = dsp_clone (chain); + if (tail) { + tail->next = new; + tail = new; + } + else { + dsp_chain = tail = new; + } + chain = chain->next; + } + + streamer_dsp_postinit (); + + char fname[PATH_MAX]; + snprintf (fname, sizeof (fname), "%s/dspconfig", plug_get_config_dir ()); + streamer_dsp_chain_save (fname, dsp_chain); + + mutex_unlock (decodemutex); +} diff --git a/streamer.h b/streamer.h index 7a65c95c..77165bae 100644 --- a/streamer.h +++ b/streamer.h @@ -111,4 +111,7 @@ streamer_notify_playlist_deleted (playlist_t *plt); struct ddb_dsp_context_s * streamer_get_dsp_chain (void); +void +streamer_set_dsp_chain (struct ddb_dsp_context_s *chain); + #endif // __STREAMER_H -- cgit v1.2.3