diff src/audacious/output.c @ 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 ad1d7687814c
children ef01234ae265
line wrap: on
line diff
--- 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;