changeset 2538:719e0898ff3c trunk

[svn] - Patch to use libsamplerate for high-quality interpolated upsampling, similar to what foobar2000 can do. Patch by Teru KAMOGASHIRA.
author nenolod
date Sat, 17 Feb 2007 02:19:35 -0800
parents 7aac1b5ef85d
children 76724f3da0e1
files ChangeLog configure.ac mk/rules.mk.in src/audacious/Makefile src/audacious/build_stamp.c src/audacious/glade/prefswin.glade src/audacious/output.c src/audacious/ui_preferences.c
diffstat 8 files changed, 501 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Feb 17 01:54:30 2007 -0800
+++ b/ChangeLog	Sat Feb 17 02:19:35 2007 -0800
@@ -1,3 +1,14 @@
+2007-02-17 09:54:30 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
+  revision [4084]
+  - reinstate rcfile class for now
+  
+  trunk/src/audacious/Makefile       |    2 
+  trunk/src/audacious/rcfile.c       |  565 +++++++++++++++++++++++++++++++++++++
+  trunk/src/audacious/rcfile.h       |   94 ++++++
+  trunk/src/audacious/ui_equalizer.c |    2 
+  4 files changed, 662 insertions(+), 1 deletion(-)
+
+
 2007-02-17 09:02:11 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
   revision [4082]
   - relocate configdb to audacious core
--- a/configure.ac	Sat Feb 17 01:54:30 2007 -0800
+++ b/configure.ac	Sat Feb 17 02:19:35 2007 -0800
@@ -204,6 +204,20 @@
 AC_SUBST(CHARDET_LIBS)
 AC_SUBST(SUBDIR_GUESS)
 
+dnl libsamplerate support
+dnl ========================
+AC_ARG_ENABLE(samplerate,
+  [  --enable-samplerate          enable libsamplerate support (default=no)],
+  [cv_samplerate="$enable_samplerate"], [cv_samplerate="no"])
+if test "x$cv_samplerate" = "xyes"; then
+   AC_DEFINE(USE_SRC, 1, [Define if libsamplerate enabled] )
+   PKG_CHECK_MODULES(samplerate, samplerate)
+   AC_SUBST(USE_SRC)
+   AC_SUBST(samplerate_CFLAGS)
+   AC_SUBST(samplerate_LIBS)
+   AC_CHECK_LIB(samplerate, src_process,,AC_MSG_ERROR([*** Unable to find libsamplerate library!]))
+fi
+
 dnl regex support (gnu/oniguruma/pcre)
 dnl ========================
 REGEX_LIBS=
--- a/mk/rules.mk.in	Sat Feb 17 01:54:30 2007 -0800
+++ b/mk/rules.mk.in	Sat Feb 17 02:19:35 2007 -0800
@@ -316,6 +316,8 @@
 CURL_LIBS ?= @CURL_LIBS@
 MUSICBRAINZ_LIBS ?= @MUSICBRAINZ_LIBS@
 CHARDET_LIBS ?= @CHARDET_LIBS@
+samplerate_CFLAGS ?= @samplerate_CFLAGS@
+samplerate_LIBS ?= @samplerate_LIBS@
 SUBDIR_GUESS ?= @SUBDIR_GUESS@
 LIBNOTIFY_CFLAGS ?= @LIBNOTIFY_CFLAGS@
 LIBNOTIFY_LIBS ?= @LIBNOTIFY_LIBS@
--- a/src/audacious/Makefile	Sat Feb 17 01:54:30 2007 -0800
+++ b/src/audacious/Makefile	Sat Feb 17 02:19:35 2007 -0800
@@ -11,6 +11,7 @@
 LDADD = \
 	-L.. $(LTLIBINTL) \
 	-L../libaudacious -laudacious \
+	$(samplerate_LIBS) \
 	$(CHARDET_LIBS) \
 	$(GTK_LIBS) \
 	$(LIBGLADE_LIBS) \
@@ -22,6 +23,7 @@
 	$(LIBGLADE_CFLAGS) \
 	$(BEEP_DEFINES) \
 	$(ARCH_DEFINES) \
+	$(samplerate_CFLAGS) \
 	$(REGEX_CFLAGS) \
 	-D_AUDACIOUS_CORE \
 	-I.. -I../.. \
