changeset 4286:af324ff0a983

added passthrough mode. tested with ape and flac
author Eugene Zagidullin <e.asphyx@gmail.com>
date Sat, 16 Feb 2008 01:47:30 +0300
parents 314c972f2060
children 19c4a20d11a1
files src/audacious/main.c src/audacious/main.h src/audacious/output.c src/audacious/ui_preferences.c
diffstat 4 files changed, 188 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/main.c	Fri Feb 15 15:34:46 2008 +0100
+++ b/src/audacious/main.c	Sat Feb 16 01:47:30 2008 +0300
@@ -248,6 +248,7 @@
     48000,          /* samplerate */
     SRC_SINC_BEST_QUALITY, /* default interpolation method */
 #endif
+    FALSE,          /* bypass dsp */
 };
 
 typedef struct bmp_cfg_boolent_t {
@@ -367,6 +368,7 @@
 #ifdef USE_SRC
     {"enable_src",                 &cfg.enable_src, TRUE},
 #endif
+    {"bypass_dsp",                 &cfg.bypass_dsp, TRUE},
 };
 
 static gint ncfgbent = G_N_ELEMENTS(bmp_boolents);
--- a/src/audacious/main.h	Fri Feb 15 15:34:46 2008 +0100
+++ b/src/audacious/main.h	Sat Feb 16 01:47:30 2008 +0300
@@ -155,6 +155,7 @@
     gint src_rate;
     gint src_type;
 #endif
+    gboolean bypass_dsp;
 };
 
 typedef struct _BmpConfig BmpConfig;
--- a/src/audacious/output.c	Fri Feb 15 15:34:46 2008 +0100
+++ b/src/audacious/output.c	Sat Feb 16 01:47:30 2008 +0300
@@ -23,7 +23,7 @@
  *  Audacious or using our public API to be a derived work.
  */
 
-/*#define AUD_DEBUG*/
+/* #define AUD_DEBUG */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
@@ -69,6 +69,7 @@
 };
 
 static gint decoder_srate = 0;
+static gboolean bypass_dsp = FALSE;
 
 OutputPlugin psuedo_output_plugin = {
     .description = "XMMS reverse compatibility output plugin",
@@ -271,11 +272,51 @@
     if (sad_state_to_float != NULL)   {SAD_dither_free(sad_state_to_float);   sad_state_to_float = NULL;}
 }
 
