+++ /dev/null
-#include <limits>
-#include <mad.h>
-#include <msp/strings/format.h>
-#include "mp3decoder.h"
-
-using namespace std;
-
-namespace {
-
-Msp::Int16 scale(mad_fixed_t sample)
-{
- if(sample<=-MAD_F_ONE)
- return numeric_limits<Msp::Int16>::min();
- else if(sample>=MAD_F_ONE)
- return numeric_limits<Msp::Int16>::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
- {
- 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(...)
- {
- delete[] in_buffer;
- throw;
- }
-}
-
-Mp3Decoder::~Mp3Decoder()
-{
- delete[] in_buffer;
- mad_synth_finish(&priv->synth);
- mad_frame_finish(&priv->frame);
- mad_stream_finish(&priv->stream);
- delete priv;
-}
-
-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()<sizeof(id3_sig))
- return false;
- return !sig.compare(0, sizeof(id3_sig), id3_sig, sizeof(id3_sig));
-}
-
-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 = get_n_channels(format);
- mad_pcm &pcm = priv->synth.pcm;
-
- unsigned pos = 0;
- while(pos+2*nchan<=len)
- {
- if(read_pos>=pcm.length && !decode(true))
- break;
-
- for(unsigned i=0; i<nchan; ++i)
- {
- Int16 sample = scale(pcm.samples[i][read_pos]);
- buf[pos++] = sample;
- buf[pos++] = sample>>8;
- }
-
- ++read_pos;
- }
-
- return pos;
-}
-
-bool Mp3Decoder::fill_input()
-{
- unsigned in_pos = 0;
- if(priv->stream.next_frame && priv->stream.next_frame<priv->stream.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<unsigned char *>(in_buffer), in_pos);
- priv->stream.error = MAD_ERROR_NONE;
-
- return len;
-}
-
-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(!try_decode(full))
- {
- if(priv->stream.error==MAD_ERROR_BUFLEN)
- {
- if(!fill_input())
- return false;
- }
- 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
-} // namespace Msp