--- a/src/audacious/build_stamp.c	Sat Feb 17 01:54:30 2007 -0800
+++ b/src/audacious/build_stamp.c	Sat Feb 17 02:19:35 2007 -0800
@@ -1,2 +1,2 @@
 #include <glib.h>
-const gchar *svn_stamp = "20070217-4082";
+const gchar *svn_stamp = "20070217-4084";
--- a/src/audacious/glade/prefswin.glade	Sat Feb 17 01:54:30 2007 -0800
+++ b/src/audacious/glade/prefswin.glade	Sat Feb 17 02:19:35 2007 -0800
@@ -4156,6 +4156,274 @@
 		      <property name="fill">False</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkAlignment" id="alignment90">
+		      <property name="visible">True</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xscale">1</property>
+		      <property name="yscale">1</property>
+		      <property name="top_padding">12</property>
+		      <property name="bottom_padding">12</property>
+		      <property name="left_padding">0</property>
+		      <property name="right_padding">0</property>
+
+		      <child>
+			<widget class="GtkLabel" id="label93">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">&lt;b&gt;Sampling Rate Converter&lt;/b&gt;</property>
+			  <property name="use_underline">False</property>
+			  <property name="use_markup">True</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkAlignment" id="alignment92">
+		      <property name="visible">True</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xscale">1</property>
+		      <property name="yscale">1</property>
+		      <property name="top_padding">0</property>
+		      <property name="bottom_padding">0</property>
+		      <property name="left_padding">12</property>
+		      <property name="right_padding">0</property>
+
+		      <child>
+			<widget class="GtkCheckButton" id="enable_src">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">Enable Sampling Rate Converter</property>
+			  <property name="use_underline">True</property>
+			  <property name="relief">GTK_RELIEF_NORMAL</property>
+			  <property name="focus_on_click">True</property>
+			  <property name="active">True</property>
+			  <property name="inconsistent">False</property>
+			  <property name="draw_indicator">True</property>
+			  <signal name="realize" handler="on_enable_src_realize" last_modification_time="Fri, 16 Feb 2007 11:10:57 GMT"/>
+			  <signal name="toggled" handler="on_enable_src_toggled" last_modification_time="Fri, 16 Feb 2007 11:11:02 GMT"/>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkAlignment" id="alignment91">
+		      <property name="visible">True</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xscale">1</property>
+		      <property name="yscale">1</property>
+		      <property name="top_padding">0</property>
+		      <property name="bottom_padding">6</property>
+		      <property name="left_padding">12</property>
+		      <property name="right_padding">0</property>
+
+		      <child>
+			<widget class="GtkVBox" id="vbox36">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <widget class="GtkTable" id="table13">
+			      <property name="visible">True</property>
+			      <property name="n_rows">3</property>
+			      <property name="n_columns">2</property>
+			      <property name="homogeneous">False</property>
+			      <property name="row_spacing">6</property>
+			      <property name="column_spacing">6</property>
+
+			      <child>
+				<widget class="GtkLabel" id="label91">
+				  <property name="visible">True</property>
+				  <property name="label" translatable="yes">Sampling Rate [Hz]:</property>
+				  <property name="use_underline">False</property>
+				  <property name="use_markup">False</property>
+				  <property name="justify">GTK_JUSTIFY_LEFT</property>
+				  <property name="wrap">False</property>
+				  <property name="selectable">False</property>
+				  <property name="xalign">0</property>
+				  <property name="yalign">0.5</property>
+				  <property name="xpad">0</property>
+				  <property name="ypad">0</property>
+				  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				  <property name="width_chars">-1</property>
+				  <property name="single_line_mode">False</property>
+				  <property name="angle">0</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">0</property>
+				  <property name="right_attach">1</property>
+				  <property name="top_attach">0</property>
+				  <property name="bottom_attach">1</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkSpinButton" id="src_rate">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="climb_rate">1</property>
+				  <property name="digits">0</property>
+				  <property name="numeric">False</property>
+				  <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+				  <property name="snap_to_ticks">False</property>
+				  <property name="wrap">False</property>
+				  <property name="adjustment">96000 1000 768000 1000 1000 1000</property>
+				  <signal name="realize" handler="on_src_rate_realize" last_modification_time="Fri, 16 Feb 2007 11:11:10 GMT"/>
+				  <signal name="value_changed" handler="on_src_rate_value_changed" last_modification_time="Fri, 16 Feb 2007 11:11:15 GMT"/>
+				</widget>
+				<packing>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">0</property>
+				  <property name="bottom_attach">1</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkImage" id="image9">
+				  <property name="visible">True</property>
+				  <property name="stock">gtk-info</property>
+				  <property name="icon_size">4</property>
+				  <property name="xalign">1</property>
+				  <property name="yalign">0</property>
+				  <property name="xpad">0</property>
+				  <property name="ypad">0</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">0</property>
+				  <property name="right_attach">1</property>
+				  <property name="top_attach">2</property>
+				  <property name="bottom_attach">3</property>
+				  <property name="x_options">fill</property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkLabel" id="label92">
+				  <property name="visible">True</property>
+				  <property name="label" translatable="yes">&lt;span size=&quot;small&quot;&gt;All stream will be converted to this sampling rate.
+This should be the max supported sampling rate of
+the sound card or output plugin.&lt;/span&gt;</property>
+				  <property name="use_underline">False</property>
+				  <property name="use_markup">True</property>
+				  <property name="justify">GTK_JUSTIFY_LEFT</property>
+				  <property name="wrap">True</property>
+				  <property name="selectable">False</property>
+				  <property name="xalign">0</property>
+				  <property name="yalign">0.5</property>
+				  <property name="xpad">0</property>
+				  <property name="ypad">0</property>
+				  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				  <property name="width_chars">-1</property>
+				  <property name="single_line_mode">False</property>
+				  <property name="angle">0</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">2</property>
+				  <property name="bottom_attach">3</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkLabel" id="label94">
+				  <property name="visible">True</property>
+				  <property name="label" translatable="yes">Converter Type:</property>
+				  <property name="use_underline">False</property>
+				  <property name="use_markup">False</property>
+				  <property name="justify">GTK_JUSTIFY_LEFT</property>
+				  <property name="wrap">False</property>
+				  <property name="selectable">False</property>
+				  <property name="xalign">0</property>
+				  <property name="yalign">0.5</property>
+				  <property name="xpad">0</property>
+				  <property name="ypad">0</property>
+				  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				  <property name="width_chars">-1</property>
+				  <property name="single_line_mode">False</property>
+				  <property name="angle">0</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">0</property>
+				  <property name="right_attach">1</property>
+				  <property name="top_attach">1</property>
+				  <property name="bottom_attach">2</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkComboBox" id="src_converter_type">
+				  <property name="visible">True</property>
+				  <property name="items" translatable="yes">SRC_SINC_BEST_QUALITY
+SRC_SINC_MEDIUM_QUALITY
+SRC_SINC_FASTEST
+SRC_ZERO_ORDER_HOLD
+SRC_LINEAR</property>
+				  <property name="add_tearoffs">False</property>
+				  <property name="focus_on_click">True</property>
+				  <signal name="realize" handler="on_src_converter_type_realize" after="yes" last_modification_time="Fri, 16 Feb 2007 13:16:11 GMT"/>
+				  <signal name="changed" handler="on_src_converter_type_changed" last_modification_time="Fri, 16 Feb 2007 13:16:37 GMT"/>
+				</widget>
+				<packing>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">1</property>
+				  <property name="bottom_attach">2</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options">fill</property>
+				</packing>
+			      </child>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">False</property>
+			    </packing>
+			  </child>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="tab_expand">False</property>
--- a/src/audacious/output.c	Sat Feb 17 01:54:30 2007 -0800
+++ b/src/audacious/output.c	Sat Feb 17 02:19:35 2007 -0800
@@ -32,6 +32,10 @@
 #include "playback.h"
 
 #include "playlist.h"
