Author: titmuss
Date: Fri May 16 05:52:53 2008
New Revision: 2469

URL: http://svn.slimdevices.com?rev=2469&root=Jive&view=rev
Log:
Bug: N/A
Description:
Add support for mp3 gapless playback.


Modified:
    7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_mad.c
    7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c
    7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h

Modified: 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_mad.c
URL: 
http://svn.slimdevices.com/7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_mad.c?rev=2469&root=Jive&r1=2468&r2=2469&view=diff
==============================================================================
--- 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_mad.c 
(original)
+++ 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_mad.c Fri May 
16 05:52:53 2008
@@ -31,6 +31,10 @@
        u8_t *input_buffer;
        sample_t *output_buffer;
        u8_t *guard_pointer;
+
+       u32_t frames;
+       u32_t encoder_delay;
+       u32_t encoder_padding;
 
        enum {
                MAD_STATE_OK = 0,
@@ -43,6 +47,95 @@
 };
 
 
+#define XING_MAGIC      ( ('X' << 24) | ('i' << 16) | ('n' << 8) | 'g' )
+#define INFO_MAGIC      ( ('I' << 24) | ('n' << 16) | ('f' << 8) | 'o' )
+#define LAME_MAGIC      ( ('L' << 24) | ('A' << 16) | ('M' << 8) | 'E' )
+
+#define XING_FRAMES    0x01
+#define XING_BYTES     0x02
+#define XING_TOC       0x04
+#define XING_SCALE     0x08
+
+static void xing_parse(struct decode_mad *self) {
+       struct mad_bitptr ptr = self->stream.anc_ptr;
+       unsigned int bitlen = self->stream.anc_bitlen;
+
+       if (bitlen < 64) {
+               DEBUG_TRACE("no xing header");
+               return;
+       }
+
+       u32_t magic = mad_bit_read(&ptr, 32);
+       DEBUG_TRACE("xing magic %x", magic);
+       if (magic != XING_MAGIC && magic != INFO_MAGIC) {
+               return;
+       }
+
+       u32_t flags = mad_bit_read(&ptr, 32);
+       bitlen -= 64;
+
+       // skip traditional xing vbr tag data
+       if (flags & XING_FRAMES) {
+               DEBUG_TRACE("skipping xing frames");
+               if (bitlen < 32) {
+                       return;
+               }
+               mad_bit_skip(&ptr, 32);
+               bitlen -= 32;
+       }
+       if (flags & XING_BYTES) {
+               DEBUG_TRACE("skipping xing bytes");
+               if (bitlen < 32) {
+                       return;
+               }
+               mad_bit_skip(&ptr, 32);
+               bitlen -= 32;
+       }
+       if (flags & XING_TOC) {
+               DEBUG_TRACE("skipping xing toc");
+               if (bitlen < 800) {
+                       return;
+               }
+               mad_bit_skip(&ptr, 800);
+               bitlen -= 800;
+       }
+       if (flags & XING_SCALE) {
+               DEBUG_TRACE("skipping xing scale");
+               if (bitlen < 32) {
+                       return;
+               }
+               mad_bit_skip(&ptr, 32);
+               bitlen -= 32;
+       }
+
+       if (bitlen < 72) {
+               DEBUG_TRACE("no lame header");
+               return;
+       }
+
+       magic = mad_bit_read(&ptr, 32);
+       mad_bit_skip(&ptr, 40);
+       bitlen -= 72;
+
+       DEBUG_TRACE("lame magic %x", magic);
+       if (magic != LAME_MAGIC) {
+               return;
+       }
+
+       if (bitlen < 120) {
+               return;
+       }
+
+       mad_bit_skip(&ptr, 96);
+
+       self->encoder_delay = mad_bit_read(&ptr, 12);
+       self->encoder_padding = mad_bit_read(&ptr, 12);
+
+       DEBUG_TRACE("encoder delay %d", self->encoder_delay);
+       DEBUG_TRACE("encoder padding %d", self->encoder_padding);
+}
+
+
 static void decode_mad_frame(struct decode_mad *self) {
        size_t read_max, read_num, remaining;
        u8_t *read_start;
@@ -82,7 +175,7 @@
                                /* If we're at the end of the input file, write
                                 * out the buffer guard.
                                 */
-                               self->guard_pointer = read_start + read_num;
+                               self->guard_pointer = read_start;
                                memset(self->guard_pointer, 0, 
MAD_BUFFER_GUARD);
                                read_num += MAD_BUFFER_GUARD;
                        }
