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(...)
mad_synth_finish(&priv->synth);
mad_frame_finish(&priv->frame);
mad_stream_finish(&priv->stream);
+ delete priv;
}
bool Mp3Decoder::detect(const string &sig)
return !sig.compare(0, sizeof(id3_sig), 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)
{
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