+#include "libaudacious/configdb.h"
+#ifdef USE_SRC
+#include <samplerate.h>
+#endif
 
 OutputPluginData op_data = {
     NULL,
@@ -217,12 +221,63 @@
     return op->output_time();
 }
 
+#ifdef USE_SRC
+static SRC_STATE *src_state;
+static SRC_DATA src_data;
+static int overSamplingFs = 96000;
+static int converter_type = SRC_SINC_BEST_QUALITY;
+static int srcError = 0;
+static void freeSRC()
+{
+  if(src_state != NULL)
+    src_state = src_delete(src_state);
+}
+#endif
+
 gint
 output_open_audio(AFormat fmt, gint rate, gint nch)
 {
     gint ret;
     OutputPlugin *op;
     
+#ifdef USE_SRC
+    ConfigDb *db;
+    gboolean src_enabled;
+    gint src_rate, src_type;
+    db = bmp_cfg_db_open();
+    
+    if (bmp_cfg_db_get_bool(db, NULL, "enable_src", &src_enabled) == FALSE)
+      src_enabled = FALSE;
+
+    if (bmp_cfg_db_get_int(db, NULL, "src_rate", &src_rate) == FALSE)
+      overSamplingFs = 48000;
+    else
+      overSamplingFs = src_rate;
+
+    if (bmp_cfg_db_get_int(db, NULL, "src_type", &src_type) == FALSE)
+      converter_type = SRC_SINC_BEST_QUALITY;
+    else
+      converter_type = src_type;
+    
+    bmp_cfg_db_close(db);
+    
+    freeSRC();
+    
+    if(src_enabled&&
+       (fmt == FMT_S16_NE||(fmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN)||
+	(fmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN)))
+      {
+	src_state = src_new(converter_type, nch, &srcError);
+	if (src_state != NULL)
+	  {
+	    src_data.src_ratio = (float)overSamplingFs/(float)rate;
+	    rate = overSamplingFs;
+	  }
+	else
+	  fprintf(stderr, "src_new(): %s\n\n", src_strerror(srcError));
+      }
+#endif
+    
     op = get_current_output_plugin();
 
     if (op == NULL)
@@ -268,6 +323,10 @@
 {
     OutputPlugin *op = get_current_output_plugin();
 
+#ifdef USE_SRC
+    freeSRC();
+#endif
+
     /* Do not close if there are still songs to play and the user has 
      * not requested a stop.  --nenolod
      */
@@ -329,6 +388,12 @@
     return op->buffer_playing();
 }
 
+#ifdef USE_SRC
+static float *srcIn = NULL, *srcOut = NULL;
+static short int *wOut = NULL;
+static gboolean isSrcAlloc = FALSE;
+#endif
+
 /* called by input plugin when data is ready */
 void
 produce_audio(gint time,        /* position             */
@@ -346,6 +411,42 @@
     OutputPlugin *op = get_current_output_plugin();
     int writeoffs;
 
+#ifdef USE_SRC
+    if(isSrcAlloc == TRUE)
+      {
+        free(srcIn);
+        free(srcOut);
+        free(wOut);
+        isSrcAlloc = FALSE;
+      }
+    
+    if(src_state != NULL&&length > 0)
+      {
+        int lrLength = length/2;
+        int overLrLength = (int)floor(lrLength*(src_data.src_ratio+1));
+        srcIn = (float*)malloc(sizeof(float)*lrLength);
+        srcOut = (float*)malloc(sizeof(float)*overLrLength);
+        wOut = (short int*)malloc(sizeof(short int)*overLrLength);
+        src_short_to_float_array((short int*)ptr, srcIn, lrLength);
+        isSrcAlloc = TRUE;
+        src_data.data_in = srcIn;
+        src_data.data_out = srcOut;
+        src_data.end_of_input = 0;
+        src_data.input_frames = lrLength/2;
+        src_data.output_frames = overLrLength/2;
+        if (srcError = src_process(src_state, &src_data))
+          {
+            fprintf(stderr, "src_process(): %s\n", src_strerror(srcError));
+          }
+        else
+          {
+            src_float_to_short_array(srcOut, wOut, src_data.output_frames_gen*2);
+            ptr = wOut;
+            length = src_data.output_frames_gen*4;
+          }
+      }
+#endif
+
     if (!caneq && cfg.equalizer_active) {    /* wrong byte order */
         byteswap(length, ptr);               /* so convert */
         ++swapped;
--- a/src/audacious/ui_preferences.c	Sat Feb 17 01:54:30 2007 -0800
+++ b/src/audacious/ui_preferences.c	Sat Feb 17 02:19:35 2007 -0800
@@ -1510,6 +1510,102 @@
 }
 
 static void
+on_enable_src_realize(GtkToggleButton * button,
+                                    gpointer data)
+{
+#ifdef USE_SRC
+    ConfigDb *db;
+    gboolean ret;
+
+    db = bmp_cfg_db_open();
+
+    if (bmp_cfg_db_get_bool(db, NULL, "enable_src", &ret) != FALSE)
+        gtk_toggle_button_set_active(button, ret);
+
+    bmp_cfg_db_close(db);
+#else
+    gtk_toggle_button_set_active(button, FALSE);
+    gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+#endif
+}
+
+static void
+on_enable_src_toggled(GtkToggleButton * button,
+                                    gpointer data)
+{
+    ConfigDb *db;
+    gboolean ret = gtk_toggle_button_get_active(button);
+
+    db = bmp_cfg_db_open();
+    bmp_cfg_db_set_bool(db, NULL, "enable_src", ret);
+    bmp_cfg_db_close(db);
+}
+
+static void
+on_src_rate_realize(GtkSpinButton * button,
+                                    gpointer data)
+{
+#ifdef USE_SRC
+    ConfigDb *db;
+    gint value;
+
+    db = bmp_cfg_db_open();
+
+    if (bmp_cfg_db_get_int(db, NULL, "src_rate", &value) != FALSE)
+        gtk_spin_button_set_value(button, (gdouble)value);
+
+    bmp_cfg_db_close(db);
+#else
+    gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
+#endif
+}
+
+static void
+on_src_rate_value_changed(GtkSpinButton * button,
+                                    gpointer data)
+{
+    ConfigDb *db;
+    gint value = gtk_spin_button_get_value_as_int(button);
+
+    db = bmp_cfg_db_open();
+    bmp_cfg_db_set_int(db, NULL, "src_rate", value);
+    bmp_cfg_db_close(db);
+}
+
+static void
+on_src_converter_type_realize(GtkComboBox * box,
+			      gpointer data)
+{
+#ifdef USE_SRC
+    ConfigDb *db;
+    gint value;
+
+    db = bmp_cfg_db_open();
+
+    if (bmp_cfg_db_get_int(db, NULL, "src_type", &value) != FALSE)
+        gtk_combo_box_set_active(box, value);
+    else
+        gtk_combo_box_set_active(box, 0);
+
+    bmp_cfg_db_close(db);
+#else
+    gtk_widget_set_sensitive(GTK_WIDGET(box), FALSE);
+#endif
+}
+
+static void
+on_src_converter_type_changed(GtkComboBox * box,
+			      gpointer data)
+{
+    ConfigDb *db;
+    gint value = gtk_combo_box_get_active(box);
+
+    db = bmp_cfg_db_open();
+    bmp_cfg_db_set_int(db, NULL, "src_type", value);
+    bmp_cfg_db_close(db);
+}
+
+static void
 on_mouse_wheel_scroll_pl_realize(GtkSpinButton * button,
                                  gpointer data)
 {
@@ -2253,6 +2349,12 @@
     FUNC_MAP_ENTRY(on_mouse_wheel_scroll_pl_changed)
     FUNC_MAP_ENTRY(on_pause_between_songs_time_realize)
     FUNC_MAP_ENTRY(on_pause_between_songs_time_changed)
+    FUNC_MAP_ENTRY(on_enable_src_realize)
+    FUNC_MAP_ENTRY(on_enable_src_toggled)
+    FUNC_MAP_ENTRY(on_src_rate_realize)
+    FUNC_MAP_ENTRY(on_src_rate_value_changed)
+    FUNC_MAP_ENTRY(on_src_converter_type_realize)
+    FUNC_MAP_ENTRY(on_src_converter_type_changed)
     FUNC_MAP_ENTRY(on_pl_metadata_on_load_realize)
     FUNC_MAP_ENTRY(on_pl_metadata_on_load_toggled)
     FUNC_MAP_ENTRY(on_pl_metadata_on_display_realize)