summaryrefslogtreecommitdiff
path: root/streamer.c
diff options
context:
space:
mode:
Diffstat (limited to 'streamer.c')
-rw-r--r--streamer.c344
1 files changed, 86 insertions, 258 deletions
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