]> git.tdb.fi Git - libs/al.git/blobdiff - source/mp3decoder.cpp
Fix sound file signature comparisons
[libs/al.git] / source / mp3decoder.cpp
index a717cf4b3b4dde400cac7b234d4cecf6db822c1d..cc3235683db098cc5782ef11ba2b7094678f9bb1 100644 (file)
@@ -54,8 +54,10 @@ Mp3Decoder::Mp3Decoder(IO::Seekable &io):
 
        try
        {
-               decode_frame();
-               format = (priv->frame.header.mode==MAD_MODE_SINGLE_CHANNEL ? MONO16 : STEREO16);
+               if(!fill_input() || !decode(false))
+                       throw runtime_error("no mp3 data");
+
+               format = create_format(2, MAD_NCHANNELS(&priv->frame.header));
                freq = priv->frame.header.samplerate;
        }
        catch(...)
@@ -71,6 +73,7 @@ Mp3Decoder::~Mp3Decoder()
        mad_synth_finish(&priv->synth);
        mad_frame_finish(&priv->frame);
        mad_stream_finish(&priv->stream);
+       delete priv;
 }
 
 bool Mp3Decoder::detect(const string &sig)
@@ -81,27 +84,47 @@ bool Mp3Decoder::detect(const string &sig)
        static const char id3_sig[] = { 'I', 'D', '3' };
        if(sig.size()<sizeof(id3_sig))
                return false;
-       return !sig.compare(0, sizeof(id3_sig), id3_sig);
+       return !sig.compare(0, sizeof(id3_sig), id3_sig, sizeof(id3_sig));
 }
 
-void Mp3Decoder::rewind()
+void Mp3Decoder::seek(unsigned pos)
 {
+       unsigned unit = get_unit_size(format);
+       pos /= unit;
+
        in.seek(0, IO::S_BEG);
+       mad_stream_buffer(&priv->stream, 0, 0);
+       fill_input();
+       if(!pos)
+       {
+               priv->synth.pcm.length = 0;
+               return;
+       }
+
+       while(decode(false))
+       {
+               unsigned frame_len = 32*MAD_NSBSAMPLES(&priv->frame.header);
+               if(frame_len>pos)
+               {
+                       decode(true);
+                       read_pos = pos;
+                       break;
+               }
+
+               pos -= frame_len;
+       }
 }
 
 unsigned Mp3Decoder::read(char *buf, unsigned len)
 {
-       unsigned nchan = (format==STEREO16 ? 2 : 1);
+       unsigned nchan = get_n_channels(format);
        mad_pcm &pcm = priv->synth.pcm;
 
        unsigned pos = 0;
        while(pos+2*nchan<=len)
        {
-               if(read_pos>=pcm.length)
-               {
-                       if(!decode_frame())
-                               break;
-               }
+               if(read_pos>=pcm.length && !decode(true))
+                       break;
 
                for(unsigned i=0; i<nchan; ++i)
                {
@@ -134,26 +157,34 @@ bool Mp3Decoder::fill_input()
        return len;
 }
 
-bool Mp3Decoder::decode_frame()
+bool Mp3Decoder::try_decode(bool full)
+{
+       if(full)
+               return !mad_frame_decode(&priv->frame, &priv->stream);
+       else
+               return !mad_header_decode(&priv->frame.header, &priv->stream);
+}
+
+bool Mp3Decoder::decode(bool full)
 {
-       while(1)
+       while(!try_decode(full))
        {
-               if(!priv->stream.buffer || priv->stream.error==MAD_ERROR_BUFLEN)
+               if(priv->stream.error==MAD_ERROR_BUFLEN)
+               {
                        if(!fill_input())
                                return false;
-
-               if(!mad_frame_decode(&priv->frame, &priv->stream))
-               {
-                       mad_synth_frame(&priv->synth, &priv->frame);
-                       read_pos = 0;
-                       return true;
                }
-
-               if(priv->stream.error==MAD_ERROR_BUFLEN)
-                       continue;
                else if(!MAD_RECOVERABLE(priv->stream.error))
                        throw mp3_error("mad_frame_decode", priv->stream.error);
        }
+
+       if(full)
+       {
+               read_pos = 0;
+               mad_synth_frame(&priv->synth, &priv->frame);
+       }
+
+       return true;
 }
 
 } // namespace AL