Mercurial > almixer_isolated
comparison Isolated/LGPL/mpg123.c @ 38:71b465ff0622
Added support files.
author | Eric Wing <ewing@anscamobile.com> |
---|---|
date | Thu, 28 Apr 2011 16:22:30 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
37:b346b6608eab | 38:71b465ff0622 |
---|---|
1 /* | |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2.1 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * libmpg123 decoder for SDL_sound. This is a very lightweight MP3 decoder, | |
22 * which is included with the SDL_sound source, so that it doesn't rely on | |
23 * unnecessary external libraries. | |
24 * | |
25 * libmpg123 is part of mpg123, and can be found in its original | |
26 * form at: http://www.mpg123.org/ | |
27 * | |
28 * Please see the file LICENSE.txt in the source's root directory. The included | |
29 * source code for libmpg123 falls under the LGPL, which is the same license | |
30 * as SDL_sound (so you can consider it a single work). | |
31 * | |
32 * This file written by Ryan C. Gordon. (icculus@icculus.org) | |
33 */ | |
34 | |
35 #if HAVE_CONFIG_H | |
36 # include <config.h> | |
37 #endif | |
38 | |
39 #ifdef SOUND_SUPPORTS_MPG123 | |
40 | |
41 #include <stdio.h> | |
42 #include <stdlib.h> | |
43 #include <string.h> | |
44 #include <assert.h> | |
45 | |
46 #include "mpg123.h" | |
47 | |
48 #ifdef ALMIXER_COMPILE_WITHOUT_SDL | |
49 #include "SoundDecoder.h" | |
50 #include "SoundDecoder_Internal.h" | |
51 #include "SimpleMutex.h" | |
52 #include "ALmixer_RWops.h" | |
53 #include <stdint.h> | |
54 typedef struct SimpleMutex SDL_mutex; | |
55 typedef struct ALmixer_RWops SDL_RWops; | |
56 #define SDL_CreateMutex SimpleMutex_CreateMutex | |
57 #define SDL_DestroyMutex SimpleMutex_DestroyMutex | |
58 #define SDL_LockMutex SimpleMutex_LockMutex | |
59 #define SDL_UnlockMutex SimpleMutex_UnlockMutex | |
60 typedef uint32_t Uint32; | |
61 #define SDL_RWseek ALmixer_RWseek | |
62 #define SDL_RWread ALmixer_RWread | |
63 | |
64 #else | |
65 #include "SDL_sound.h" | |
66 | |
67 #define __SDL_SOUND_INTERNAL__ | |
68 #include "SDL_sound_internal.h" | |
69 #endif | |
70 | |
71 #ifdef _MSC_VER | |
72 #define snprintf _snprintf | |
73 #endif | |
74 | |
75 | |
76 static int MPG123_init(void); | |
77 static void MPG123_quit(void); | |
78 static int MPG123_open(Sound_Sample *sample, const char *ext); | |
79 static void MPG123_close(Sound_Sample *sample); | |
80 static Uint32 MPG123_read(Sound_Sample *sample); | |
81 static int MPG123_rewind(Sound_Sample *sample); | |
82 static int MPG123_seek(Sound_Sample *sample, Uint32 ms); | |
83 | |
84 /* !!! FIXME: MPEG and MPG extensions? */ | |
85 static const char *extensions_mpg123[] = { "MP3", NULL }; | |
86 const Sound_DecoderFunctions __Sound_DecoderFunctions_MPG123 = | |
87 { | |
88 { | |
89 extensions_mpg123, | |
90 "MP3 decoding via internal libmpg123", | |
91 "Ryan C. Gordon <icculus@icculus.org>", | |
92 "http://www.icculus.org/SDL_sound/" | |
93 }, | |
94 | |
95 MPG123_init, /* init() method */ | |
96 MPG123_quit, /* quit() method */ | |
97 MPG123_open, /* open() method */ | |
98 MPG123_close, /* close() method */ | |
99 MPG123_read, /* read() method */ | |
100 MPG123_rewind, /* rewind() method */ | |
101 MPG123_seek /* seek() method */ | |
102 }; | |
103 | |
104 | |
105 /* this is what we store in our internal->decoder_private field... */ | |
106 typedef mpg123_handle mpg123_t; | |
107 | |
108 static SDL_mutex *mpg123_mutex = NULL; | |
109 static int mpg123_rwops_count = 0; | |
110 static SDL_RWops **mpg123_rwops = NULL; | |
111 | |
112 static void print_decoders(const char *kind, char **decoders) | |
113 { | |
114 SNDDBG(("%s:", kind)); | |
115 if (*decoders == NULL) | |
116 { | |
117 SNDDBG((" [none]")); | |
118 } | |
119 else | |
120 { | |
121 do | |
122 { | |
123 SNDDBG((" %s", *decoders)); | |
124 } while (*(++decoders)); | |
125 } /* else */ | |
126 SNDDBG(("\n")); | |
127 } /* print_decoders */ | |
128 | |
129 | |
130 static int MPG123_init(void) | |
131 { | |
132 int retval = 0; | |
133 assert(mpg123_mutex == NULL); | |
134 if (mpg123_init() == MPG123_OK) | |
135 { | |
136 char **supported = mpg123_supported_decoders(); | |
137 print_decoders("ALL MPG123 DECODERS", mpg123_decoders()); | |
138 print_decoders("SUPPORTED MPG123 DECODERS", mpg123_supported_decoders()); | |
139 if ((supported != NULL) && (*supported != NULL)) | |
140 { | |
141 mpg123_mutex = SDL_CreateMutex(); | |
142 if (mpg123_mutex != NULL) | |
143 retval = 1; /* at least one decoder available. */ | |
144 } /* if */ | |
145 } /* if */ | |
146 | |
147 return retval; | |
148 } /* MPG123_init */ | |
149 | |
150 | |
151 static void MPG123_quit(void) | |
152 { | |
153 mpg123_exit(); | |
154 SDL_DestroyMutex(mpg123_mutex); | |
155 mpg123_mutex = NULL; | |
156 free(mpg123_rwops); | |
157 mpg123_rwops = NULL; | |
158 mpg123_rwops_count = 0; | |
159 } /* MPG123_quit */ | |
160 | |
161 | |
162 /* bridge rwops reading to libmpg123 hooks. */ | |
163 static ssize_t rwread(int fd, void *buf, size_t len) | |
164 { | |
165 SDL_RWops *rw = NULL; | |
166 SDL_LockMutex(mpg123_mutex); | |
167 rw = mpg123_rwops[fd]; | |
168 SDL_UnlockMutex(mpg123_mutex); | |
169 return (ssize_t) SDL_RWread(rw, buf, 1, len); | |
170 } /* rwread */ | |
171 | |
172 | |
173 /* bridge rwops seeking to libmpg123 hooks. */ | |
174 static off_t rwseek(int fd, off_t pos, int whence) | |
175 { | |
176 SDL_RWops *rw = NULL; | |
177 SDL_LockMutex(mpg123_mutex); | |
178 rw = mpg123_rwops[fd]; | |
179 SDL_UnlockMutex(mpg123_mutex); | |
180 return (off_t) SDL_RWseek(rw, pos, whence); | |
181 } /* rwseek */ | |
182 | |
183 | |
184 static const char *set_error(mpg123_handle *mp, const int err) | |
185 { | |
186 char buffer[128]; | |
187 const char *str = NULL; | |
188 if ((err == MPG123_ERR) && (mp != NULL)) | |
189 str = mpg123_strerror(mp); | |
190 else | |
191 str = mpg123_plain_strerror(err); | |
192 | |
193 snprintf(buffer, sizeof (buffer), "MPG123: %s", str); | |
194 __Sound_SetError(buffer); | |
195 | |
196 return(NULL); /* this is for BAIL_MACRO to not try to reset the string. */ | |
197 } /* set_error */ | |
198 | |
199 | |
200 /* Make sure we are only given decoded data in a format we can handle. */ | |
201 static int set_formats(mpg123_handle *mp) | |
202 { | |
203 int rc = 0; | |
204 const long *rates = NULL; | |
205 size_t ratecount = 0; | |
206 const int channels = MPG123_STEREO | MPG123_MONO; | |
207 const int encodings = /* !!! FIXME: SDL 1.3 can do sint32 and float32. | |
208 MPG123_ENC_SIGNED_32 | MPG123_ENC_FLOAT_32 | */ | |
209 MPG123_ENC_SIGNED_8 | MPG123_ENC_UNSIGNED_8 | | |
210 MPG123_ENC_SIGNED_16 | MPG123_ENC_UNSIGNED_16; | |
211 | |
212 mpg123_rates(&rates, &ratecount); | |
213 | |
214 rc = mpg123_format_none(mp); | |
215 while ((ratecount--) && (rc == MPG123_OK)) | |
216 rc = mpg123_format(mp, *(rates++), channels, encodings); | |
217 | |
218 return(rc); | |
219 } /* set_formats */ | |
220 | |
221 | |
222 static int MPG123_open(Sound_Sample *sample, const char *ext) | |
223 { | |
224 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
225 mpg123_handle *mp = NULL; | |
226 long rate = 0; | |
227 int channels = 0; | |
228 int fmt = 0; | |
229 int rc = 0; | |
230 off_t len = 0; | |
231 int seekable = 0; | |
232 void *ptr = NULL; | |
233 int rwops = 0; | |
234 | |
235 /* !!! FIXME: so much tapdance because we need a pointer, not an int. */ | |
236 SDL_LockMutex(mpg123_mutex); | |
237 for (rwops = 0; rwops < mpg123_rwops_count; rwops++) | |
238 { | |
239 if (mpg123_rwops[rwops] == NULL) | |
240 break; | |
241 } /* for */ | |
242 if (rwops < mpg123_rwops_count) | |
243 ptr = mpg123_rwops; | |
244 else | |
245 { | |
246 mpg123_rwops_count++; | |
247 ptr = realloc(mpg123_rwops, sizeof (SDL_RWops *) * mpg123_rwops_count); | |
248 if (ptr != NULL) | |
249 mpg123_rwops = (SDL_RWops **) ptr; | |
250 } /* else */ | |
251 if (ptr != NULL) | |
252 mpg123_rwops[rwops] = internal->rw; | |
253 SDL_UnlockMutex(mpg123_mutex); | |
254 BAIL_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, 0); | |
255 | |
256 if ((mp = mpg123_new(NULL, &rc)) == NULL) | |
257 goto mpg123_open_failed; | |
258 else if ((rc = set_formats(mp)) != MPG123_OK) | |
259 goto mpg123_open_failed; | |
260 else if ((rc = mpg123_replace_reader(mp, rwread, rwseek)) != MPG123_OK) | |
261 goto mpg123_open_failed; | |
262 else if ((rc = mpg123_open_fd(mp, rwops)) != MPG123_OK) | |
263 goto mpg123_open_failed; | |
264 else if ((rc = mpg123_scan(mp)) != MPG123_OK) | |
265 goto mpg123_open_failed; /* !!! FIXME: this may be wrong. */ | |
266 else if ((rc = mpg123_getformat(mp, &rate, &channels, &fmt)) != MPG123_OK) | |
267 goto mpg123_open_failed; | |
268 | |
269 if (mpg123_seek(mp, 0, SEEK_END) >= 0) /* can seek? */ | |
270 { | |
271 len = mpg123_tell(mp); | |
272 if ((rc = (int) mpg123_seek(mp, 0, SEEK_SET)) < 0) | |
273 goto mpg123_open_failed; | |
274 seekable = 1; | |
275 } /* if */ | |
276 | |
277 internal->decoder_private = mp; | |
278 sample->actual.rate = rate; | |
279 sample->actual.channels = channels; | |
280 | |
281 rc = MPG123_BAD_OUTFORMAT; /* in case this fails... */ | |
282 if (fmt == MPG123_ENC_SIGNED_8) | |
283 sample->actual.format = AUDIO_S8; | |
284 else if (fmt == MPG123_ENC_UNSIGNED_8) | |
285 sample->actual.format = AUDIO_U8; | |
286 else if (fmt == MPG123_ENC_SIGNED_16) | |
287 sample->actual.format = AUDIO_S16SYS; | |
288 else if (fmt == MPG123_ENC_UNSIGNED_16) | |
289 sample->actual.format = AUDIO_U16SYS; | |
290 /* !!! FIXME: SDL 1.3 can do sint32 and float32 ... | |
291 else if (fmt == MPG123_ENC_SIGNED_32) | |
292 sample->actual.format = AUDIO_S32SYS; | |
293 else if (fmt == MPG123_ENC_FLOAT_32) | |
294 sample->actual.format = AUDIO_F32SYS; | |
295 */ | |
296 else | |
297 goto mpg123_open_failed; | |
298 | |
299 SNDDBG(("MPG123: Accepting data stream.\n")); | |
300 | |
301 sample->flags = SOUND_SAMPLEFLAG_NONE; | |
302 internal->total_time = -1; | |
303 if (seekable) | |
304 { | |
305 sample->flags |= SOUND_SAMPLEFLAG_CANSEEK; | |
306 internal->total_time = ((len / rate) * 1000) + | |
307 (((len % rate) * 1000) / rate); | |
308 } /* if */ | |
309 | |
310 return(1); /* we'll handle this data. */ | |
311 | |
312 mpg123_open_failed: | |
313 SDL_LockMutex(mpg123_mutex); | |
314 mpg123_rwops[rwops] = NULL; | |
315 if (rwops == mpg123_rwops_count) | |
316 mpg123_rwops_count--; | |
317 SDL_UnlockMutex(mpg123_mutex); | |
318 set_error(mp, rc); | |
319 mpg123_delete(mp); /* NULL is safe. */ | |
320 return(0); | |
321 } /* MPG123_open */ | |
322 | |
323 | |
324 static void MPG123_close(Sound_Sample *sample) | |
325 { | |
326 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
327 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
328 int i; | |
329 | |
330 SDL_LockMutex(mpg123_mutex); | |
331 for (i = 0; i < mpg123_rwops_count; i++) | |
332 { | |
333 if (mpg123_rwops[i] == internal->rw) | |
334 mpg123_rwops[i] = NULL; | |
335 } /* for */ | |
336 | |
337 for (i = mpg123_rwops_count-1; i >= 0; i--) | |
338 { | |
339 if (mpg123_rwops[i] != NULL) | |
340 break; | |
341 } /* for */ | |
342 mpg123_rwops_count = i + 1; | |
343 SDL_UnlockMutex(mpg123_mutex); | |
344 | |
345 mpg123_close(mp); /* don't need this at the moment, but it's safe. */ | |
346 mpg123_delete(mp); | |
347 } /* MPG123_close */ | |
348 | |
349 | |
350 static Uint32 MPG123_read(Sound_Sample *sample) | |
351 { | |
352 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
353 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
354 size_t bw = 0; | |
355 const int rc = mpg123_read(mp, (unsigned char *) internal->buffer, | |
356 internal->buffer_size, &bw); | |
357 if (rc == MPG123_DONE) | |
358 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
359 else if (rc != MPG123_OK) | |
360 { | |
361 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
362 set_error(mp, rc); | |
363 } /* else if */ | |
364 | |
365 return((Uint32) bw); | |
366 } /* MPG123_read */ | |
367 | |
368 | |
369 static int MPG123_rewind(Sound_Sample *sample) | |
370 { | |
371 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
372 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
373 const int rc = (int) mpg123_seek(mp, 0, SEEK_SET); | |
374 BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0); | |
375 return(1); | |
376 } /* MPG123_rewind */ | |
377 | |
378 | |
379 static int MPG123_seek(Sound_Sample *sample, Uint32 ms) | |
380 { | |
381 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
382 mpg123_t *mp = ((mpg123_t *) internal->decoder_private); | |
383 const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f; | |
384 const off_t frame_offset = (off_t) (frames_per_ms * ((float) ms)); | |
385 const int rc = (int) mpg123_seek(mp, frame_offset , SEEK_SET); | |
386 BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0); | |
387 return(1); | |
388 } /* MPG123_seek */ | |
389 | |
390 #endif /* SOUND_SUPPORTS_MPG123 */ | |
391 | |
392 /* end of mpg123.c ... */ | |
393 |