/
music_mpg123.c
432 lines (371 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
22
/* This file supports playing MP3 files with mpg123 */
23
24
25
#ifdef MUSIC_MP3_MPG123
26
27
#include <stdio.h> // For SEEK_SET
28
#include "SDL_assert.h"
29
30
#include "SDL_loadso.h"
31
32
33
34
#include "music_mpg123.h"
#include <mpg123.h>
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
typedef struct {
int loaded;
void *handle;
int (*mpg123_close)(mpg123_handle *mh);
void (*mpg123_delete)(mpg123_handle *mh);
void (*mpg123_exit)(void);
int (*mpg123_format)( mpg123_handle *mh, long rate, int channels, int encodings );
int (*mpg123_format_none)(mpg123_handle *mh);
int (*mpg123_getformat)( mpg123_handle *mh, long *rate, int *channels, int *encoding );
int (*mpg123_init)(void);
mpg123_handle *(*mpg123_new)(const char* decoder, int *error);
int (*mpg123_open_handle)(mpg123_handle *mh, void *iohandle);
const char* (*mpg123_plain_strerror)(int errcode);
50
void (*mpg123_rates)(const long **list, size_t *number);
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
int (*mpg123_read)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done );
int (*mpg123_replace_reader_handle)( mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) );
off_t (*mpg123_seek)( mpg123_handle *mh, off_t sampleoff, int whence );
const char* (*mpg123_strerror)(mpg123_handle *mh);
} mpg123_loader;
static mpg123_loader mpg123 = {
0, NULL
};
#ifdef MPG123_DYNAMIC
#define FUNCTION_LOADER(FUNC, SIG) \
mpg123.FUNC = (SIG) SDL_LoadFunction(mpg123.handle, #FUNC); \
if (mpg123.FUNC == NULL) { SDL_UnloadObject(mpg123.handle); return -1; }
#else
#define FUNCTION_LOADER(FUNC, SIG) \
mpg123.FUNC = FUNC;
#endif
70
static int MPG123_Load(void)
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{
if (mpg123.loaded == 0) {
#ifdef MPG123_DYNAMIC
mpg123.handle = SDL_LoadObject(MPG123_DYNAMIC);
if (mpg123.handle == NULL) {
return -1;
}
#elif defined(__MACOSX__)
extern int mpg123_init(void) __attribute__((weak_import));
if (mpg123_init == NULL)
{
/* Missing weakly linked framework */
Mix_SetError("Missing mpg123.framework");
return -1;
}
#endif
FUNCTION_LOADER(mpg123_close, int (*)(mpg123_handle *mh))
FUNCTION_LOADER(mpg123_delete, void (*)(mpg123_handle *mh))
FUNCTION_LOADER(mpg123_exit, void (*)(void))
FUNCTION_LOADER(mpg123_format, int (*)( mpg123_handle *mh, long rate, int channels, int encodings ))
FUNCTION_LOADER(mpg123_format_none, int (*)(mpg123_handle *mh))
FUNCTION_LOADER(mpg123_getformat, int (*)( mpg123_handle *mh, long *rate, int *channels, int *encoding ))
FUNCTION_LOADER(mpg123_init, int (*)(void))
FUNCTION_LOADER(mpg123_new, mpg123_handle *(*)(const char* decoder, int *error))
FUNCTION_LOADER(mpg123_open_handle, int (*)(mpg123_handle *mh, void *iohandle))
FUNCTION_LOADER(mpg123_plain_strerror, const char* (*)(int errcode))
98
FUNCTION_LOADER(mpg123_rates, void (*)(const long **list, size_t *number));
99
100
101
102
103
104
105
106
107
108
FUNCTION_LOADER(mpg123_read, int (*)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done ))
FUNCTION_LOADER(mpg123_replace_reader_handle, int (*)( mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) ))
FUNCTION_LOADER(mpg123_seek, off_t (*)( mpg123_handle *mh, off_t sampleoff, int whence ))
FUNCTION_LOADER(mpg123_strerror, const char* (*)(mpg123_handle *mh))
}
++mpg123.loaded;
return 0;
}
109
static void MPG123_Unload(void)
110
111
112
113
114
115
116
117
118
119
120
121
122
{
if (mpg123.loaded == 0) {
return;
}
if (mpg123.loaded == 1) {
#ifdef MPG123_DYNAMIC
SDL_UnloadObject(mpg123.handle);
#endif
}
--mpg123.loaded;
}
123
124
typedef struct
{
125
int play_count;
126
127
128
129
130
SDL_RWops* src;
int freesrc;
int volume;
mpg123_handle* handle;
131
132
133
134
SDL_AudioStream *stream;
unsigned char *buffer;
size_t buffer_size;
} MPG123_Music;
135
136
137
138
static int MPG123_Seek(void *context, double secs);
static void MPG123_Delete(void *context);
139
140
static int mpg123_format_to_sdl(int fmt)
141
142
143
{
switch (fmt)
{
144
145
146
147
148
149
150
case MPG123_ENC_SIGNED_8: return AUDIO_S8;
case MPG123_ENC_UNSIGNED_8: return AUDIO_U8;
case MPG123_ENC_SIGNED_16: return AUDIO_S16SYS;
case MPG123_ENC_UNSIGNED_16: return AUDIO_U16SYS;
case MPG123_ENC_SIGNED_32: return AUDIO_S32SYS;
case MPG123_ENC_FLOAT_32: return AUDIO_F32SYS;
default: return -1;
151
152
153
}
}
154
155
/*
static const char *mpg123_format_str(int fmt)
156
157
158
159
160
161
162
163
164
{
switch (fmt)
{
#define f(x) case x: return #x;
f(MPG123_ENC_UNSIGNED_8)
f(MPG123_ENC_UNSIGNED_16)
f(MPG123_ENC_SIGNED_8)
f(MPG123_ENC_SIGNED_16)
f(MPG123_ENC_SIGNED_32)
165
f(MPG123_ENC_FLOAT_32)
166
167
168
169
#undef f
}
return "unknown";
}
170
*/
171
172
static char const* mpg_err(mpg123_handle* mpg, int result)
173
174
175
{
char const* err = "unknown error";
176
if (mpg && result == MPG123_ERR) {
177
err = mpg123.mpg123_strerror(mpg);
178
} else {
179
err = mpg123.mpg123_plain_strerror(result);
180
181
182
183
184
}
return err;
}
/* we're gonna override mpg123's I/O with these wrappers for RWops */
185
186
static ssize_t rwops_read(void* p, void* dst, size_t n)
{
187
188
189
return (ssize_t)SDL_RWread((SDL_RWops*)p, dst, 1, n);
}
190
191
static off_t rwops_seek(void* p, off_t offset, int whence)
{
192
193
194
return (off_t)SDL_RWseek((SDL_RWops*)p, (Sint64)offset, whence);
}
195
196
static void rwops_cleanup(void* p)
{
197
198
199
200
(void)p;
/* do nothing, we will free the file later */
}
201
202
203
static int MPG123_Open(const SDL_AudioSpec *spec)
{
204
if (mpg123.mpg123_init() != MPG123_OK) {
205
206
207
208
209
210
211
Mix_SetError("mpg123_init() failed");
return -1;
}
return 0;
}
static void *MPG123_CreateFromRW(SDL_RWops *src, int freesrc)
212
{
213
MPG123_Music *music;
214
int result;
215
216
const long *rates;
size_t i, num_rates;
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
music = (MPG123_Music*)SDL_calloc(1, sizeof(*music));
if (!music) {
return NULL;
}
music->src = src;
music->volume = MIX_MAX_VOLUME;
/* Just assume 16-bit 2 channel audio for now */
music->buffer_size = music_spec.samples * sizeof(Sint16) * 2;
music->buffer = (unsigned char *)SDL_malloc(music->buffer_size);
if (!music->buffer) {
MPG123_Delete(music);
SDL_OutOfMemory();
return NULL;
232
233
}
234
music->handle = mpg123.mpg123_new(0, &result);
235
if (result != MPG123_OK) {
236
237
238
MPG123_Delete(music);
Mix_SetError("mpg123_new failed");
return NULL;
239
240
}
241
result = mpg123.mpg123_replace_reader_handle(
242
music->handle,
243
rwops_read, rwops_seek, rwops_cleanup
244
);
245
if (result != MPG123_OK) {
246
247
248
MPG123_Delete(music);
Mix_SetError("mpg123_replace_reader_handle: %s", mpg_err(music->handle, result));
return NULL;
249
250
}
251
result = mpg123.mpg123_format_none(music->handle);
252
if (result != MPG123_OK) {
253
254
255
MPG123_Delete(music);
Mix_SetError("mpg123_format_none: %s", mpg_err(music->handle, result));
return NULL;
256
257
}
258
259
260
261
262
263
264
265
266
267
268
mpg123.mpg123_rates(&rates, &num_rates);
for (i = 0; i < num_rates; ++i) {
const int channels = (MPG123_MONO|MPG123_STEREO);
const int formats = (MPG123_ENC_SIGNED_8 |
MPG123_ENC_UNSIGNED_8 |
MPG123_ENC_SIGNED_16 |
MPG123_ENC_UNSIGNED_16 |
MPG123_ENC_SIGNED_32 |
MPG123_ENC_FLOAT_32);
mpg123.mpg123_format(music->handle, rates[i], channels, formats);
269
270
}
271
result = mpg123.mpg123_open_handle(music->handle, music->src);
272
if (result != MPG123_OK) {
273
274
275
MPG123_Delete(music);
Mix_SetError("mpg123_open_handle: %s", mpg_err(music->handle, result));
return NULL;
276
277
}
278
279
music->freesrc = freesrc;
return music;
280
281
}
282
static void MPG123_SetVolume(void *context, int volume)
283
{
284
285
MPG123_Music *music = (MPG123_Music *)context;
music->volume = volume;
286
287
}
288
static int MPG123_Play(void *context, int play_count)
289
{
290
291
292
MPG123_Music *music = (MPG123_Music *)context;
music->play_count = play_count;
return MPG123_Seek(music, 0.0);
293
294
}
295
296
/* read some mp3 stream data and convert it for output */
static int MPG123_GetSome(void *context, void *data, int bytes, SDL_bool *done)
297
{
298
299
300
MPG123_Music *music = (MPG123_Music *)context;
int filled, result;
size_t amount;
301
long rate;
302
int channels, encoding, format;
303
304
305
306
307
308
if (music->stream) {
filled = SDL_AudioStreamGet(music->stream, data, bytes);
if (filled != 0) {
return filled;
}
309
310
}
311
312
313
if (!music->play_count) {
/* All done */
*done = SDL_TRUE;
314
315
316
return 0;
}
317
318
319
320
321
result = mpg123.mpg123_read(music->handle, music->buffer, music->buffer_size, &amount);
switch (result) {
case MPG123_OK:
if (SDL_AudioStreamPut(music->stream, music->buffer, (int)amount) < 0) {
return -1;
322
}
323
break;
324
325
326
327
328
329
case MPG123_NEW_FORMAT:
result = mpg123.mpg123_getformat(music->handle, &rate, &channels, &encoding);
if (result != MPG123_OK) {
Mix_SetError("mpg123_getformat: %s", mpg_err(music->handle, result));
return -1;
330
}
331
/*printf("MPG123 format: %s, channels = %d, rate = %ld\n", mpg123_format_str(encoding), channels, rate);*/
332
333
334
format = mpg123_format_to_sdl(encoding);
SDL_assert(format != -1);
335
336
337
338
339
music->stream = SDL_NewAudioStream(format, channels, (int)rate,
music_spec.format, music_spec.channels, music_spec.freq);
if (!music->stream) {
return -1;
340
}
341
342
343
344
345
346
347
348
349
350
351
352
353
354
break;
case MPG123_DONE:
if (music->play_count == 1) {
music->play_count = 0;
SDL_AudioStreamFlush(music->stream);
} else {
int play_count = -1;
if (music->play_count > 0) {
play_count = (music->play_count - 1);
}
if (MPG123_Play(music, play_count) < 0) {
return -1;
}
355
}
356
357
358
359
break;
default:
Mix_SetError("mpg123_read: %s", mpg_err(music->handle, result));
return -1;
360
}
361
362
363
364
365
366
return 0;
}
static int MPG123_GetAudio(void *context, void *data, int bytes)
{
MPG123_Music *music = (MPG123_Music *)context;
return music_pcm_getaudio(context, data, bytes, music->volume, MPG123_GetSome);
367
368
}
369
static int MPG123_Seek(void *context, double secs)
370
{
371
372
MPG123_Music *music = (MPG123_Music *)context;
off_t offset = (off_t)(music_spec.freq * secs);
373
374
375
if ((offset = mpg123.mpg123_seek(music->handle, offset, SEEK_SET)) < 0) {
return Mix_SetError("mpg123_seek: %s", mpg_err(music->handle, (int)-offset));
376
}
377
return 0;
378
379
}
380
381
static void MPG123_Delete(void *context)
{
382
MPG123_Music *music = (MPG123_Music *)context;
383
384
385
386
if (music->handle) {
mpg123.mpg123_close(music->handle);
mpg123.mpg123_delete(music->handle);
387
}
388
389
if (music->stream) {
SDL_FreeAudioStream(music->stream);
390
}
391
392
393
394
395
396
397
if (music->buffer) {
SDL_free(music->buffer);
}
if (music->freesrc) {
SDL_RWclose(music->src);
}
SDL_free(music);
398
399
400
401
}
static void MPG123_Close(void)
{
402
mpg123.mpg123_exit();
403
404
405
406
407
408
409
410
411
412
}
Mix_MusicInterface Mix_MusicInterface_MPG123 =
{
"MPG123",
MIX_MUSIC_MPG123,
MUS_MP3,
SDL_FALSE,
SDL_FALSE,
413
MPG123_Load,
414
415
416
417
418
MPG123_Open,
MPG123_CreateFromRW,
NULL, /* CreateFromFile */
MPG123_SetVolume,
MPG123_Play,
419
NULL, /* IsPlaying */
420
421
422
423
MPG123_GetAudio,
MPG123_Seek,
NULL, /* Pause */
NULL, /* Resume */
424
NULL, /* Stop */
425
426
MPG123_Delete,
MPG123_Close,
427
MPG123_Unload
428
429
430
431
432
};
#endif /* MUSIC_MP3_MPG123 */
/* vi: set ts=4 sw=4 expandtab: */