]> git.tdb.fi Git - libs/al.git/blob - source/mp3decoder.cpp
cc3235683db098cc5782ef11ba2b7094678f9bb1
[libs/al.git] / source / mp3decoder.cpp
1 #include <limits>
2 #include <mad.h>
3 #include <msp/strings/format.h>
4 #include "mp3decoder.h"
5
6 using namespace std;
7
8 namespace {
9
10 Msp::Int16 scale(mad_fixed_t sample)
11 {
12         if(sample<=-MAD_F_ONE)
13                 return numeric_limits<Msp::Int16>::min();
14         else if(sample>=MAD_F_ONE)
15                 return numeric_limits<Msp::Int16>::max();
16         else
17                 return (sample + (1<<(MAD_F_FRACBITS-16))) >> (MAD_F_FRACBITS-15);
18 }
19
20 } // namespace
21
22
23 namespace Msp {
24 namespace AL {
25
26 mp3_error::mp3_error(const std::string &func, int err):
27         runtime_error(format("%s: %s", func, get_message(err)))
28 { }
29
30 string mp3_error::get_message(int err)
31 {
32         return format("%d", err);
33 }
34
35
36 struct Mp3Decoder::Private
37 {
38         mad_stream stream;
39         mad_frame frame;
40         mad_synth synth;
41 };
42
43
44 Mp3Decoder::Mp3Decoder(IO::Seekable &io):
45         priv(new Private),
46         in(io),
47         in_buf_size(16384),
48         in_buffer(new char[in_buf_size]),
49         read_pos(0)
50 {
51         mad_stream_init(&priv->stream);
52         mad_frame_init(&priv->frame);
53         mad_synth_init(&priv->synth);
54
55         try
56         {
57                 if(!fill_input() || !decode(false))
58                         throw runtime_error("no mp3 data");
59
60                 format = create_format(2, MAD_NCHANNELS(&priv->frame.header));
61                 freq = priv->frame.header.samplerate;
62         }
63         catch(...)
64         {
65                 delete[] in_buffer;
66                 throw;
67         }
68 }
69
70 Mp3Decoder::~Mp3Decoder()
71 {
72         delete[] in_buffer;
73         mad_synth_finish(&priv->synth);
74         mad_frame_finish(&priv->frame);
75         mad_stream_finish(&priv->stream);
76         delete priv;
77 }
78
79 bool Mp3Decoder::detect(const string &sig)
80 {
81         if(sig.size()>=2 && sig[0]=='\xFF' && (sig[1]&0xE0)==0xE0)
82                 return true;
83
84         static const char id3_sig[] = { 'I', 'D', '3' };
85         if(sig.size()<sizeof(id3_sig))
86                 return false;
87         return !sig.compare(0, sizeof(id3_sig), id3_sig, sizeof(id3_sig));
88 }
89
90 void Mp3Decoder::seek(unsigned pos)
91 {
92         unsigned unit = get_unit_size(format);
93         pos /= unit;
94
95         in.seek(0, IO::S_BEG);
96         mad_stream_buffer(&priv->stream, 0, 0);
97         fill_input();
98         if(!pos)
99         {
100                 priv->synth.pcm.length = 0;
101                 return;
102         }
103
104         while(decode(false))
105         {
106                 unsigned frame_len = 32*MAD_NSBSAMPLES(&priv->frame.header);
107                 if(frame_len>pos)
108                 {
109                         decode(true);
110                         read_pos = pos;
111                         break;
112                 }
113
114                 pos -= frame_len;
115         }
116 }
117
118 unsigned Mp3Decoder::read(char *buf, unsigned len)
119 {
120         unsigned nchan = get_n_channels(format);
121         mad_pcm &pcm = priv->synth.pcm;
122
123         unsigned pos = 0;
124         while(pos+2*nchan<=len)
125         {
126                 if(read_pos>=pcm.length && !decode(true))
127                         break;
128
129                 for(unsigned i=0; i<nchan; ++i)
130                 {
131                         Int16 sample = scale(pcm.samples[i][read_pos]);
132                         buf[pos++] = sample;
133                         buf[pos++] = sample>>8;
134                 }
135
136                 ++read_pos;
137         }
138
139         return pos;
140 }
141
142 bool Mp3Decoder::fill_input()
143 {
144         unsigned in_pos = 0;
145         if(priv->stream.next_frame && priv->stream.next_frame<priv->stream.bufend)
146         {
147                 copy(priv->stream.next_frame, priv->stream.bufend, in_buffer);
148                 in_pos = priv->stream.bufend-priv->stream.next_frame;
149         }
150
151         unsigned len = in.read(in_buffer+in_pos, in_buf_size-in_pos);
152         in_pos += len;
153
154         mad_stream_buffer(&priv->stream, reinterpret_cast<unsigned char *>(in_buffer), in_pos);
155         priv->stream.error = MAD_ERROR_NONE;
156
157         return len;
158 }
159
160 bool Mp3Decoder::try_decode(bool full)
161 {
162         if(full)
163                 return !mad_frame_decode(&priv->frame, &priv->stream);
164         else
165                 return !mad_header_decode(&priv->frame.header, &priv->stream);
166 }
167
168 bool Mp3Decoder::decode(bool full)
169 {
170         while(!try_decode(full))
171         {
172                 if(priv->stream.error==MAD_ERROR_BUFLEN)
173                 {
174                         if(!fill_input())
175                                 return false;
176                 }
177                 else if(!MAD_RECOVERABLE(priv->stream.error))
178                         throw mp3_error("mad_frame_decode", priv->stream.error);
179         }
180
181         if(full)
182         {
183                 read_pos = 0;
184                 mad_synth_frame(&priv->synth, &priv->frame);
185         }
186
187         return true;
188 }
189
190 } // namespace AL
191 } // namespace Msp