/
music_mpg123.c
431 lines (371 loc) · 12.6 KB
1
2
/*
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
{
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))
97
FUNCTION_LOADER(mpg123_rates, void (*)(const long **list, size_t *number));
98
99
100
101
102
103
104
105
106
107
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;
}
108
static void MPG123_Unload(void)
109
110
111
112
113
114
115
116
117
118
119
120
121
{
if (mpg123.loaded == 0) {
return;
}
if (mpg123.loaded == 1) {
#ifdef MPG123_DYNAMIC
SDL_UnloadObject(mpg123.handle);
#endif
}
--mpg123.loaded;
}
122
123
typedef struct
{
124
int play_count;
125
126
127
128
129
SDL_RWops* src;
int freesrc;
int volume;
mpg123_handle* handle;
130
131
132
133
SDL_AudioStream *stream;
unsigned char *buffer;
size_t buffer_size;
} MPG123_Music;
134
135
136
137
static int MPG123_Seek(void *context, double secs);
static void MPG123_Delete(void *context);
138
139
static int mpg123_format_to_sdl(int fmt)
140
141
142
{
switch (fmt)
{
143
144
145
146
147
148
149
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;
150
151
152
}
}
153
154
/*
static const char *mpg123_format_str(int fmt)
155
156
157
158
159
160
161
162
163
{
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)
164
f(MPG123_ENC_FLOAT_32)
165
166
167
168
#undef f
}
return "unknown";
}
169
*/
170
171
static char const* mpg_err(mpg123_handle* mpg, int result)
172
173
174
{
char const* err = "unknown error";
175
if (mpg && result == MPG123_ERR) {
176
err = mpg123.mpg123_strerror(mpg);
177
} else {
178
err = mpg123.mpg123_plain_strerror(result);
179
180
181
182
183
}
return err;
}
/* we're gonna override mpg123's I/O with these wrappers for RWops */
184
185
static ssize_t rwops_read(void* p, void* dst, size_t n)
{
186
187
188
return (ssize_t)SDL_RWread((SDL_RWops*)p, dst, 1, n);
}
189
190
static off_t rwops_seek(void* p, off_t offset, int whence)
{
191
192
193
return (off_t)SDL_RWseek((SDL_RWops*)p, (Sint64)offset, whence);
}
194
195
static void rwops_cleanup(void* p)
{
196
197
198
199
(void)p;
/* do nothing, we will free the file later */
}
200
201
202
static int MPG123_Open(const SDL_AudioSpec *spec)
{
203
if (mpg123.mpg123_init() != MPG123_OK) {
204
205
206
207
208
209
210
Mix_SetError("mpg123_init() failed");
return -1;
}
return 0;
}
static void *MPG123_CreateFromRW(SDL_RWops *src, int freesrc)
211
{
212
MPG123_Music *music;
213
int result;
214
215
const long *rates;
size_t i, num_rates;
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
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;
231
232
}
233
music->handle = mpg123.mpg123_new(0, &result);
234
if (result != MPG123_OK) {
235
236
237
MPG123_Delete(music);
Mix_SetError("mpg123_new failed");
return NULL;
238
239
}
240
result = mpg123.mpg123_replace_reader_handle(
241
music->handle,
242
rwops_read, rwops_seek, rwops_cleanup
243
);
244
if (result != MPG123_OK) {
245
246
247
MPG123_Delete(music);
Mix_SetError("mpg123_replace_reader_handle: %s", mpg_err(music->handle, result));
return NULL;
248
249
}
250
result = mpg123.mpg123_format_none(music->handle);
251
if (result != MPG123_OK) {
252
253
254
MPG123_Delete(music);
Mix_SetError("mpg123_format_none: %s", mpg_err(music->handle, result));
return NULL;
255
256
}
257
258
259
260
261
262
263
264
265
266
267
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);
268
269
}
270
result = mpg123.mpg123_open_handle(music->handle, music->src);
271
if (result != MPG123_OK) {
272
273
274
MPG123_Delete(music);
Mix_SetError("mpg123_open_handle: %s", mpg_err(music->handle, result));
return NULL;
275
276
}
277
278
music->freesrc = freesrc;
return music;
279
280
}
281
static void MPG123_SetVolume(void *context, int volume)
282
{
283
284
MPG123_Music *music = (MPG123_Music *)context;
music->volume = volume;
285
286
}
287
static int MPG123_Play(void *context, int play_count)
288
{
289
290
291
MPG123_Music *music = (MPG123_Music *)context;
music->play_count = play_count;
return MPG123_Seek(music, 0.0);
292
293
}
294
295
/* read some mp3 stream data and convert it for output */
static int MPG123_GetSome(void *context, void *data, int bytes, SDL_bool *done)
296
{
297
298
299
MPG123_Music *music = (MPG123_Music *)context;
int filled, result;
size_t amount;
300
long rate;
301
int channels, encoding, format;
302
303
304
305
306
307
if (music->stream) {
filled = SDL_AudioStreamGet(music->stream, data, bytes);
if (filled != 0) {
return filled;
}
308
309
}
310
311
312
if (!music->play_count) {
/* All done */
*done = SDL_TRUE;
313
314
315
return 0;
}
316
317
318
319
320
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;
321
}
322
break;
323
324
325
326
327
328
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;
329
}
330
/*printf("MPG123 format: %s, channels = %d, rate = %ld\n", mpg123_format_str(encoding), channels, rate);*/
331
332
333
format = mpg123_format_to_sdl(encoding);
SDL_assert(format != -1);
334
335
336
337
338
music->stream = SDL_NewAudioStream(format, channels, (int)rate,
music_spec.format, music_spec.channels, music_spec.freq);
if (!music->stream) {
return -1;
339
}
340
341
342
343
344
345
346
347
348
349
350
351
352
353
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;
}
354
}
355
356
357
358
break;
default:
Mix_SetError("mpg123_read: %s", mpg_err(music->handle, result));
return -1;
359
}
360
361
362
363
364
365
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);
366
367
}
368
static int MPG123_Seek(void *context, double secs)
369
{
370
371
MPG123_Music *music = (MPG123_Music *)context;
off_t offset = (off_t)(music_spec.freq * secs);
372
373
374
if ((offset = mpg123.mpg123_seek(music->handle, offset, SEEK_SET)) < 0) {
return Mix_SetError("mpg123_seek: %s", mpg_err(music->handle, (int)-offset));
375
}
376
return 0;
377
378
}
379
380
static void MPG123_Delete(void *context)
{
381
MPG123_Music *music = (MPG123_Music *)context;
382
383
384
385
if (music->handle) {
mpg123.mpg123_close(music->handle);
mpg123.mpg123_delete(music->handle);
386
}
387
388
if (music->stream) {
SDL_FreeAudioStream(music->stream);
389
}
390
391
392
393
394
395
396
if (music->buffer) {
SDL_free(music->buffer);
}
if (music->freesrc) {
SDL_RWclose(music->src);
}
SDL_free(music);
397
398
399
400
}
static void MPG123_Close(void)
{
401
mpg123.mpg123_exit();
402
403
404
405
406
407
408
409
410
411
}
Mix_MusicInterface Mix_MusicInterface_MPG123 =
{
"MPG123",
MIX_MUSIC_MPG123,
MUS_MP3,
SDL_FALSE,
SDL_FALSE,
412
MPG123_Load,
413
414
415
416
417
MPG123_Open,
MPG123_CreateFromRW,
NULL, /* CreateFromFile */
MPG123_SetVolume,
MPG123_Play,
418
NULL, /* IsPlaying */
419
420
421
422
MPG123_GetAudio,
MPG123_Seek,
NULL, /* Pause */
NULL, /* Resume */
423
NULL, /* Stop */
424
425
MPG123_Delete,
MPG123_Close,
426
MPG123_Unload
427
428
429
430
431
};
#endif /* MUSIC_MP3_MPG123 */
/* vi: set ts=4 sw=4 expandtab: */