changeset 4267:a41fb6bc632a

- src stuff traveled to src_flow.c - vis works again.
author Eugene Zagidullin <e.asphyx@gmail.com>
date Sun, 10 Feb 2008 07:19:45 +0300
parents 92642f860860
children af17e0fc8f08
files src/audacious/flow.c src/audacious/main.c src/audacious/main.h src/audacious/output.c src/audacious/src_flow.c src/audacious/src_flow.h src/audacious/ui_preferences.c src/audacious/util.c src/audacious/util.h
diffstat 9 files changed, 266 insertions(+), 271 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/flow.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/flow.c	Sun Feb 10 07:19:45 2008 +0300
@@ -20,6 +20,9 @@
  * Audacious or using our public API to be a derived work. 
  */
 
+#define AUD_DEBUG
+
+#include "main.h"
 #include "flow.h"
 
 mowgli_object_class_t flow_klass;
@@ -59,8 +62,10 @@
     {
         element->func(&context);
 
-        if (context.error)
+        if (context.error) {
+            AUDDBG("context.error!\n");
             break;
+        }
     }
 
     *data = context.data;
--- a/src/audacious/main.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/main.c	Sun Feb 10 07:19:45 2008 +0300
@@ -45,6 +45,10 @@
 #include <sys/stat.h>
 #include <signal.h>
 
+#ifdef USE_SRC
+#  include <samplerate.h>
+#endif
+
 #include "platform/smartinclude.h"
 
 #include "configdb.h"
@@ -239,6 +243,11 @@
     FALSE,          /* enable adaptive scaler */
     0.0,            /* preamp */
     -9.0,           /* default gain */
+#ifdef USE_SRC
+    FALSE,          /* enable resampling */
+    48000,          /* samplerate */
+    SRC_SINC_BEST_QUALITY, /* default interpolation method */
+#endif
 };
 
 typedef struct bmp_cfg_boolent_t {
@@ -355,6 +364,9 @@
     {"replay_gain_track",          &cfg.replay_gain_track, TRUE},
     {"replay_gain_album",          &cfg.replay_gain_album, TRUE},
     {"enable_adaptive_scaler",     &cfg.enable_adaptive_scaler, TRUE},
+#ifdef USE_SRC
+    {"enable_src",                 &cfg.enable_src, TRUE},
+#endif
 };
 
 static gint ncfgbent = G_N_ELEMENTS(bmp_boolents);
@@ -393,6 +405,10 @@
     {"colorize_g", &cfg.colorize_g, TRUE},
     {"colorize_b", &cfg.colorize_b, TRUE},
     {"output_bit_depth", &cfg.output_bit_depth, TRUE},
+#ifdef USE_SRC
+    {"src_rate", &cfg.src_rate, TRUE},
+    {"src_type", &cfg.src_type, TRUE},
+#endif
 };
 
 static gint ncfgient = G_N_ELEMENTS(bmp_numents);
--- a/src/audacious/main.h	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/main.h	Sun Feb 10 07:19:45 2008 +0300
@@ -150,6 +150,11 @@
     gboolean enable_adaptive_scaler;
     gfloat replay_gain_preamp;
     gfloat default_gain;
+#ifdef USE_SRC
+    gboolean enable_src;
+    gint src_rate;
+    gint src_type;
+#endif
 };
 
 typedef struct _BmpConfig BmpConfig;
--- a/src/audacious/output.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/output.c	Sun Feb 10 07:19:45 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"
@@ -50,7 +50,7 @@
 #include <math.h>
 
 #ifdef USE_SRC
-#include <samplerate.h>
+# include "src_flow.h"
 #endif
 
 #define FMT_FRACBITS(a) ( (a) == FMT_FIXED32 ? __AUDACIOUS_ASSUMED_MAD_F_FRACBITS__ : 0 )
@@ -66,6 +66,8 @@
     0
 };
 