+static gboolean
+reopen_audio(AFormat fmt, gint rate, gint nch)
+{
+    OutputPlugin *op = get_current_output_plugin();
+
+    if (op == NULL)
+        return FALSE;
+
+    /* Is our output port already open? */
+    if ((op_state.rate != 0 && op_state.nch != 0) &&
+        (op_state.rate == rate && op_state.nch == nch && op_state.fmt == fmt))
+    {
+        /* Yes, and it's the correct sampling rate. Reset the counter and go. */
+	AUDDBG("flushing output instead of reopening\n");
+	plugin_set_current((Plugin *)op);
+        op->flush(0);
+        return TRUE;
+    }
+    else if (op_state.rate != 0 && op_state.nch != 0)
+    {
+        plugin_set_current((Plugin *)op);
+        op->close_audio();
+    }
+
+    plugin_set_current((Plugin *)op);
+    gint ret = op->open_audio(fmt, rate, nch);
+
+    if (ret == 1)            /* Success? */
+    {
+        AUDDBG("opened audio: fmt=%d, rate=%d, nch=%d\n", fmt, rate, nch);
+        op_state.fmt = fmt;
+        op_state.rate = rate;
+        op_state.nch = nch;
+
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
 gint
 output_open_audio(AFormat fmt, gint rate, gint nch)
 {
     gint ret;
-    OutputPlugin *op;
+    /*OutputPlugin *op;*/
     AUDDBG("requested: fmt=%d, rate=%d, nch=%d\n", fmt, rate, nch);
 
     AFormat output_fmt;
@@ -284,71 +325,85 @@
     SAD_buffer_format output_sad_fmt;
 
     decoder_srate = rate;
+    bypass_dsp = cfg.bypass_dsp;
 
+    if (bypass_dsp) {
+        AUDDBG("trying to open audio in native format\n");
+        bypass_dsp = reopen_audio(fmt, rate, nch);
+        AUDDBG("opening in native fmt %s\n", bypass_dsp ? "succeeded" : "failed");
+    }
+
+    if (bypass_dsp) {
+        return TRUE;
+    } else {
 #ifdef USE_SRC
-    if(cfg.enable_src) rate = cfg.src_rate;
+        if(cfg.enable_src) rate = cfg.src_rate;
 #endif
     
-    bit_depth = cfg.output_bit_depth;
-
-    AUDDBG("bit depth: %d\n", bit_depth);
-    output_fmt = (bit_depth == 24) ? FMT_S24_NE : FMT_S16_NE;
+        bit_depth = cfg.output_bit_depth;
     
-    freeSAD();
-
-    AUDDBG("initializing dithering engine for 2 stage conversion: fmt%d --> float -->fmt%d\n", fmt, output_fmt);
-    input_sad_fmt.sample_format = sadfmt_from_afmt(fmt);
-    if (input_sad_fmt.sample_format < 0) return FALSE;
-    input_sad_fmt.fracbits = FMT_FRACBITS(fmt);
-    input_sad_fmt.channels = nch;
-    input_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
-    input_sad_fmt.samplerate = 0;
-    
-    output_sad_fmt.sample_format = SAD_SAMPLE_FLOAT;
-    output_sad_fmt.fracbits = 0;
-    output_sad_fmt.channels = nch;
-    output_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
-    output_sad_fmt.samplerate = 0;
-    
-    sad_state_to_float = SAD_dither_init(&input_sad_fmt, &output_sad_fmt, &ret);
-    if (sad_state_to_float == NULL) {
-        AUDDBG("ditherer init failed (decoder's native --> float)\n");
-        return FALSE;
-    }
-    SAD_dither_set_dither (sad_state_to_float, FALSE);
+        AUDDBG("bit depth: %d\n", bit_depth);
+        output_fmt = (bit_depth == 24) ? FMT_S24_NE : FMT_S16_NE;
+        
+        freeSAD();
     
-    input_sad_fmt.sample_format = SAD_SAMPLE_FLOAT;
-    input_sad_fmt.fracbits = 0;
-    input_sad_fmt.channels = nch;
-    input_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
-    input_sad_fmt.samplerate = 0;
-    
-    output_sad_fmt.sample_format = sadfmt_from_afmt(output_fmt);
-    if (output_sad_fmt.sample_format < 0) return FALSE;
-    output_sad_fmt.fracbits = FMT_FRACBITS(output_fmt);
-    output_sad_fmt.channels = nch;
-    output_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
-    output_sad_fmt.samplerate = 0;
+        AUDDBG("initializing dithering engine for 2 stage conversion: fmt%d --> float -->fmt%d\n", fmt, output_fmt);
+        input_sad_fmt.sample_format = sadfmt_from_afmt(fmt);
+        if (input_sad_fmt.sample_format < 0) return FALSE;
+        input_sad_fmt.fracbits = FMT_FRACBITS(fmt);
+        input_sad_fmt.channels = nch;
+        input_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
+        input_sad_fmt.samplerate = 0;
+        
+        output_sad_fmt.sample_format = SAD_SAMPLE_FLOAT;
+        output_sad_fmt.fracbits = 0;
+        output_sad_fmt.channels = nch;
+        output_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
+        output_sad_fmt.samplerate = 0;
+        
+        sad_state_to_float = SAD_dither_init(&input_sad_fmt, &output_sad_fmt, &ret);
+        if (sad_state_to_float == NULL) {
+            AUDDBG("ditherer init failed (decoder's native --> float)\n");
+            return FALSE;
+        }
+        SAD_dither_set_dither (sad_state_to_float, FALSE);
+        
+        input_sad_fmt.sample_format = SAD_SAMPLE_FLOAT;
+        input_sad_fmt.fracbits = 0;
+        input_sad_fmt.channels = nch;
+        input_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
+        input_sad_fmt.samplerate = 0;
+        
+        output_sad_fmt.sample_format = sadfmt_from_afmt(output_fmt);
+        if (output_sad_fmt.sample_format < 0) return FALSE;
+        output_sad_fmt.fracbits = FMT_FRACBITS(output_fmt);
+        output_sad_fmt.channels = nch;
+        output_sad_fmt.channels_order = SAD_CHORDER_INTERLEAVED;
+        output_sad_fmt.samplerate = 0;
+        
+        sad_state_from_float = SAD_dither_init(&input_sad_fmt, &output_sad_fmt, &ret);
+        if (sad_state_from_float == NULL) {
+            SAD_dither_free(sad_state_to_float);
+            AUDDBG("ditherer init failed (float --> output)\n");
+            return FALSE;
+        }
+        SAD_dither_set_dither (sad_state_from_float, TRUE);
+        
+        fmt = output_fmt;
     
-    sad_state_from_float = SAD_dither_init(&input_sad_fmt, &output_sad_fmt, &ret);
-    if (sad_state_from_float == NULL) {
-        SAD_dither_free(sad_state_to_float);
-        AUDDBG("ditherer init failed (float --> output)\n");
-        return FALSE;
-    }
-    SAD_dither_set_dither (sad_state_from_float, TRUE);
+        if(replay_gain_info.album_peak == 0.0 && replay_gain_info.track_peak == 0.0) {
+            AUDDBG("RG info isn't set yet. Filling replay_gain_info with default values.\n");
+            replay_gain_info.track_gain = cfg.default_gain;
+            replay_gain_info.track_peak = 0.01;
+            replay_gain_info.album_gain = cfg.default_gain;
+            replay_gain_info.album_peak = 0.01;
+        }
+        apply_replaygain_info(&replay_gain_info);
     
-    fmt = output_fmt;
-
-    if(replay_gain_info.album_peak == 0.0 && replay_gain_info.track_peak == 0.0) {
-        AUDDBG("RG info isn't set yet. Filling replay_gain_info with default values.\n");
-        replay_gain_info.track_gain = cfg.default_gain;
-        replay_gain_info.track_peak = 0.01;
-        replay_gain_info.album_gain = cfg.default_gain;
-        replay_gain_info.album_peak = 0.01;
-    }
-    apply_replaygain_info(&replay_gain_info);
+        return reopen_audio(fmt, rate, nch);
+    } /* bypass_dsp */
     
+#if 0
     op = get_current_output_plugin();
 
     if (op == NULL)
@@ -382,6 +437,7 @@
     }
 
     return ret;
+#endif
 }
 
 void
@@ -499,64 +555,67 @@
     gint writeoffs;
     gpointer float_ptr;
 
-    if(length <= 0 || sad_state_from_float == NULL || sad_state_to_float == NULL) return;
-    
-    plugin_set_current((Plugin *)(playback->output));
-    gint time = playback->output->written_time();
+    if (!bypass_dsp) {
 
-    if (legacy_flow == NULL)
-    {
-        legacy_flow = flow_new();
-        flow_link_element(legacy_flow, iir_flow);
-        flow_link_element(legacy_flow, effect_flow);
-    }
-    
-    if (postproc_flow == NULL)
-    {
-        postproc_flow = flow_new();
-        flow_link_element(postproc_flow, vis_flow);
-#ifdef USE_SRC
-        flow_link_element(postproc_flow, src_flow);
-#endif
-        flow_link_element(postproc_flow, volumecontrol_flow);
-    }
-
-    int frames = length / nch / FMT_SIZEOF(fmt);
-    int len = frames * nch * sizeof(float);
-    if(sad_float_buf == NULL || sad_float_buf_length < len) {
-        sad_float_buf_length = len;
-        sad_float_buf = smart_realloc(sad_float_buf, &sad_float_buf_length);
-    }
+        if(length <= 0 || sad_state_from_float == NULL || sad_state_to_float == NULL) return;
+        
+        plugin_set_current((Plugin *)(playback->output));
+        gint time = playback->output->written_time();
 
-    SAD_dither_process_buffer(sad_state_to_float, ptr, sad_float_buf, frames);
-    float_ptr = sad_float_buf;
+        if (legacy_flow == NULL)
+        {
+            legacy_flow = flow_new();
+            flow_link_element(legacy_flow, iir_flow);
+            flow_link_element(legacy_flow, effect_flow);
+        }
+        
+        if (postproc_flow == NULL)
+        {
+            postproc_flow = flow_new();
+            flow_link_element(postproc_flow, vis_flow);
+#ifdef USE_SRC
+            flow_link_element(postproc_flow, src_flow);
+#endif
+            flow_link_element(postproc_flow, volumecontrol_flow);
+        }
     
-    length = flow_execute(postproc_flow,
-                          time,
-                          &float_ptr,
-                          len,
-                          FMT_FLOAT,
-                          decoder_srate,
-                          nch);
+        int frames = length / nch / FMT_SIZEOF(fmt);
+        int len = frames * nch * sizeof(float);
+        if(sad_float_buf == NULL || sad_float_buf_length < len) {
+            sad_float_buf_length = len;
+            sad_float_buf = smart_realloc(sad_float_buf, &sad_float_buf_length);
+        }
     
-    frames = length / nch / sizeof(float);
-    len = frames * nch * FMT_SIZEOF(op_state.fmt);
-    if(sad_out_buf == NULL || sad_out_buf_length < len) {
-        sad_out_buf_length = len;
-        sad_out_buf = smart_realloc(sad_out_buf, &sad_out_buf_length);
-    }
-
-    SAD_dither_process_buffer(sad_state_from_float, float_ptr, sad_out_buf, frames);
-
-    length = len;
-    ptr = sad_out_buf;
+        SAD_dither_process_buffer(sad_state_to_float, ptr, sad_float_buf, frames);
+        float_ptr = sad_float_buf;
+        
+        length = flow_execute(postproc_flow,
+                              time,
+                              &float_ptr,
+                              len,
+                              FMT_FLOAT,
+                              decoder_srate,
+                              nch);
+        
+        frames = length / nch / sizeof(float);
+        len = frames * nch * FMT_SIZEOF(op_state.fmt);
+        if(sad_out_buf == NULL || sad_out_buf_length < len) {
+            sad_out_buf_length = len;
+            sad_out_buf = smart_realloc(sad_out_buf, &sad_out_buf_length);
+        }
     
-    if (op_state.fmt == FMT_S16_NE || (op_state.fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) ||
-                                      (op_state.fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN)) {
-        length = flow_execute(legacy_flow, time, &ptr, length, op_state.fmt, op_state.rate, op_state.nch);
-    } else {
-        AUDDBG("legacy_flow can deal only with S16_NE streams\n"); /*FIXME*/
-    }
+        SAD_dither_process_buffer(sad_state_from_float, float_ptr, sad_out_buf, frames);
+    
+        length = len;
+        ptr = sad_out_buf;
+    
+        if (op_state.fmt == FMT_S16_NE || (op_state.fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) ||
+                                          (op_state.fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN)) {
+            length = flow_execute(legacy_flow, time, &ptr, length, op_state.fmt, op_state.rate, op_state.nch);
+        } else {
+            AUDDBG("legacy_flow can deal only with S16_NE streams\n"); /*FIXME*/
+        }
+    } /* !bypass_dsp */
 
     /**** write it out ****/
 
--- a/src/audacious/ui_preferences.c	Fri Feb 15 15:34:46 2008 +0100
+++ b/src/audacious/ui_preferences.c	Sat Feb 16 01:47:30 2008 +0300
@@ -225,7 +225,19 @@
     {WIDGET_LABEL, N_("<b>Bit Depth</b>"), NULL, NULL, NULL, FALSE},
     {WIDGET_CUSTOM, NULL, NULL, NULL, NULL, FALSE, ui_preferences_bit_depth},
 };
