2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
37 static void *mp123_handle;
38 #define MAKE_FUNC(x) static typeof(x)* p##x
39 MAKE_FUNC(mpg123_read);
40 MAKE_FUNC(mpg123_init);
41 MAKE_FUNC(mpg123_open_feed);
42 MAKE_FUNC(mpg123_new);
43 MAKE_FUNC(mpg123_delete);
44 MAKE_FUNC(mpg123_feed);
45 MAKE_FUNC(mpg123_exit);
46 MAKE_FUNC(mpg123_getformat);
47 MAKE_FUNC(mpg123_format_none);
48 MAKE_FUNC(mpg123_decode);
49 MAKE_FUNC(mpg123_format);
52 #define mpg123_read pmpg123_read
53 #define mpg123_init pmpg123_init
54 #define mpg123_open_feed pmpg123_open_feed
55 #define mpg123_new pmpg123_new
56 #define mpg123_delete pmpg123_delete
57 #define mpg123_feed pmpg123_feed
58 #define mpg123_exit pmpg123_exit
59 #define mpg123_getformat pmpg123_getformat
60 #define mpg123_format_none pmpg123_format_none
61 #define mpg123_decode pmpg123_decode
62 #define mpg123_format pmpg123_format
64 #define mp123_handle 1
68 struct mp3Stream : public alureStream {
70 mpg123_handle *mp3File;
74 std::ios::pos_type dataStart;
75 std::ios::pos_type dataEnd;
82 #define MPG123_LIB "libmpg123.dll"
83 #elif defined(__APPLE__)
84 #define MPG123_LIB "libmpg123.0.dylib"
86 #define MPG123_LIB "libmpg123.so.0"
88 mp123_handle = OpenLib(MPG123_LIB);
89 if(!mp123_handle) return;
91 LOAD_FUNC(mp123_handle, mpg123_read);
92 LOAD_FUNC(mp123_handle, mpg123_init);
93 LOAD_FUNC(mp123_handle, mpg123_open_feed);
94 LOAD_FUNC(mp123_handle, mpg123_new);
95 LOAD_FUNC(mp123_handle, mpg123_delete);
96 LOAD_FUNC(mp123_handle, mpg123_feed);
97 LOAD_FUNC(mp123_handle, mpg123_exit);
98 LOAD_FUNC(mp123_handle, mpg123_getformat);
99 LOAD_FUNC(mp123_handle, mpg123_format_none);
100 LOAD_FUNC(mp123_handle, mpg123_decode);
101 LOAD_FUNC(mp123_handle, mpg123_format);
109 CloseLib(mp123_handle);
114 static void Init() { }
115 static void Deinit() { }
118 virtual bool IsValid()
119 { return mp3File != NULL; }
121 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
124 *frequency = samplerate;
125 *blockalign = channels*2;
129 virtual ALuint GetData(ALubyte *data, ALuint bytes)
138 int ret = mpg123_read(mp3File, data, bytes, &got);
144 if(ret == MPG123_NEW_FORMAT)
146 mpg123_delete(mp3File);
150 if(ret == MPG123_NEED_MORE)
152 unsigned char data[4096];
153 ALint insize = std::min<ALint>(sizeof(data),
154 (dataEnd-fstream->tellg()));
157 fstream->read((char*)data, insize);
158 insize = fstream->gcount();
160 if(insize > 0 && mpg123_feed(mp3File, data, insize) == MPG123_OK)
169 virtual bool Rewind()
172 std::ios::pos_type oldpos = fstream->tellg();
173 fstream->seekg(dataStart);
175 mpg123_handle *newFile = mpg123_new(NULL, NULL);
176 if(mpg123_open_feed(newFile) == MPG123_OK)
178 unsigned char data[4096];
183 ALuint amt, total = 0;
186 amt = std::min<ALint>(sizeof(data),
187 (dataEnd-fstream->tellg()));
188 fstream->read((char*)data, amt);
189 amt = fstream->gcount();
192 ret = mpg123_decode(newFile, data, amt, NULL, 0, NULL);
193 } while(ret == MPG123_NEED_MORE && total < 64*1024);
195 if(ret == MPG123_NEW_FORMAT &&
196 mpg123_getformat(newFile, &newrate, &newchans, &enc) == MPG123_OK)
198 if(mpg123_format_none(newFile) == MPG123_OK &&
199 mpg123_format(newFile, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
203 mpg123_delete(mp3File);
208 mpg123_delete(newFile);
211 fstream->seekg(oldpos);
212 SetError("Restart failed");
216 mp3Stream(std::istream *_fstream)
217 : alureStream(_fstream), mp3File(NULL), format(AL_NONE),
218 dataStart(0), dataEnd(0)
220 if(!mp123_handle) return;
225 mp3File = mpg123_new(NULL, NULL);
226 if(mpg123_open_feed(mp3File) == MPG123_OK)
228 unsigned char data[4096];
231 ALuint amt, total = 0;
234 amt = std::min<ALint>(sizeof(data),
235 (dataEnd-fstream->tellg()));
236 fstream->read((char*)data, amt);
237 amt = fstream->gcount();
240 ret = mpg123_decode(mp3File, data, amt, NULL, 0, NULL);
241 } while(ret == MPG123_NEED_MORE && total < 64*1024);
243 if(ret == MPG123_NEW_FORMAT &&
244 mpg123_getformat(mp3File, &samplerate, &channels, &enc) == MPG123_OK)
246 format = GetSampleFormat(channels, 16, false);
247 if(mpg123_format_none(mp3File) == MPG123_OK &&
248 mpg123_format(mp3File, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
255 mpg123_delete(mp3File);
262 mpg123_delete(mp3File);
272 if(!fstream->read(reinterpret_cast<char*>(buffer), 12))
275 if(memcmp(buffer, "RIFF", 4) != 0 || memcmp(buffer+8, "WAVE", 4) != 0)
279 // Check for an ID3v2 tag, and skip it
280 if(memcmp(buffer, "ID3", 3) == 0 &&
281 buffer[3] <= 4 && buffer[4] != 0xff &&
282 (buffer[5]&0x0f) == 0 && (buffer[6]&0x80) == 0 &&
283 (buffer[7]&0x80) == 0 && (buffer[8]&0x80) == 0 &&
284 (buffer[9]&0x80) == 0)
286 dataStart = (buffer[6]<<21) | (buffer[7]<<14) |
287 (buffer[8]<< 7) | (buffer[9] );
288 dataStart += ((buffer[5]&0x10) ? 20 : 10);
291 if(fstream->seekg(0, std::ios_base::end))
293 dataEnd = fstream->tellg();
294 fstream->seekg(dataStart);
296 return fstream->good();
303 if(!fstream->read(tag, 4))
306 /* read chunk length */
307 length = read_le32(fstream);
309 if(memcmp(tag, "fmt ", 4) == 0 && length >= 16)
311 /* Data type (should be 0x0050 or 0x0055 for MP3 data) */
312 type = read_le16(fstream);
313 if(type != 0x0050 && type != 0x0055)
316 /* Ignore the rest of the chunk. Everything we need is in the
319 else if(memcmp(tag, "data", 4) == 0)
321 if(type == 0x0050 || type == 0x0055)
323 dataStart = fstream->tellg();
326 return fstream->good();
330 fstream->seekg(length, std::ios_base::cur);
336 // Priority = -2, because mp3 loading can find false-positives, and interferes
338 static DecoderDecl<mp3Stream,-2> mp3Stream_decoder;
339 Decoder &alure_init_mpg123(void)
340 { return mp3Stream_decoder; }