diff options
-rw-r--r-- | cmp3.c | 148 | ||||
-rw-r--r-- | deadbeef.h | 4 | ||||
-rw-r--r-- | streamer.c | 53 |
3 files changed, 152 insertions, 53 deletions
@@ -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, @@ -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); @@ -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 (); |