summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--premix.c21
-rw-r--r--src.c177
-rw-r--r--src.h46
-rw-r--r--streamer.c344
5 files changed, 331 insertions, 258 deletions
diff --git a/Makefile.am b/Makefile.am
index cab4aa3b..8219b914 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,6 +21,7 @@ deadbeef_SOURCES =\
plugins.c plugins.h moduleconf.h\
playlist.c playlist.h \
streamer.c streamer.h\
+ src.c src.h\
premix.c premix.h\
messagepump.c messagepump.h\
conf.c conf.h\
diff --git a/premix.c b/premix.c
index d85c698d..d3745e11 100644
--- a/premix.c
+++ b/premix.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include "deadbeef.h"
#include "premix.h"
+#include "optmath.h"
#define trace(...) { fprintf(stderr, __VA_ARGS__); }
//#define trace(fmt,...)
@@ -201,6 +202,23 @@ pcm_write_samples_24_to_24 (const ddb_waveformat_t * restrict inputfmt, const ch
output += outputsamplesize;
}
}
+static inline void
+pcm_write_samples_float_to_16 (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int nsamples, int * restrict channelmap, int outputsamplesize) {
+ fpu_control ctl;
+ fpu_setround (&ctl);
+ for (int s = 0; s < nsamples; s++) {
+ for (int c = 0; c < inputfmt->channels; c++) {
+ if (channelmap[c] != -1) {
+ int16_t *out = (int16_t*)(output + (outputfmt->bps >> 3) * channelmap[c]);
+ float sample = *((float*)input);
+ *out = (int16_t)ftoi (sample*0x7fff);
+ }
+ input += 4;
+ }
+ output += outputsamplesize;
+ }
+ fpu_restore (ctl);
+}
int
pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict input, const ddb_waveformat_t * restrict outputfmt, char * restrict output, int inputsize) {
@@ -285,6 +303,9 @@ pcm_convert (const ddb_waveformat_t * restrict inputfmt, const char * restrict i
else if (inputfmt->bps == 32 && outputfmt->bps == 32) {
pcm_write_samples_32_to_32 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
}
+ else if (inputfmt->is_float && inputfmt->bps == 32 && outputfmt->bps == 16) {
+ pcm_write_samples_float_to_16 (inputfmt, input, outputfmt, output, nsamples, channelmap, outputsamplesize);
+ }
else {
trace ("no converter from %d to %d\n", inputfmt->bps, outputfmt->bps);
}
diff --git a/src.c b/src.c
new file mode 100644
index 00000000..edeccff4
--- /dev/null
+++ b/src.c
@@ -0,0 +1,177 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <samplerate.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "conf.h"
+#include "threading.h"
+#include "src.h"
+
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(fmt,...)
+
+#define SRC_BUFFER 16000
+#define SRC_MAX_CHANNELS 8
+
+typedef struct {
+ ddb_src_t ddb_src;
+
+ int quality;
+ SRC_STATE *src;
+ SRC_DATA srcdata;
+ int remaining; // number of input samples in SRC buffer
+ __attribute__((__aligned__(16))) char in_fbuffer[sizeof(float)*SRC_BUFFER*SRC_MAX_CHANNELS];
+// __attribute__((__aligned__(16))) float out_fbuffer[SRC_BUFFER*SRC_MAX_CHANNELS];
+ uintptr_t mutex;
+} ddb_src_libsamplerate_t;
+
+ddb_src_t *
+ddb_src_init (void) {
+ ddb_src_libsamplerate_t *src = malloc (sizeof (ddb_src_libsamplerate_t));
+ memset (src, 0, sizeof (ddb_src_libsamplerate_t));
+ src->mutex = mutex_create ();
+ src->quality = conf_get_int ("src->quality", 2);
+ src->src = src_new (src->quality, 2, NULL);
+ if (!src->src) {
+ ddb_src_free ((ddb_src_t *)src);
+ return NULL;
+ }
+ return (ddb_src_t *)src;
+}
+
+void
+ddb_src_free (ddb_src_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ if (src->mutex) {
+ mutex_free (src->mutex);
+ src->mutex = 0;
+ }
+ if (src->src) {
+ src_delete (src->src);
+ src->src = NULL;
+ }
+ free (src);
+}
+
+void
+ddb_src_lock (ddb_src_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ mutex_lock (src->mutex);
+}
+
+void
+ddb_src_unlock (ddb_src_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ mutex_unlock (src->mutex);
+}
+
+void
+ddb_src_reset (ddb_src_t *_src, int full) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ src->remaining = 0;
+ if (full) {
+ src_reset (src->src);
+ }
+}
+
+void
+ddb_src_confchanged (ddb_src_t *_src) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+ int q = conf_get_int ("src->quality", 2);
+ if (q != src->quality && q >= SRC_SINC_BEST_QUALITY && q <= SRC_LINEAR) {
+ ddb_src_lock (_src);
+ trace ("changing src->quality from %d to %d\n", src->quality, q);
+ src->quality = q;
+ if (src) {
+ src_delete (src->src);
+ src->src = NULL;
+ }
+ memset (&src->srcdata, 0, sizeof (src->srcdata));
+ src->src = src_new (src->quality, 2, NULL);
+ ddb_src_unlock (_src);
+ }
+}
+
+int
+ddb_src_process (ddb_src_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels) {
+ ddb_src_libsamplerate_t *src = (ddb_src_libsamplerate_t*)_src;
+
+extern FILE *out;
+ int initsize = buffersize;
+ int samplesize = nchannels * sizeof (float);
+
+ do {
+ // add more frames to input SRC buffer
+ int n = nframes;
+ if (n >= SRC_BUFFER - src->remaining) {
+ n = SRC_BUFFER - src->remaining;
+ }
+
+ if (n > 0) {
+ memcpy (&src->in_fbuffer[src->remaining*samplesize], input, n * samplesize);
+
+ src->remaining += n;
+ input += n * nchannels;
+ nframes -= n;
+ }
+ if (!src->remaining) {
+ //trace ("WARNING: SRC input buffer starved\n");
+ break;
+ }
+
+ // call libsamplerate
+ src->srcdata.data_in = (float *)src->in_fbuffer;
+ src->srcdata.data_out = (float *)output;
+ src->srcdata.input_frames = src->remaining;
+ src->srcdata.output_frames = buffersize/samplesize;
+ src->srcdata.src_ratio = ratio;
+ src->srcdata.end_of_input = 0;
+ ddb_src_lock (_src);
+ src_set_ratio (src->src, ratio);
+ trace ("src input: %d, ratio %f, buffersize: %d\n", src->srcdata.input_frames, ratio, buffersize);
+ int src_err = src_process (src->src, &src->srcdata);
+ trace ("src output: %d, used: %d\n", src->srcdata.output_frames_gen, src->srcdata.input_frames_used);
+
+ ddb_src_unlock (_src);
+ if (src_err) {
+ const char *err = src_strerror (src_err) ;
+ fprintf (stderr, "src_process error %s\n"
+ "srcdata.data_in=%p, srcdata.data_out=%p, srcdata.input_frames=%d, srcdata.output_frames=%d, srcdata.src_ratio=%f", err, src->srcdata.data_in, src->srcdata.data_out, (int)src->srcdata.input_frames, (int)src->srcdata.output_frames, ratio);
+ exit (-1);
+ }
+
+ buffersize -= src->srcdata.output_frames_gen * samplesize;
+ output += src->srcdata.output_frames_gen * samplesize;
+
+ // calculate how many unused input samples left
+ src->remaining -= src->srcdata.input_frames_used;
+ // copy spare samples for next update
+ if (src->remaining > 0 && src->srcdata.input_frames_used > 0) {
+ memmove (src->in_fbuffer, &src->in_fbuffer[src->srcdata.input_frames_used*samplesize], src->remaining * samplesize);
+ }
+ if (src->srcdata.output_frames_gen == 0) {
+ break;
+ }
+ } while (nframes > 0);
+
+ trace ("src processed: %d bytes\n", initsize-buffersize);
+ return initsize - buffersize;
+}
+
diff --git a/src.h b/src.h
new file mode 100644
index 00000000..74bf9e75
--- /dev/null
+++ b/src.h
@@ -0,0 +1,46 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __SRC_H
+#define __SRC_H
+
+typedef struct {
+} ddb_src_t;
+
+ddb_src_t *
+ddb_src_init (void);
+
+void
+ddb_src_free (ddb_src_t *src);
+
+void
+ddb_src_lock (ddb_src_t *_src);
+
+void
+ddb_src_unlock (ddb_src_t *src);
+
+void
+ddb_src_reset (ddb_src_t *src, int full);
+
+void
+ddb_src_confchanged (ddb_src_t *src);
+
+int
+ddb_src_process (ddb_src_t *_src, const char * restrict input, int nframes, char * restrict output, int buffersize, float ratio, int nchannels);
+
+#endif
diff --git a/streamer.c b/streamer.c
index b1f2836f..a7b4712b 100644
--- a/streamer.c
+++ b/streamer.c
@@ -36,38 +36,28 @@
#include "volume.h"
#include "vfs.h"
#include "premix.h"
+#include "src.h"
-#define trace(...) { fprintf(stderr, __VA_ARGS__); }
-//#define trace(fmt,...)
+//#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+#define trace(fmt,...)
-#define WRITE_DUMP 1
+//#define WRITE_DUMP 1
#if WRITE_DUMP
FILE *out;
#endif
static intptr_t streamer_tid;
-static int src_quality;
-static SRC_STATE *src;
-static SRC_DATA srcdata;
-static int src_remaining; // number of input samples in SRC buffer
+static ddb_src_t *src;
static int conf_replaygain_mode = 0;
static int conf_replaygain_scale = 1;
-#define SRC_BUFFER 16000
-static int src_in_remaining = 0;
-//static int16_t g_src_in_buffer[SRC_BUFFER*2];
-static __attribute__((__aligned__(16))) float g_src_in_fbuffer[SRC_BUFFER*2];
-static __attribute__((__aligned__(16))) float g_src_out_fbuffer[SRC_BUFFER*2];
-
static int streaming_terminate;
// buffer up to 3 seconds at 44100Hz stereo
#define STREAM_BUFFER_SIZE 0x80000 // slightly more than 3 seconds of 44100 stereo
#define STREAM_BUFFER_MASK 0x7ffff
-//#define STREAM_BUFFER_SIZE 0x10000 // slightly more than 3 seconds of 44100 stereo
-//#define STREAM_BUFFER_MASK 0xffff
static int streambuffer_fill;
static int streambuffer_pos;
@@ -75,7 +65,6 @@ static int bytes_until_next_song = 0;
static char streambuffer[STREAM_BUFFER_SIZE];
static uintptr_t mutex;
static uintptr_t decodemutex;
-static uintptr_t srcmutex;
static int nextsong = -1;
static int nextsong_pstate = -1;
static int badsong = -1;
@@ -109,16 +98,6 @@ streamer_unlock (void) {
}
void
-src_lock (void) {
- mutex_lock (srcmutex);
-}
-
-void
-src_unlock (void) {
- mutex_unlock (srcmutex);
-}
-
-void
adjust_waveformat (ddb_waveformat_t *fmt) {
if (!fmt->is_multichannel) {
if (fmt->channels == 1) {
@@ -768,7 +747,7 @@ streamer_start_new_song (void) {
int initsng = nextsong;
int pstate = nextsong_pstate;
nextsong = -1;
- src_remaining = 0;
+ ddb_src_reset (src, 0);
streamer_unlock ();
if (badsong == sng) {
trace ("looped to bad file. stopping...\n");
@@ -865,7 +844,7 @@ streamer_thread (void *ctx) {
#ifdef __linux__
prctl (PR_SET_NAME, "deadbeef-stream", 0, 0, 0, 0);
#endif
- src_remaining = 0;
+ ddb_src_reset (src, 0);
while (!streaming_terminate) {
struct timeval tm1;
@@ -1079,7 +1058,7 @@ streamer_thread (void *ctx) {
int channels = output->fmt.channels;
int bytes_in_one_second = rate * (output->fmt.bps>>3) * channels;
const int blocksize = 4096;
- int alloc_time = 1000 / (bytes_in_one_second * 2 / blocksize);
+ int alloc_time = 1000 / (bytes_in_one_second * output->fmt.channels / blocksize);
streamer_lock ();
if (streambuffer_fill < (STREAM_BUFFER_SIZE-blocksize)) {
@@ -1144,11 +1123,6 @@ streamer_thread (void *ctx) {
playing_track = NULL;
}
mutex_unlock (decodemutex);
-
- if (src) {
- src_delete (src);
- src = NULL;
- }
}
int
@@ -1158,14 +1132,12 @@ streamer_init (void) {
#endif
mutex = mutex_create ();
decodemutex = mutex_create ();
- srcmutex = mutex_create ();
- src_quality = conf_get_int ("src_quality", 2);
- src = src_new (src_quality, 2, NULL);
- conf_replaygain_mode = conf_get_int ("replaygain_mode", 0);
- conf_replaygain_scale = conf_get_int ("replaygain_scale", 1);
+ src = ddb_src_init ();
if (!src) {
return -1;
}
+ conf_replaygain_mode = conf_get_int ("replaygain_mode", 0);
+ conf_replaygain_scale = conf_get_int ("replaygain_scale", 1);
streamer_tid = thread_start (streamer_thread, NULL);
return 0;
}
@@ -1195,8 +1167,10 @@ streamer_free (void) {
decodemutex = 0;
mutex_free (mutex);
mutex = 0;
- mutex_free (srcmutex);
- srcmutex = 0;
+ if (src) {
+ ddb_src_free (src);
+ src = NULL;
+ }
}
void
@@ -1205,15 +1179,14 @@ streamer_reset (int full) { // must be called when current song changes by exter
fprintf (stderr, "ERROR: someone called streamer_reset after exit\n");
return; // failsafe, in case someone calls streamer reset after deinit
}
- src_lock ();
+ ddb_src_lock (src);
if (full) {
streamer_lock ();
streambuffer_pos = 0;
streambuffer_fill = 0;
streamer_unlock ();
}
- src_remaining = 0;
- src_reset (src);
+ ddb_src_reset (src, 1);
// reset dsp
DB_dsp_t **dsp = deadbeef->plug_get_dsp_list ();
//int srate = output->fmt.samplerate;
@@ -1222,7 +1195,7 @@ streamer_reset (int full) { // must be called when current song changes by exter
dsp[i]->reset ();
}
}
- src_unlock ();
+ ddb_src_unlock (src);
}
int replaygain = 1;
@@ -1322,194 +1295,6 @@ mono_int16_to_stereo_int16 (int16_t *in, int16_t *out, int nsamples) {
}
}
-#if 0
-static void
-int16_to_float32 (int16_t *in, float *out, int nsamples) {
- while (nsamples > 0) {
- *out++ = (*in++)/(float)0x7fff;
- nsamples--;
- }
-}
-
-static void
-mono_int16_to_stereo_float32 (int16_t *in, float *out, int nsamples) {
- while (nsamples > 0) {
- float sample = (*in++)/(float)0x7fff;
- *out++ = sample;
- *out++ = sample;
- nsamples--;
- }
-}
-
-static void
-mono_float32_to_stereo_float32 (float *in, float *out, int nsamples) {
- while (nsamples > 0) {
- float sample = *in++;
- *out++ = sample;
- *out++ = sample;
- nsamples--;
- }
-}
-#endif
-
-static void
-float32_to_int16 (float *in, int16_t *out, int nsamples) {
- fpu_control ctl;
- fpu_setround (&ctl);
- while (nsamples > 0) {
- float sample = *in++;
- if (sample > 1) {
- sample = 1;
- }
- else if (sample < -1) {
- sample = -1;
- }
- *out++ = (int16_t)ftoi (sample*0x7fff);
- nsamples--;
- }
- fpu_restore (ctl);
-}
-
-/*
-
- src algorithm
-
- initsize = size;
- while (size > 0) {
- need_frames = SRC_BUFFER - src_remaining
- read_samples (need_frames)
- src_process (output_frames)
- convert_to_int16 (bytes, size)
- // handle errors
- }
- return initsize-size;
-
-*/
-
-#if 0
-static int
-streamer_read_data_for_src (int16_t *buffer, int frames) {
- int channels = fileinfo->fmt.channels;
- if (channels > 2) {
- channels = 2;
- }
- int bytesread = fileinfo->plugin->read_int16 (fileinfo, (uint8_t*)buffer, frames * sizeof (int16_t) * channels);
- apply_replay_gain_int16 (streaming_track, (uint8_t*)buffer, bytesread);
- if (channels == 1) {
- // convert to stereo
- int n = frames-1;
- while (n >= 0) {
- buffer[n*2+0] = buffer[n];
- buffer[n*2+1] = buffer[n];
- n--;
- }
- }
- return bytesread / (sizeof (int16_t) * channels);
-}
-
-static int
-streamer_read_data_for_src_float (float *buffer, int frames) {
- int channels = fileinfo->fmt.channels;
- if (channels > 2) {
- channels = 2;
- }
- if (fileinfo->plugin->read_float32) {
- int bytesread = fileinfo->plugin->read_float32 (fileinfo, (uint8_t*)buffer, frames * sizeof (float) * channels);
- apply_replay_gain_float32 (streaming_track, (uint8_t*)buffer, bytesread);
- if (channels == 1) {
- // convert to stereo
- int n = frames-1;
- while (n >= 0) {
- buffer[n*2+1] = buffer[n];
- buffer[n*2+0] = buffer[n];
- n--;
- }
- }
- return bytesread / (sizeof (float) * channels);
- }
-
-// trace ("read_float32 not impl\n");
- int16_t intbuffer[frames*2];
- int res = streamer_read_data_for_src (intbuffer, frames);
- for (int i = 0; i < res; i++) {
- buffer[i*2+0] = intbuffer[i*2+0]/(float)0x7fff;
- buffer[i*2+1] = intbuffer[i*2+1]/(float)0x7fff;
- }
- return res;
-}
-
-static int
-streamer_decode_src_libsamplerate (uint8_t *bytes, int size) {
- DB_output_t *output = plug_get_output ();
- int initsize = size;
- int16_t *out = (int16_t *)bytes;
- int samplerate = fileinfo->fmt.samplerate;
- if (!samplerate) {
- return 0;
- }
- float ratio = output->fmt.samplerate/(float)samplerate;
- while (size > 0) {
- int n_output_frames = size / sizeof (int16_t) / 2;
- int n_input_frames = n_output_frames * samplerate / output->fmt.samplerate + 100;
- // read data from decoder
- if (n_input_frames >= SRC_BUFFER - src_remaining ) {
- n_input_frames = SRC_BUFFER - src_remaining;
- }
-
- int nread;
- if (!n_input_frames) {
- nread = 0;
- }
- else {
- nread = streamer_read_data_for_src_float (&g_src_in_fbuffer[src_remaining*2], n_input_frames);
- }
- src_remaining += nread;
- if (!src_remaining) {
- trace ("SRC input buffer empty\n");
- break;
- }
- // resample
-
- srcdata.data_in = g_src_in_fbuffer;
- srcdata.data_out = g_src_out_fbuffer;
- srcdata.input_frames = src_remaining;
- srcdata.output_frames = size/4;
- srcdata.src_ratio = ratio;
-// trace ("SRC from %d to %d\n", samplerate, output->fmt.samplerate);
- srcdata.end_of_input = 0;//(nread == n_input_frames) ? 0 : 1;
- //if (streamer_buffering)
- src_lock ();
- src_set_ratio (src, ratio);
- int src_err = src_process (src, &srcdata);
- src_unlock ();
- if (src_err) {
- const char *err = src_strerror (src_err) ;
- fprintf (stderr, "src_process error %s\n"
- "srcdata.data_in=%p, srcdata.data_out=%p, srcdata.input_frames=%d, srcdata.output_frames=%d, srcdata.src_ratio=%f", err, srcdata.data_in, srcdata.data_out, (int)srcdata.input_frames, (int)srcdata.output_frames, (float)srcdata.src_ratio);
- exit (-1);
- }
- // convert back to s16 format
- int genbytes = srcdata.output_frames_gen * 4;
- int bytesread = min(size, genbytes);
- float32_to_int16 ((float*)g_src_out_fbuffer, (int16_t*)bytes, bytesread>>1);
- size -= bytesread;
- bytes += bytesread;
- // calculate how many unused input samples left
- src_remaining -= srcdata.input_frames_used;
-
- // copy spare samples for next update
- if (src_remaining > 0) {
- memmove (g_src_in_fbuffer, &g_src_in_fbuffer[srcdata.input_frames_used*2], src_remaining * sizeof (float) * 2);
- }
-
-// if (nread != n_input_frames) {
-// trace ("nread=%d, n_input_frames=%d, mismatch!\n", nread, n_input_frames);
-// break;
-// }
- }
- return initsize-size;
-}
-#endif
// decodes data and converts to current output format
// returns number of bytes been read
@@ -1525,22 +1310,76 @@ streamer_read_async (char *bytes, int size) {
mutex_unlock (decodemutex);
break;
}
+
if (fileinfo->fmt.samplerate != -1) {
- if (!memcmp (&fileinfo->fmt, &output->fmt, sizeof (ddb_waveformat_t)), 0) {
+ DB_dsp_t **dsp = deadbeef->plug_get_dsp_list ();
+ if (!memcmp (&fileinfo->fmt, &output->fmt, sizeof (ddb_waveformat_t))) {
bytesread = fileinfo->plugin->read (fileinfo, bytes, size);
}
else {
-// trace ("format mismatch, converting:\n");
-// trace ("input bps=%d, channels=%d, samplerate=%d, channelmask=%X\n", fileinfo->fmt.bps, fileinfo->fmt.channels, fileinfo->fmt.samplerate, fileinfo->fmt.channelmask);
-// trace ("output bps=%d, channels=%d, samplerate=%d, channelmask=%X\n", output->fmt.bps, output->fmt.channels, output->fmt.samplerate, output->fmt.channelmask);
-
- int outputsamplesize = (output->fmt.bps>>3)*output->fmt.channels;
- int inputsamplesize = (fileinfo->fmt.bps>>3)*fileinfo->fmt.channels;
- int inputsize = size/outputsamplesize*inputsamplesize;
- char input[inputsize];
- inputsize = fileinfo->plugin->read (fileinfo, input, inputsize);
- bytesread = pcm_convert (&fileinfo->fmt, input, &output->fmt, bytes, inputsize);
-// trace ("decoded %d bytes, writing %d bytes, requested %d bytes\n", inputsize, bytesread, size);
+ if (output->fmt.samplerate != fileinfo->fmt.samplerate) {
+ // convert to float, prepare for DSP
+ int outputsamplesize = (output->fmt.bps>>3)*output->fmt.channels;
+ int inputsamplesize = (fileinfo->fmt.bps>>3)*fileinfo->fmt.channels;
+
+ float ratio = output->fmt.samplerate/(float)fileinfo->fmt.samplerate;
+
+#define SRC_NUM_SAMPLES 1024
+ char outbuf[SRC_NUM_SAMPLES * output->fmt.channels * sizeof (float)];
+ char *src_data = NULL;
+ int src_data_size = 0;
+ bytesread = 0;
+ ddb_waveformat_t srcfmt;
+ memcpy (&srcfmt, &output->fmt, sizeof (srcfmt));
+ srcfmt.bps = 32;
+ srcfmt.is_float = 1;
+ int inputsize = (ftoi (SRC_NUM_SAMPLES * ratio) + 100) * inputsamplesize;
+ char input[inputsize];
+ char tempbuf[inputsize/inputsamplesize * sizeof (float) * output->fmt.channels];
+ while (1) {
+ int converted_bytes = 0;
+ // drain src
+ int n = sizeof (outbuf);
+
+ int remaining = (size - bytesread) / (output->fmt.bps >> 3) * 4;
+ if (n > remaining) {
+ n = remaining;
+ }
+ converted_bytes = ddb_src_process (src, src_data, src_data_size/(sizeof(float)*output->fmt.channels), outbuf, n, ratio, srcfmt.channels);
+
+ src_data = NULL;
+ src_data_size = 0;
+ if (converted_bytes > 0) {
+ bytesread += pcm_convert (&srcfmt, outbuf, &output->fmt, bytes + bytesread, converted_bytes);
+ assert (bytesread <= size);
+ if (bytesread == size) {
+ break;
+ }
+ continue;
+ }
+
+ // read more samples for src
+ inputsize = fileinfo->plugin->read (fileinfo, input, (ftoi (SRC_NUM_SAMPLES * ratio) + 100) * inputsamplesize);
+ if (!inputsize && !converted_bytes) {
+ break; // eof
+ }
+
+ // convert to float
+ int tempsize = pcm_convert (&fileinfo->fmt, input, &srcfmt, tempbuf, inputsize);
+ assert (tempsize <= sizeof (tempbuf));
+
+ src_data = tempbuf;
+ src_data_size = tempsize;
+ }
+ }
+ else {
+ int outputsamplesize = (output->fmt.bps>>3)*output->fmt.channels;
+ int inputsamplesize = (fileinfo->fmt.bps>>3)*fileinfo->fmt.channels;
+ int inputsize = size/outputsamplesize*inputsamplesize;
+ char input[inputsize];
+ inputsize = fileinfo->plugin->read (fileinfo, input, inputsize);
+ bytesread = pcm_convert (&fileinfo->fmt, input, &output->fmt, bytes, inputsize);
+ }
}
#if WRITE_DUMP
if (bytesread) {
@@ -1715,19 +1554,8 @@ void
streamer_configchanged (void) {
conf_replaygain_mode = conf_get_int ("replaygain_mode", 0);
conf_replaygain_scale = conf_get_int ("replaygain_scale", 1);
- int q = conf_get_int ("src_quality", 2);
- if (q != src_quality && q >= SRC_SINC_BEST_QUALITY && q <= SRC_LINEAR) {
- src_lock ();
- trace ("changing src_quality from %d to %d\n", src_quality, q);
- src_quality = q;
- if (src) {
- src_delete (src);
- src = NULL;
- }
- memset (&srcdata, 0, sizeof (srcdata));
- src = src_new (src_quality, 2, NULL);
- src_unlock ();
- }
+
+ ddb_src_confchanged (src);
}
void