-    
+
+static PreferencesWidget audio_page_widgets2[] = {
+    {WIDGET_LABEL, N_("<b>Volume Control</b>"), NULL, NULL, NULL, FALSE},
+    {WIDGET_CHK_BTN, N_("Use software volume control"), &cfg.software_volume_control, NULL,
+                     N_("Use software volume control. This may be useful for situations where your audio system does not support"
+                        "controlling the playback volume."), FALSE},
+    {WIDGET_LABEL,   N_("<b>Advanced</b>"), NULL, NULL, NULL, FALSE},
+    {WIDGET_CHK_BTN, N_("Bypass all of signal processing if possible"), &cfg.bypass_dsp, NULL,
+                     N_("Try to pass input plugin's output directly to output plugin, if the latter supports "
+                        "format produced by input plugin. If it's true, all signal processing will be disabled "
+                        "(i.e. DSP plugins, equalizer, Replay Gain and software volume control)."), FALSE},
+};
+
 static PreferencesWidget replay_gain_page_widgets[] = {
     {WIDGET_LABEL, N_("<b>Replay Gain configuration</b>"), NULL, NULL, NULL, FALSE},
     {WIDGET_CHK_BTN, N_("Enable Replay Gain"), &cfg.enable_replay_gain, NULL, NULL, FALSE},
@@ -927,18 +939,6 @@
 }
 
 static void