+static gint decoder_srate = 0;
+
 OutputPlugin psuedo_output_plugin = {
     .description = "XMMS reverse compatibility output plugin",
     .get_volume = output_get_volume,
@@ -231,40 +233,12 @@
     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 float *srcIn = NULL, *srcOut = NULL;
-static short int *wOut = NULL;
-static int lengthOfSrcIn = 0;
-static int lengthOfSrcOut = 0;
-
-static void freeSRC()
-{
-  if(src_state != NULL)
-    src_state = src_delete(src_state);
-  free(srcIn);
-  free(srcOut);
-  free(wOut);
-  srcIn = NULL;
-  srcOut = NULL;
-  wOut = NULL;
-  lengthOfSrcIn = 0;
-  lengthOfSrcOut = 0;
-}
-
-#endif
-
-static SAD_dither_t *sad_state = NULL;
 static SAD_dither_t *sad_state_to_float = NULL;
 static SAD_dither_t *sad_state_from_float = NULL;
+static float *sad_float_buf = NULL;
 static void *sad_out_buf = NULL;
-static int sad_out_buf_length = 0;
+static guint sad_float_buf_length = 0;
+static guint sad_out_buf_length = 0;
 static ReplayGainInfo replay_gain_info = {
     .track_gain = 0.0,
     .track_peak = 0.0,
@@ -275,10 +249,8 @@
 static void
 freeSAD()
 {
-    if (sad_state != NULL)            {SAD_dither_free(sad_state);            sad_state = NULL;}
     if (sad_state_from_float != NULL) {SAD_dither_free(sad_state_from_float); sad_state_from_float = NULL;}
     if (sad_state_to_float != NULL)   {SAD_dither_free(sad_state_to_float);   sad_state_to_float = NULL;}
-    if (sad_out_buf != NULL)          {free(sad_out_buf);                     sad_out_buf = NULL; sad_out_buf_length = 0;}
 }
 
 gint
@@ -286,138 +258,69 @@
 {
     gint ret;
     OutputPlugin *op;
-    AUDDBG("\n");
+    AUDDBG("requested: fmt=%d, rate=%d, nch=%d\n", fmt, rate, nch);
 
     AFormat output_fmt;
     int bit_depth;
     SAD_buffer_format input_sad_fmt;
     SAD_buffer_format output_sad_fmt;
 
-#ifdef USE_SRC
-    gboolean src_enabled;
-    gint src_rate, src_type;
-    ConfigDb *db;
-    
-    db = cfg_db_open();
-    
-    if (cfg_db_get_bool(db, NULL, "enable_src", &src_enabled) == FALSE)
-      src_enabled = FALSE;
-
-    if (cfg_db_get_int(db, NULL, "src_rate", &src_rate) == FALSE)
-      overSamplingFs = 48000;
-    else
-      overSamplingFs = src_rate;
-
-    /* don't resample if sampling rates are the same --nenolod */
-    if (rate == overSamplingFs)
-      src_enabled = FALSE;
+    decoder_srate = rate;
 
-    if (cfg_db_get_int(db, NULL, "src_type", &src_type) == FALSE)
-      converter_type = SRC_SINC_BEST_QUALITY;
-    else
-      converter_type = src_type;
-    
-    freeSRC();
-    
-    if(src_enabled)
-      {
-	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));
-          src_enabled = FALSE;
-        }
-      }
-    
-    cfg_db_close(db);
+#ifdef USE_SRC
+    if(cfg.enable_src) rate = cfg.src_rate;
 #endif
     
-    /*if (cfg_db_get_int(db, NULL, "output_bit_depth", &bit_depth) == FALSE) bit_depth = 16;*/
     bit_depth = cfg.output_bit_depth;
 
     AUDDBG("bit depth: %d\n", bit_depth);
     output_fmt = (bit_depth == 24) ? FMT_S24_NE : FMT_S16_NE;
-    /*output_fmt = (bit_depth == 24) ? FMT_S24_LE : FMT_S16_LE;*/ /* no reason to support other output formats --asphyx */
     
     freeSAD();
 
