/
music_modplug.c
310 lines (270 loc) · 8.52 KB
1
2
/*
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2017 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
23
24
#ifdef MUSIC_MOD_MODPLUG
#include "SDL_loadso.h"
25
26
27
#include "music_modplug.h"
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#ifdef MODPLUG_HEADER
#include MODPLUG_HEADER
#else
#include <libmodplug/modplug.h>
#endif
typedef struct {
int loaded;
void *handle;
ModPlugFile* (*ModPlug_Load)(const void* data, int size);
void (*ModPlug_Unload)(ModPlugFile* file);
int (*ModPlug_Read)(ModPlugFile* file, void* buffer, int size);
void (*ModPlug_Seek)(ModPlugFile* file, int millisecond);
void (*ModPlug_GetSettings)(ModPlug_Settings* settings);
void (*ModPlug_SetSettings)(const ModPlug_Settings* settings);
void (*ModPlug_SetMasterVolume)(ModPlugFile* file,unsigned int cvol) ;
} modplug_loader;
static modplug_loader modplug = {
0, NULL
};
52
53
static ModPlug_Settings settings;
54
#ifdef MODPLUG_DYNAMIC
55
56
57
58
59
60
61
#define FUNCTION_LOADER(FUNC, SIG) \
modplug.FUNC = (SIG) SDL_LoadFunction(modplug.handle, #FUNC); \
if (modplug.FUNC == NULL) { SDL_UnloadObject(modplug.handle); return -1; }
#else
#define FUNCTION_LOADER(FUNC, SIG) \
modplug.FUNC = FUNC;
#endif
62
63
64
65
static int MODPLUG_Load(void)
{
if (modplug.loaded == 0) {
66
#ifdef MODPLUG_DYNAMIC
67
68
69
70
modplug.handle = SDL_LoadObject(MODPLUG_DYNAMIC);
if (modplug.handle == NULL) {
return -1;
}
71
#elif defined(__MACOSX__)
72
73
74
75
76
77
78
extern ModPlugFile* ModPlug_Load(const void* data, int size) __attribute__((weak_import));
if (ModPlug_Load == NULL)
{
/* Missing weakly linked framework */
Mix_SetError("Missing modplug.framework");
return -1;
}
79
80
81
82
83
84
85
86
#endif
FUNCTION_LOADER(ModPlug_Load, ModPlugFile* (*)(const void* data, int size))
FUNCTION_LOADER(ModPlug_Unload, void (*)(ModPlugFile* file))
FUNCTION_LOADER(ModPlug_Read, int (*)(ModPlugFile* file, void* buffer, int size))
FUNCTION_LOADER(ModPlug_Seek, void (*)(ModPlugFile* file, int millisecond))
FUNCTION_LOADER(ModPlug_GetSettings, void (*)(ModPlug_Settings* settings))
FUNCTION_LOADER(ModPlug_SetSettings, void (*)(const ModPlug_Settings* settings))
FUNCTION_LOADER(ModPlug_SetMasterVolume, void (*)(ModPlugFile* file,unsigned int cvol))
87
88
89
90
91
92
93
}
++modplug.loaded;
return 0;
}
static void MODPLUG_Unload(void)
94
{
95
96
if (modplug.loaded == 0) {
return;
97
}
98
if (modplug.loaded == 1) {
99
100
101
#ifdef MODPLUG_DYNAMIC
SDL_UnloadObject(modplug.handle);
#endif
102
103
104
}
--modplug.loaded;
}
105
106
107
typedef struct
108
{
109
110
111
112
113
114
int play_count;
ModPlugFile *file;
SDL_AudioStream *stream;
void *buffer;
int buffer_size;
} MODPLUG_Music;
115
116
117
118
static int MODPLUG_Seek(void *context, double position);
static void MODPLUG_Delete(void *context);
119
120
121
122
123
124
125
126
127
128
static int MODPLUG_Open(const SDL_AudioSpec *spec)
{
/* ModPlug supports U8 or S16 audio output */
modplug.ModPlug_GetSettings(&settings);
settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING;
if (spec->channels == 1) {
settings.mChannels = 1;
} else {
settings.mChannels = 2;
129
}
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
if (SDL_AUDIO_BITSIZE(spec->format) == 8) {
settings.mBits = 8;
} else {
settings.mBits = 16;
}
if (spec->freq >= 44100) {
settings.mFrequency = 44100;
} else if (spec->freq >= 22050) {
settings.mFrequency = 22050;
} else {
settings.mFrequency = 11025;
}
settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
settings.mReverbDepth = 0;
settings.mReverbDelay = 100;
settings.mBassAmount = 0;
settings.mBassRange = 50;
settings.mSurroundDepth = 0;
settings.mSurroundDelay = 10;
settings.mLoopCount = 0;
150
modplug.ModPlug_SetSettings(&settings);
151
return 0;
152
153
154
}
/* Load a modplug stream from an SDL_RWops object */
155
void *MODPLUG_CreateFromRW(SDL_RWops *src, int freesrc)
156
{
157
158
159
160
161
162
MODPLUG_Music *music;
void *buffer;
size_t size;
music = (MODPLUG_Music *)SDL_calloc(1, sizeof(*music));
if (!music) {
163
SDL_OutOfMemory();
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
return NULL;
}
music->stream = SDL_NewAudioStream((settings.mBits == 8) ? AUDIO_U8 : AUDIO_S16SYS, settings.mChannels, settings.mFrequency,
music_spec.format, music_spec.channels, music_spec.freq);
if (!music->stream) {
MODPLUG_Delete(music);
return NULL;
}
music->buffer_size = music_spec.samples * (settings.mBits / 8) * settings.mChannels;
music->buffer = SDL_malloc(music->buffer_size);
if (!music->buffer) {
MODPLUG_Delete(music);
return NULL;
179
}
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
buffer = SDL_LoadFile_RW(src, &size, SDL_FALSE);
if (buffer) {
music->file = modplug.ModPlug_Load(buffer, (int)size);
if (!music->file) {
Mix_SetError("ModPlug_Load failed");
}
SDL_free(buffer);
}
if (!music->file) {
MODPLUG_Delete(music);
return NULL;
}
if (freesrc) {
196
SDL_RWclose(src);
197
198
}
return music;
199
200
}
201
202
/* Set the volume for a modplug stream */
static void MODPLUG_SetVolume(void *context, int volume)
203
{
204
205
MODPLUG_Music *music = (MODPLUG_Music *)context;
modplug.ModPlug_SetMasterVolume(music->file, volume*4);
206
207
}
208
/* Start playback of a given modplug stream */
209
static int MODPLUG_Play(void *context, int play_count)
210
{
211
212
213
MODPLUG_Music *music = (MODPLUG_Music *)context;
music->play_count = play_count;
return MODPLUG_Seek(music, 0.0);
214
215
216
}
/* Play some of a stream previously started with modplug_play() */
217
static int MODPLUG_GetSome(void *context, void *data, int bytes, SDL_bool *done)
218
{
219
220
221
222
223
224
MODPLUG_Music *music = (MODPLUG_Music *)context;
int filled, amount;
filled = SDL_AudioStreamGet(music->stream, data, bytes);
if (filled != 0) {
return filled;
225
226
}
227
228
229
230
231
232
233
234
235
236
if (!music->play_count) {
/* All done */
*done = SDL_TRUE;
return 0;
}
amount = modplug.ModPlug_Read(music->file, music->buffer, music->buffer_size);
if (amount > 0) {
if (SDL_AudioStreamPut(music->stream, music->buffer, amount) < 0) {
return -1;
237
}
238
239
240
241
242
243
244
245
246
247
248
249
} else {
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 (MODPLUG_Play(music, play_count) < 0) {
return -1;
}
250
251
}
}
252
253
254
255
256
return 0;
}
static int MODPLUG_GetAudio(void *context, void *data, int bytes)
{
return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, MODPLUG_GetSome);
257
258
}
259
260
/* Jump (seek) to a given position */
static int MODPLUG_Seek(void *context, double position)
261
{
262
263
MODPLUG_Music *music = (MODPLUG_Music *)context;
modplug.ModPlug_Seek(music->file, (int)(position*1000));
264
return 0;
265
266
267
}
/* Close the given modplug stream */
268
static void MODPLUG_Delete(void *context)
269
{
270
271
272
273
274
275
276
277
278
279
280
MODPLUG_Music *music = (MODPLUG_Music *)context;
if (music->file) {
modplug.ModPlug_Unload(music->file);
}
if (music->stream) {
SDL_FreeAudioStream(music->stream);
}
if (music->buffer) {
SDL_free(music->buffer);
}
SDL_free(music);
281
282
}
283
Mix_MusicInterface Mix_MusicInterface_MODPLUG =
284
{
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
"MODPLUG",
MIX_MUSIC_MODPLUG,
MUS_MOD,
SDL_FALSE,
SDL_FALSE,
MODPLUG_Load,
MODPLUG_Open,
MODPLUG_CreateFromRW,
NULL, /* CreateFromFile */
MODPLUG_SetVolume,
MODPLUG_Play,
NULL, /* IsPlaying */
MODPLUG_GetAudio,
MODPLUG_Seek,
NULL, /* Pause */
NULL, /* Resume */
NULL, /* Stop */
MODPLUG_Delete,
NULL, /* Close */
MODPLUG_Unload,
};
#endif /* MUSIC_MOD_MODPLUG */
309
310
/* vi: set ts=4 sw=4 expandtab: */