X-Git-Url: http://git.tdb.fi/?p=libs%2Fal.git;a=blobdiff_plain;f=source%2Fmp3decoder.cpp;fp=source%2Fmp3decoder.cpp;h=a717cf4b3b4dde400cac7b234d4cecf6db822c1d;hp=0000000000000000000000000000000000000000;hb=0e266d73f9aab89410c736e969eaa51ef914acf1;hpb=d035e638b940f25cb5d46a049a00b34dc60dc5e0 diff --git a/source/mp3decoder.cpp b/source/mp3decoder.cpp new file mode 100644 index 0000000..a717cf4 --- /dev/null +++ b/source/mp3decoder.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include "mp3decoder.h" + +using namespace std; + +namespace { + +Msp::Int16 scale(mad_fixed_t sample) +{ + if(sample<=-MAD_F_ONE) + return numeric_limits::min(); + else if(sample>=MAD_F_ONE) + return numeric_limits::max(); + else + return (sample + (1<<(MAD_F_FRACBITS-16))) >> (MAD_F_FRACBITS-15); +} + +} // namespace + + +namespace Msp { +namespace AL { + +mp3_error::mp3_error(const std::string &func, int err): + runtime_error(format("%s: %s", func, get_message(err))) +{ } + +string mp3_error::get_message(int err) +{ + return format("%d", err); +} + + +struct Mp3Decoder::Private +{ + mad_stream stream; + mad_frame frame; + mad_synth synth; +}; + + +Mp3Decoder::Mp3Decoder(IO::Seekable &io): + priv(new Private), + in(io), + in_buf_size(16384), + in_buffer(new char[in_buf_size]), + read_pos(0) +{ + mad_stream_init(&priv->stream); + mad_frame_init(&priv->frame); + mad_synth_init(&priv->synth); + + try + { + decode_frame(); + format = (priv->frame.header.mode==MAD_MODE_SINGLE_CHANNEL ? MONO16 : STEREO16); + freq = priv->frame.header.samplerate; + } + catch(...) + { + delete[] in_buffer; + throw; + } +} + +Mp3Decoder::~Mp3Decoder() +{ + delete[] in_buffer; + mad_synth_finish(&priv->synth); + mad_frame_finish(&priv->frame); + mad_stream_finish(&priv->stream); +} + +bool Mp3Decoder::detect(const string &sig) +{ + if(sig.size()>=2 && sig[0]=='\xFF' && (sig[1]&0xE0)==0xE0) + return true; + + static const char id3_sig[] = { 'I', 'D', '3' }; + if(sig.size()synth.pcm; + + unsigned pos = 0; + while(pos+2*nchan<=len) + { + if(read_pos>=pcm.length) + { + if(!decode_frame()) + break; + } + + for(unsigned i=0; i>8; + } + + ++read_pos; + } + + return pos; +} + +bool Mp3Decoder::fill_input() +{ + unsigned in_pos = 0; + if(priv->stream.next_frame && priv->stream.next_framestream.bufend) + { + copy(priv->stream.next_frame, priv->stream.bufend, in_buffer); + in_pos = priv->stream.bufend-priv->stream.next_frame; + } + + unsigned len = in.read(in_buffer+in_pos, in_buf_size-in_pos); + in_pos += len; + + mad_stream_buffer(&priv->stream, reinterpret_cast(in_buffer), in_pos); + priv->stream.error = MAD_ERROR_NONE; + + return len; +} + +bool Mp3Decoder::decode_frame() +{ + while(1) + { + if(!priv->stream.buffer || 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); + } +} + +} // namespace AL +} // namespace Msp