summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2009-08-29 23:04:23 +0200
committerGravatar waker <wakeroid@gmail.com>2009-08-29 23:04:35 +0200
commit2b088104790e6f752e1c342d6c4caf7dc23755fd (patch)
treebdd4c984daaeed5c6e84cfb2daeda374c5b40380
parentf4d508b243888a9dbe79b5916e497254d370e35a (diff)
read_float32 support in mad mp3 decoder and streamer
-rw-r--r--cmp3.c148
-rw-r--r--deadbeef.h4
-rw-r--r--streamer.c53
3 files changed, 152 insertions, 53 deletions
diff --git a/cmp3.c b/cmp3.c
index d0db147f..671a3e4e 100644
--- a/cmp3.c
+++ b/cmp3.c
@@ -36,7 +36,7 @@ static DB_functions_t *deadbeef;
#define READBUFFER 5*8192
// FIXME: cache is bad name for this
-#define CACHESIZE 81920
+#define BUFSIZE 81920
// vbrmethod constants
#define LAME_CBR 1
@@ -59,12 +59,14 @@ typedef struct {
char input[READBUFFER];
int remaining;
- // output buffer, supplied by player
- char *output;
+ // NOTE: both "output" and "cache" buffers store sampels in libmad fixed point format
+
+// // output buffer, supplied by player
+// char output[BUFSIZE];
int readsize;
// cache, for extra decoded samples
- char cache[CACHESIZE];
+ char cache[BUFSIZE];
int cachefill;
// information, filled by cmp3_scan_stream
@@ -119,7 +121,7 @@ cmp3_init (DB_playItem_t *it) {
buffer.startoffset = it->startoffset;
buffer.endoffset = it->endoffset;
buffer.remaining = 0;
- buffer.output = NULL;
+ //buffer.output = NULL;
buffer.readsize = 0;
buffer.cachefill = 0;
plugin.info.readpos = 0;
@@ -159,7 +161,8 @@ cmp3_init (DB_playItem_t *it) {
* Converts a sample from libmad's fixed point number format to a signed *
* short (16 bits). *
****************************************************************************/
-static signed short MadFixedToSshort(mad_fixed_t Fixed)
+static inline int16_t
+MadFixedToSshort(mad_fixed_t Fixed)
{
/* A fixed point number is formed of the following bit pattern:
*
@@ -192,6 +195,11 @@ static signed short MadFixedToSshort(mad_fixed_t Fixed)
return((signed short)Fixed);
}
+static inline float
+MadFixedToFloat (mad_fixed_t Fixed) {
+ return (float)((Fixed) / (float)(1L << MAD_F_FRACBITS));
+}
+
#define MadErrorString(x) mad_stream_errorstr(x)
static uint32_t
@@ -480,8 +488,8 @@ cmp3_scan_stream (buffer_t *buffer, float position) {
static int
cmp3_decode (void) {
- int nread = 0;
int eof = 0;
+// char *output = buffer.output;
for (;;) {
if (eof) {
break;
@@ -548,37 +556,47 @@ cmp3_decode (void) {
int i;
for(i=0;i<synth.pcm.length;i++)
{
+#if 0
if (buffer.readsize > 0) {
- *((int16_t*)buffer.output) = MadFixedToSshort(synth.pcm.samples[0][i]);
- buffer.output+=2;
+ *((int16_t*)output) = MadFixedToSshort(synth.pcm.samples[0][i]);
+ output+=2;
buffer.readsize-=2;
- nread += 2;
if(MAD_NCHANNELS(&frame.header)==2) {
- *((int16_t*)buffer.output) = MadFixedToSshort(synth.pcm.samples[1][i]);
- buffer.output+=2;
+ *((int16_t*)output) = MadFixedToSshort(synth.pcm.samples[1][i]);
+ output+=2;
buffer.readsize-=2;
- nread += 2;
- }
- }
- else if (buffer.cachefill < CACHESIZE) {
- assert (buffer.cachefill < CACHESIZE-2);
- *((int16_t*)cache) = MadFixedToSshort(synth.pcm.samples[0][i]);
- cache+=2;
- buffer.cachefill+=2;
- if (MAD_NCHANNELS(&frame.header) == 2) {
- assert (buffer.cachefill < CACHESIZE-2);
- *((int16_t*)cache) = MadFixedToSshort(synth.pcm.samples[1][i]);
- cache+=2;
- buffer.cachefill+=2;
}
}
- else {
+ else
+#endif
+ if (buffer.cachefill >= BUFSIZE) {
printf ("cache overflow!\n");
break;
}
+ if (buffer.cachefill >= BUFSIZE - sizeof (mad_fixed_t)) {
+// printf ("readsize=%d, pcm.length=%d(%d)\n", buffer.readsize, synth.pcm.length, i);
+ }
+ assert (buffer.cachefill < BUFSIZE - sizeof (mad_fixed_t));
+ memcpy (cache, &synth.pcm.samples[0][i], sizeof (mad_fixed_t));
+// *((int16_t*)cache) = MadFixedToSshort(synth.pcm.samples[0][i]);
+ cache += sizeof (mad_fixed_t);
+ buffer.cachefill += sizeof (mad_fixed_t);
+ buffer.readsize -= sizeof (mad_fixed_t);
+ if (MAD_NCHANNELS(&frame.header) == 2) {
+ if (buffer.cachefill >= BUFSIZE - sizeof (mad_fixed_t)) {
+// printf ("readsize=%d, pcm.length=%d(%d)\n", buffer.readsize, synth.pcm.length, i);
+ }
+ assert (buffer.cachefill < BUFSIZE - sizeof (mad_fixed_t));
+// *((int16_t*)cache) = MadFixedToSshort(synth.pcm.samples[1][i]);
+ memcpy (cache, &synth.pcm.samples[1][i], sizeof (mad_fixed_t));
+ cache += sizeof (mad_fixed_t);
+ buffer.cachefill += sizeof (mad_fixed_t);
+ buffer.readsize -= sizeof (mad_fixed_t);
+ }
}
- if (buffer.readsize == 0 || eof) {
+ //printf ("readsize at end of frame: %d\n", buffer.readsize);
+ if (buffer.readsize <= 0 || eof) {
break;
}
// if (buffer.readsize > 0 && endoffile) {
@@ -587,7 +605,7 @@ cmp3_decode (void) {
// return -1;
// }
}
- return nread;
+ return 0;
}
void
@@ -608,12 +626,28 @@ cmp3_read (char *bytes, int size) {
if (plugin.info.readpos >= (buffer.timeend - buffer.timestart)) {
return 0;
}
+ int nsamples = size / 2 / plugin.info.channels;
+ size *= 2; // convert to mad sample size
+ if (buffer.cachefill < size) {
+ buffer.readsize = (size - buffer.cachefill);
+ cmp3_decode ();
+ plugin.info.readpos = (float)buffer.timer.seconds + (float)buffer.timer.fraction / MAD_TIMER_RESOLUTION;
+ }
if (buffer.cachefill > 0) {
int sz = min (size, buffer.cachefill);
- memcpy (bytes, buffer.cache, sz);
- bytes += sz;
- size -= sz;
- ret += sz;
+ mad_fixed_t *cache = (mad_fixed_t *)buffer.cache;
+ for (int i = 0; i < nsamples; i++) {
+ *((int16_t*)bytes) = MadFixedToSshort(cache[i * plugin.info.channels]);
+ bytes += 2;
+ size -= 2;
+ ret += 2;
+ if (plugin.info.channels == 2) {
+ *((int16_t*)bytes) = MadFixedToSshort(cache[i * plugin.info.channels + 1]);
+ bytes += 2;
+ size -= 2;
+ ret += 2;
+ }
+ }
if (buffer.cachefill > sz) {
memmove (buffer.cache, &buffer.cache[sz], buffer.cachefill-sz);
buffer.cachefill -= sz;
@@ -622,18 +656,54 @@ cmp3_read (char *bytes, int size) {
buffer.cachefill = 0;
}
}
- if (size > 0) {
- buffer.output = bytes;
- buffer.readsize = size;
- ret += cmp3_decode ();
+ if (plugin.info.readpos >= (buffer.timeend - buffer.timestart)) {
+ return 0;
+ }
+ return ret;
+}
+
+int
+cmp3_read_float32 (char *bytes, int size) {
+ int result;
+ int ret = 0;
+ if (plugin.info.readpos >= (buffer.timeend - buffer.timestart)) {
+ return 0;
+ }
+ int nsamples = size / 4 / plugin.info.channels;
+ if (buffer.cachefill < size) {
+ buffer.readsize = (size - buffer.cachefill);
+ //printf ("decoding %d bytes using read_float32\n", buffer.readsize);
+ cmp3_decode ();
plugin.info.readpos = (float)buffer.timer.seconds + (float)buffer.timer.fraction / MAD_TIMER_RESOLUTION;
}
+ if (buffer.cachefill > 0) {
+ int sz = min (size, buffer.cachefill);
+ mad_fixed_t *cache = (mad_fixed_t *)buffer.cache;
+ for (int i = 0; i < nsamples; i++) {
+ *((float*)bytes) = MadFixedToFloat(cache[i * plugin.info.channels]);
+ bytes += 4;
+ size -= 4;
+ ret += 4;
+ if (plugin.info.channels == 2) {
+ *((float*)bytes) = MadFixedToFloat(cache[i * plugin.info.channels + 1]);
+ bytes += 4;
+ size -= 4;
+ ret += 4;
+ }
+ }
+ if (buffer.cachefill > sz) {
+ memmove (buffer.cache, &buffer.cache[sz], buffer.cachefill-sz);
+ buffer.cachefill -= sz;
+ }
+ else {
+ buffer.cachefill = 0;
+ }
+ }
if (plugin.info.readpos >= (buffer.timeend - buffer.timestart)) {
return 0;
}
return ret;
}
-
int
cmp3_seek (float time) {
time += buffer.timestart;
@@ -1672,7 +1742,9 @@ static DB_decoder_t plugin = {
.plugin.website = "http://deadbeef.sf.net",
.init = cmp3_init,
.free = cmp3_free,
- .read = cmp3_read,
+// .read = cmp3_read,
+ .read_int16 = cmp3_read,
+ .read_float32 = cmp3_read_float32,
.seek = cmp3_seek,
.insert = cmp3_insert,
.exts = exts,
diff --git a/deadbeef.h b/deadbeef.h
index 537ad014..8d6f6e6e 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -198,8 +198,8 @@ typedef struct DB_decoder_s {
// read is called by streamer to decode specified number of bytes
// must return number of bytes that were successfully decoded (sample aligned)
- // dummy function ptr
- int (*read) (char *buffer, int size);
+// // dummy function ptr
+// int (*read) (char *buffer, int size);
// read_int16 must always output 16 bit signed integer samples
int (*read_int16) (char *buffer, int size);
diff --git a/streamer.c b/streamer.c
index b5dafebc..91ae3cda 100644
--- a/streamer.c
+++ b/streamer.c
@@ -219,11 +219,11 @@ streamer_read_async (char *bytes, int size) {
if (decoder->info.samplerate == p_get_rate ()) {
int i;
if (decoder->info.channels == 2) {
- bytesread = decoder->read (bytes, size);
+ bytesread = decoder->read_int16 (bytes, size);
codec_unlock ();
}
else {
- bytesread = decoder->read (g_readbuffer, size/2);
+ bytesread = decoder->read_int16 (g_readbuffer, size/2);
codec_unlock ();
for (i = 0; i < size/4; i++) {
int16_t sample = (int16_t)(((int32_t)(((int16_t*)g_readbuffer)[i])));
@@ -243,6 +243,7 @@ streamer_read_async (char *bytes, int size) {
assert (src_is_valid_ratio ((double)p_get_rate ()/samplerate));
// read data at source samplerate (with some room for SRC)
int nbytes = (nsamples - codecleft) * 2 * nchannels;
+ int samplesize = 2;
if (nbytes < 0) {
nbytes = 0;
}
@@ -251,23 +252,49 @@ streamer_read_async (char *bytes, int size) {
// printf ("FATAL: nbytes=%d, nsamples=%d, codecleft=%d, nchannels=%d, ratio=%f\n", nbytes, nsamples, codecleft, nchannels, (float)p_get_rate ()/samplerate);
// assert ((nbytes & 3) == 0);
// }
- bytesread = decoder->read (g_readbuffer, nbytes);
+ if (!decoder->read_float32) {
+ bytesread = decoder->read_int16 (g_readbuffer, nbytes);
+ }
+ else {
+ samplesize = 4;
+ }
}
codec_unlock ();
// recalculate nsamples according to how many bytes we've got
- nsamples = bytesread / (2 * nchannels) + codecleft;
- // convert to float
int i;
- float *fbuffer = g_fbuffer + codecleft*2;
- if (nchannels == 2) {
- for (i = 0; i < (nsamples - codecleft) * 2; i++) {
- fbuffer[i] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ if (!decoder->read_float32) {
+ nsamples = bytesread / (samplesize * nchannels) + codecleft;
+ // convert to float
+ float *fbuffer = g_fbuffer + codecleft*2;
+ if (nchannels == 2) {
+ for (i = 0; i < (nsamples - codecleft) * 2; i++) {
+ fbuffer[i] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ }
+ }
+ else if (nchannels == 1) { // convert mono to stereo
+ for (i = 0; i < (nsamples - codecleft); i++) {
+ fbuffer[i*2+0] = ((int16_t *)g_readbuffer)[i]/32767.f;
+ fbuffer[i*2+1] = fbuffer[i*2+0];
+ }
}
}
- else if (nchannels == 1) { // convert mono to stereo
- for (i = 0; i < (nsamples - codecleft); i++) {
- fbuffer[i*2+0] = ((int16_t *)g_readbuffer)[i]/32767.f;
- fbuffer[i*2+1] = fbuffer[i*2+0];
+ else {
+ float *fbuffer = g_fbuffer + codecleft*2;
+ if (nchannels == 1) {
+ codec_lock ();
+ bytesread = decoder->read_float32 (g_readbuffer, nbytes*2);
+ codec_unlock ();
+ nsamples = bytesread / (samplesize * nchannels) + codecleft;
+ for (i = 0; i < (nsamples - codecleft); i++) {
+ fbuffer[i*2+0] = ((float *)g_readbuffer)[i];
+ fbuffer[i*2+1] = fbuffer[i*2+0];
+ }
+ }
+ else {
+ codec_lock ();
+ bytesread = decoder->read_float32 ((char *)fbuffer, nbytes*2);
+ codec_unlock ();
+ nsamples = bytesread / (samplesize * nchannels) + codecleft;
}
}
//codec_lock ();