-on_software_volume_control_toggled(GtkToggleButton * button, gpointer data)
-{
-    cfg.software_volume_control = gtk_toggle_button_get_active(button);
-}
-
-static void
-on_software_volume_control_realize(GtkToggleButton * button, gpointer data)
-{
-    gtk_toggle_button_set_active(button, cfg.software_volume_control);
-}
-
-static void
 on_skin_refresh_button_clicked(GtkButton * button,
                                gpointer data)
 {
@@ -2278,10 +2278,6 @@
     GtkWidget *src_rate;
     GtkWidget *label91;
     GtkWidget *alignment4;
-    GtkWidget *label2;
-    GtkWidget *alignment7;
-    GtkWidget *software_volume_control;
-
     
     audio_page_vbox = gtk_vbox_new (FALSE, 0);
     gtk_container_add (GTK_CONTAINER (category_notebook), audio_page_vbox);
@@ -2463,20 +2459,8 @@
     alignment4 = gtk_alignment_new (0.5, 0.5, 1, 1);
     gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment4, FALSE, FALSE, 0);
     gtk_alignment_set_padding (GTK_ALIGNMENT (alignment4), 12, 12, 0, 0);
-
-    label2 = gtk_label_new (_("<b>Volume Control</b>"));
-    gtk_container_add (GTK_CONTAINER (alignment4), label2);
-    gtk_label_set_use_markup (GTK_LABEL (label2), TRUE);
-    gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
-
-    alignment7 = gtk_alignment_new (0.5, 0.5, 1, 1);
-    gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment7, FALSE, FALSE, 0);
-    gtk_alignment_set_padding (GTK_ALIGNMENT (alignment7), 0, 0, 12, 0);
-
-    software_volume_control = gtk_check_button_new_with_mnemonic (_("Use software volume control"));
-    gtk_container_add (GTK_CONTAINER (alignment7), software_volume_control);
-    gtk_tooltips_set_tip (tooltips, software_volume_control, _("Use software volume control. This may be useful for situations where your audio system does not support controlling the playback volume."), NULL);
-
+    
+    create_widgets(GTK_BOX(audio_page_vbox), audio_page_widgets2, G_N_ELEMENTS(audio_page_widgets2));
 
     g_signal_connect(G_OBJECT(output_plugin_bufsize), "value_changed",
                      G_CALLBACK(on_output_plugin_bufsize_value_changed),
@@ -2505,12 +2489,6 @@
     g_signal_connect(G_OBJECT(src_rate), "realize",
                      G_CALLBACK(on_src_rate_realize),
                      NULL);
-    g_signal_connect(G_OBJECT(software_volume_control), "toggled",
-                     G_CALLBACK(on_software_volume_control_toggled),
-                     NULL);
-    g_signal_connect(G_OBJECT(software_volume_control), "realize",
-                     G_CALLBACK(on_software_volume_control_realize),
-                     NULL);
 
     /* plugin->output page */