-#ifdef USE_SRC
-    if (src_enabled) {
-        AUDDBG("initializing dithering engine for 2 stage conversion\n");
-        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;
-    } else
-#endif /* USE_SRC */
-    {   /* needed for RG processing !*/
-        AUDDBG("initializing dithering engine for direct conversion\n");
-
-        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; /* resampling not implemented yet in libSAD */
-        
-        output_sad_fmt.sample_format = sadfmt_from_afmt(output_fmt);
-        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 = SAD_dither_init(&input_sad_fmt, &output_sad_fmt, &ret);
-        if (sad_state == NULL) {
-            AUDDBG("ditherer init failed\n");
-            return FALSE;
-        }
-        SAD_dither_set_dither (sad_state, TRUE);
-
-        fmt = output_fmt;
+    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;
 
     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");
@@ -475,11 +378,6 @@
 {
     OutputPlugin *op = get_current_output_plugin();
 
-    AUDDBG("\n");
-
-#ifdef USE_SRC
-    freeSRC();
-#endif
     freeSAD();
     
     AUDDBG("clearing RG settings\n");
@@ -491,16 +389,23 @@
     /* Do not close if there are still songs to play and the user has 
      * not requested a stop.  --nenolod
      */
-    if (ip_data.stop == FALSE && 
-       (playlist_get_position_nolock(playlist_get_active()) < 
-        playlist_get_length(playlist_get_active()) - 1))
-        return;
+    Playlist *pl = playlist_get_active();
+    if (ip_data.stop == FALSE &&
+       (playlist_get_position_nolock(pl) < playlist_get_length(pl) - 1)) {
+            AUDDBG("leaving audio opened\n");
+            return;
+        }
 
     /* Sanity check. */
     if (op == NULL)
         return;
 
+    AUDDBG("closing audio\n");
     op->close_audio();
+    AUDDBG("done\n");
+#ifdef USE_SRC
+    src_flow_free();
+#endif
 
     /* Reset the op_state. */
     op_state.fmt = op_state.rate = op_state.nch = 0;
@@ -564,8 +469,9 @@
     static Flow *legacy_flow = NULL;
     OutputPlugin *op = playback->output;
     gint writeoffs;
-
-    if (length <= 0) return;
+    gpointer float_ptr;
+    
+    if (length <= 0 || sad_state_to_float == NULL || sad_state_from_float == NULL) return;
     gint time = playback->output->written_time();
 
     if (legacy_flow == NULL)
@@ -580,61 +486,40 @@
     {
         postproc_flow = flow_new();
         flow_link_element(postproc_flow, vis_flow);
+#ifdef USE_SRC
+        flow_link_element(postproc_flow, src_flow);
+#endif
+    }
+
+    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);
     }
 
-#ifdef USE_SRC
-    if(src_state != NULL)
-      {
-        int lrLength = length / FMT_SIZEOF(fmt);
-        int overLrLength = (int)floor(lrLength*(src_data.src_ratio+1));
-	if(lengthOfSrcIn < lrLength)
-	  {
-	    lengthOfSrcIn = lrLength;
-	    free(srcIn);
-	    srcIn = (float*)malloc(sizeof(float)*lrLength);
-	  }
-	if(lengthOfSrcOut < overLrLength)
-	  {
-	    lengthOfSrcOut = overLrLength;
-	    free(srcOut);
-	    free(wOut);
-	    srcOut = (float*)malloc(sizeof(float)*overLrLength);
-	    wOut = (short int*)malloc(FMT_SIZEOF(op_state.fmt) * overLrLength);
-	  }
-        
-        SAD_dither_process_buffer(sad_state_to_float, ptr, srcIn, lrLength / nch);
-        /*flow_execute(postproc_flow, time, &srcIn, lrLength * sizeof(float), FMT_FLOAT, op_state.rate, nch);*/ /*FIXME*/
-
+    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);
+    }
 
-        src_data.data_in = srcIn;
-        src_data.data_out = srcOut;
-        src_data.end_of_input = 0;
-        src_data.input_frames = lrLength / nch;
-        src_data.output_frames = overLrLength / nch;
-        if ((srcError = src_process(src_state, &src_data)) > 0)
-          {
-            fprintf(stderr, "src_process(): %s\n", src_strerror(srcError));
-          }
-        else
-          {
-            SAD_dither_process_buffer(sad_state_from_float, srcOut, wOut, src_data.output_frames_gen);
-            ptr = wOut;
-            length = src_data.output_frames_gen *  op_state.nch * FMT_SIZEOF(op_state.fmt);
-          }
-      } else
-#endif
-    if(sad_state != NULL) {
-        int frames  = length / nch / FMT_SIZEOF(fmt);
-        int len =  frames * op_state.nch * FMT_SIZEOF(op_state.fmt);
-        if(sad_out_buf == NULL || sad_out_buf_length < len ) {
-            if(sad_out_buf != NULL) free (sad_out_buf);
-            sad_out_buf = malloc(len);
-            sad_out_buf_length = len; 
-        }
-        SAD_dither_process_buffer(sad_state, ptr, sad_out_buf, frames);
-        ptr = sad_out_buf;
-        length = len;
-    }
+    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)) {
@@ -643,6 +528,8 @@
         AUDDBG("legacy_flow can deal only with S16_NE streams\n"); /*FIXME*/
     }
 