@@ -129,49 +222,68 @@
 
 
 static void decode_mad_output(struct decode_mad *self) {
+       struct mad_pcm *pcm;
        sample_t *buf;
        mad_fixed_t *left, *right;
-       int i;
+       int i, offset = 0;
+
+       pcm = &self->synth.pcm;
 
        self->sample_rate = self->frame.header.samplerate;
 
-       if (!decode_output_can_write(self->synth.pcm.length * 2 * 
sizeof(sample_t), self->sample_rate)) {
+       if (!decode_output_can_write(pcm->length * 2 * sizeof(sample_t), 
self->sample_rate)) {
                self->state = MAD_STATE_PCM_READY;
                return;
        }
 
-       // XXXX parse xing header
-
-       buf = self->output_buffer;
-
-       left = self->synth.pcm.samples[0];
-       right = self->synth.pcm.samples[1];
-
-       if (self->synth.pcm.channels == 2) {
-               /* stero */
-               for (i=0; i<self->synth.pcm.length; i++) {
-                       *buf++ = *left++ << (32 - MAD_F_FRACBITS - 1);
-                       *buf++ = *right++ << (32 - MAD_F_FRACBITS - 1);
-               }
+       /* parse xing header */
+       if (self->frames++ == 0) {
+               xing_parse(self);
+               self->encoder_delay *= pcm->channels;
        }
        else {
-               /* mono */
-               sample_t s;
-
-               for (i=0; i<self->synth.pcm.length; i++) {
-                       s = *left++ << (32 - MAD_F_FRACBITS - 1);
-
-                       *buf++ = s;
-                       *buf++ = s;
-               }
-       }
-       
-       decode_output_samples(self->output_buffer,
-                             self->synth.pcm.length,
-                             self->sample_rate,
-                             FALSE,
-                             TRUE,
-                             FALSE);
+               buf = self->output_buffer;
+
+               left = pcm->samples[0];
+               right = pcm->samples[1];
+
+               if (pcm->channels == 2) {
+                       /* stero */
+                       for (i=0; i<pcm->length; i++) {
+                               *buf++ = *left++ << (32 - MAD_F_FRACBITS - 1);
+                               *buf++ = *right++ << (32 - MAD_F_FRACBITS - 1);
+                       }
+               }
+               else {
+                       /* mono */
+                       sample_t s;
+
+                       for (i=0; i<pcm->length; i++) {
+                               s = *left++ << (32 - MAD_F_FRACBITS - 1);
+
+                               *buf++ = s;
+                               *buf++ = s;
+                       }
+               }
+
+               /* skip samples for the encoder delay */
+               if (self->encoder_delay) {
+                       offset = self->encoder_delay;
+                       if (offset > pcm->length) {
+                               offset = pcm->length;
+                       }
+                       self->encoder_delay -= offset;
+
+                       DEBUG_TRACE("Skip encoder_delay=%d pcm->length=%d 
offset=%d", self->encoder_delay, pcm->length, offset);
+               }
+               
+               decode_output_samples(self->output_buffer + (offset * 
sizeof(sample_t)),
+                                     pcm->length - offset,
+                                     self->sample_rate,
+                                     FALSE,
+                                     TRUE,
+                                     FALSE);
+       }
 
        /* If we've come to the guard pointer, we're done */
        if (self->stream.this_frame == self->guard_pointer) {
@@ -179,7 +291,10 @@
 
                self->state = MAD_STATE_END_OF_FILE;
 
-               // XXXX remove padding?
+               if (self->encoder_padding) {
+                       DEBUG_TRACE("Remove encoder padding=%d", 
self->encoder_padding);
+                       decode_output_remove_padding(self->encoder_padding, 
self->sample_rate);
+               }
        }
        else {
                self->state = MAD_STATE_OK;
@@ -243,6 +358,10 @@
 
        /* Assume we aren't changing sample rates until proven wrong */
        self->sample_rate = decode_output_samplerate();
+
+       /* Don't check for CRC errors (bug #2527) */
+       // XXXX this needs a patch to libmad
+       //decoder->stream.options = MAD_OPTION_ZEROCRC;
        
        return self;
 }

Modified: 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c
URL: 
http://svn.slimdevices.com/7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c?rev=2469&root=Jive&r1=2468&r2=2469&view=diff
==============================================================================
--- 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c 
(original)
+++ 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c Fri 
May 16 05:52:53 2008
@@ -166,6 +166,48 @@
 }
 
 
+/* This removes padding samples from the buffer (for gapless mp3 playback). */
+void decode_output_remove_padding(u32_t nsamples, u32_t sample_rate) {
+#if 0
+       int numerator, denominator;
+       u32_t resampled_rate;
+#endif
+       size_t buffer_size;
+
+       buffer_size = SAMPLES_TO_BYTES(nsamples);
+
+#if 0
+       // XXXX full port from ip3k
+       u32_t resampled_rate = decode_output_scaled_samplerate(sample_rate, 
&numerator, &denominator);
+       if (numerator != 1) {
+               buffer_size /= numerator;
+       }
+       buffer_size *= denominator;
+#endif
+
+       DEBUG_TRACE("Removing %d bytes padding from buffer", buffer_size);
+
+       fifo_lock(&decode_fifo);
+
+       /* have we already started playing the padding? */
+       if (fifo_bytes_used(&decode_fifo) <= buffer_size) {
+               fifo_unlock(&decode_fifo);
+
+               DEBUG_TRACE("- already playing padding");
+               return;
+       }
+
+       if (decode_fifo.wptr < buffer_size) {
+               decode_fifo.wptr += decode_fifo.size - buffer_size;
+       }
+       else {
+               decode_fifo.wptr -= buffer_size;
+       }
+
+       fifo_unlock(&decode_fifo);
+}
+
+
 int decode_output_samplerate() {
        return current_sample_rate;
 }

Modified: 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h
URL: 
http://svn.slimdevices.com/7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h?rev=2469&root=Jive&r1=2468&r2=2469&view=diff
==============================================================================
--- 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h 
(original)
+++ 7.2/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h Fri 
May 16 05:52:53 2008
@@ -48,6 +48,8 @@
                                   bool_t need_scaling, bool_t 
start_immediately,
                                   bool_t copyright_asserted);
 
+extern void decode_output_remove_padding(u32_t nsamples, u32_t sample_rate);
+
 extern int decode_output_samplerate();
 
 

_______________________________________________
Jive-checkins mailing list
[email protected]
http://lists.slimdevices.com/cgi-bin/mailman/listinfo/jive-checkins

Reply via email to