+    /**** write it out ****/
+
     writeoffs = 0;
     while (writeoffs < length)
     {
@@ -699,13 +586,10 @@
 {
     SAD_replaygain_mode mode;
     SAD_replaygain_info info;
-    /*ConfigDb *db;*/
     gboolean rg_enabled;
     gboolean album_mode;
-    SAD_dither_t *active_state;
 
-
-    if(sad_state == NULL && sad_state_from_float == NULL) {
+    if(sad_state_from_float == NULL) {
         AUDDBG("SAD not initialized!\n");
         return;
     }
@@ -738,6 +622,5 @@
     AUDDBG("* album gain:          %+f dB\n", info.album_gain);
     AUDDBG("* album peak:          %f\n",     info.album_peak);
     
-    active_state = sad_state != NULL ? sad_state : sad_state_from_float;
-    SAD_dither_apply_replaygain(active_state, &info, &mode);
+    SAD_dither_apply_replaygain(sad_state_from_float, &info, &mode);
 }
--- a/src/audacious/src_flow.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/src_flow.c	Sun Feb 10 07:19:45 2008 +0300
@@ -17,15 +17,117 @@
  *  Audacious or using our public API to be a derived work.
  */
 
+#define AUD_DEBUG
+
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
 #ifdef USE_SRC
 
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
 #include <samplerate.h>
 
-/* The devil is in the details */
+#include "main.h"
+#include "plugin.h"
+#include "input.h"
+#include "playback.h"
+#include "util.h"
+
+#include "src_flow.h"
+
+static SRC_STATE *src_state = NULL;
+static SRC_DATA src_data;
+
+static int overSamplingFs = 48000; /* hmmm... does everybody have 96kHz-enabled hardware? i'm in doubt --asphyx */
+static int inputFs = 0;
+static int input_nch = 0;
+static int converter_type = SRC_SINC_BEST_QUALITY;
+static int srcError = 0;
+
+static float *srcOut = NULL;
+static unsigned int lengthOfSrcOut = 0;
+
+void
+src_flow_free()
+{
+    AUDDBG("\n");
+    if(src_state != NULL) src_state = src_delete(src_state);
+    src_state = NULL;
+    if(srcOut != NULL) free(srcOut);
+    srcOut = NULL;
+    lengthOfSrcOut = 0;
+    inputFs = 0;
+    overSamplingFs = 0;
+    input_nch = 0;
+}
+
+gint
+src_flow_init(gint infreq, gint nch)
+{
+    AUDDBG("input_rate=%d, nch=%d\n", infreq, nch);
+    src_flow_free();
+
+    /* don't resample if sampling rates are the same --nenolod */
+    if (infreq == cfg.src_rate || !cfg.enable_src) return infreq;
+    
+    overSamplingFs = cfg.src_rate;
+    inputFs = infreq;
+    input_nch = nch;
+    converter_type = cfg.src_type;
+    
+    src_state = src_new(converter_type, nch, &srcError);
+    if (src_state != NULL) {
+        src_data.src_ratio = (float)overSamplingFs / (float)infreq;
+        return overSamplingFs;
+    } else {
+        AUDDBG("src_new(): %s\n\n", src_strerror(srcError));
+        return infreq;
+    }
+}
+
+void
+src_flow(FlowContext *context) {
+   
+    if(!cfg.enable_src) return;
+    
+    if(context->fmt != FMT_FLOAT) {
+        context->error = TRUE;
+        return;
+    }
+
+    if(src_state == NULL || context->srate != inputFs || context->channels != input_nch) {
+        AUDDBG("reinitializing src\n");
+        src_flow_init(context->srate, context->channels);
+    }
+
+    int lrLength = context->len;
+    int overLrLength = (int)floor(lrLength * (src_data.src_ratio + 1));
+    
+    if(lengthOfSrcOut < overLrLength || srcOut == NULL) {
+        AUDDBG("reallocating srcOut\n");
+        lengthOfSrcOut = overLrLength;
+        srcOut = smart_realloc(srcOut, &lengthOfSrcOut);
+    }
+    
+    src_data.data_in = (float*)context->data;
+    src_data.data_out = srcOut;
+    src_data.end_of_input = 0;
+    src_data.input_frames = lrLength / context->channels / sizeof(float);
+    src_data.output_frames = overLrLength / context->channels / sizeof(float);
+    if ((srcError = src_process(src_state, &src_data)) > 0) {
+        AUDDBG("src_process(): %s\n", src_strerror(srcError));
+        context->error = TRUE;
+        return;
+    } else {
+        context->data = (gpointer) srcOut;
+        context->len = src_data.output_frames_gen * context->channels * sizeof(float);
+        return;
+    }
+}
 
 #endif /* USE_SRC */
 
--- a/src/audacious/src_flow.h	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/src_flow.h	Sun Feb 10 07:19:45 2008 +0300
@@ -24,7 +24,7 @@
 #include "flow.h"
 
 void src_flow(FlowContext *context);
-void src_flow_init(gint infreq, gint outfreq);
+gint src_flow_init(gint infreq, gint nch);
 void src_flow_free();
 
 #endif
--- a/src/audacious/ui_preferences.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/ui_preferences.c	Sun Feb 10 07:19:45 2008 +0300
@@ -857,15 +857,7 @@
                       gpointer data)
 {
 #ifdef USE_SRC
-    ConfigDb *db;
-    gboolean ret;
-
-    db = cfg_db_open();
-
-    if (cfg_db_get_bool(db, NULL, "enable_src", &ret) != FALSE)
-        gtk_toggle_button_set_active(button, ret);
-
-    cfg_db_close(db);
+    gtk_toggle_button_set_active(button, cfg.enable_src);
 #else
     gtk_toggle_button_set_active(button, FALSE);
     gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
@@ -873,15 +865,11 @@
 }
 
 static void
-on_enable_src_toggled(GtkToggleButton * button,
-                      gpointer data)
+on_enable_src_toggled(GtkToggleButton * button, gpointer data)
 {
-    ConfigDb *db;
-    gboolean ret = gtk_toggle_button_get_active(button);
-
-    db = cfg_db_open();
-    cfg_db_set_bool(db, NULL, "enable_src", ret);
-    cfg_db_close(db);
+#ifdef USE_SRC
+    cfg.enable_src = gtk_toggle_button_get_active(button);
+#endif
 }
 
 static void
@@ -889,15 +877,7 @@
                     gpointer data)
 {
 #ifdef USE_SRC
-    ConfigDb *db;
-    gint value;
-
-    db = cfg_db_open();
-
-    if (cfg_db_get_int(db, NULL, "src_rate", &value) != FALSE)
-        gtk_spin_button_set_value(button, (gdouble)value);
-
-    cfg_db_close(db);
+    gtk_spin_button_set_value(button, (gdouble)cfg.src_rate);
 #else
     gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
 #endif
@@ -907,12 +887,9 @@
 on_src_rate_value_changed(GtkSpinButton * button,
                           gpointer data)
 {
-    ConfigDb *db;
-    gint value = gtk_spin_button_get_value_as_int(button);
-
-    db = cfg_db_open();
-    cfg_db_set_int(db, NULL, "src_rate", value);
-    cfg_db_close(db);
+#ifdef USE_SRC
+    cfg.src_rate = gtk_spin_button_get_value_as_int(button);
+#endif
 }
 
 static void
@@ -920,17 +897,7 @@
                               gpointer data)
 {
 #ifdef USE_SRC
-    ConfigDb *db;
-    gint value;
-
-    db = cfg_db_open();
-
-    if (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);
-
-    cfg_db_close(db);
+    gtk_combo_box_set_active(box, cfg.src_type);
 #else
     gtk_widget_set_sensitive(GTK_WIDGET(box), FALSE);
 #endif
@@ -940,12 +907,9 @@
 on_src_converter_type_changed(GtkComboBox * box,
                               gpointer data)
 {
-    ConfigDb *db;
-    gint value = gtk_combo_box_get_active(box);
-
-    db = cfg_db_open();
-    cfg_db_set_int(db, NULL, "src_type", value);
-    cfg_db_close(db);
+#ifdef USE_SRC
+    cfg.src_type = gtk_combo_box_get_active(box);
+#endif
 }
 
 static void
--- a/src/audacious/util.c	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/util.c	Sun Feb 10 07:19:45 2008 +0300
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <math.h>
 
 #include "platform/smartinclude.h"
 #include <errno.h>
@@ -1056,3 +1057,19 @@
     AUDDBG("uri=%s\n", uri);
     return uri;
 }
+
+/* 
+ * minimize number of realloc's:
+ *  - set N to nearest power of 2 not less then N
+ *  - double it
+ *
+ *  -- asphyx
+ */
+void*
+smart_realloc(void *ptr, size_t *size) {
+    *size = (size_t)pow(2, ceil(log(*size) / log(2)) + 1);
+    if (ptr != NULL) free(ptr);
+    ptr = malloc(*size);
+    return ptr;
+}
+
--- a/src/audacious/util.h	Sat Feb 09 01:05:36 2008 +0300
+++ b/src/audacious/util.h	Sun Feb 10 07:19:45 2008 +0300
@@ -107,6 +107,9 @@
 
 SAD_sample_format sadfmt_from_afmt(AFormat fmt);
 
+/* minimizes number of realloc's */
+void* smart_realloc(void *ptr, size_t *size);
+
 G_END_DECLS
 
 #endif