/
music_modplug.c
264 lines (234 loc) · 7.11 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
#ifdef MODPLUG_MUSIC
24
25
#include "SDL_mixer.h"
#include "dynamic_modplug.h"
26
27
28
29
30
31
32
33
34
#include "music_modplug.h"
static int current_output_channels=0;
static int music_swap8=0;
static int music_swap16=0;
static ModPlug_Settings settings;
int modplug_init(SDL_AudioSpec *spec)
{
35
36
37
38
39
if ( !Mix_Init(MIX_INIT_MODPLUG) ) {
return -1;
}
modplug.ModPlug_GetSettings(&settings);
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
settings.mFlags=MODPLUG_ENABLE_OVERSAMPLING;
current_output_channels=spec->channels;
settings.mChannels=spec->channels>1?2:1;
settings.mBits=spec->format&0xFF;
music_swap8 = 0;
music_swap16 = 0;
switch(spec->format)
{
case AUDIO_U8:
case AUDIO_S8: {
if ( spec->format == AUDIO_S8 ) {
music_swap8 = 1;
}
settings.mBits=8;
}
break;
case AUDIO_S16LSB:
case AUDIO_S16MSB: {
/* See if we need to correct MikMod mixing */
62
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
63
if ( spec->format == AUDIO_S16MSB ) {
64
#else
65
if ( spec->format == AUDIO_S16LSB ) {
66
#endif
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
music_swap16 = 1;
}
settings.mBits=16;
}
break;
default: {
Mix_SetError("Unknown hardware audio format");
return -1;
}
}
settings.mFrequency=spec->freq; /*TODO: limit to 11025, 22050, or 44100 ? */
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;
89
modplug.ModPlug_SetSettings(&settings);
90
return 0;
91
92
93
94
95
96
97
98
99
100
}
/* Uninitialize the music players */
void modplug_exit()
{
}
/* Set the volume for a modplug stream */
void modplug_setvolume(modplug_data *music, int volume)
{
101
modplug.ModPlug_SetMasterVolume(music->file, volume*4);
102
103
104
}
/* Load a modplug stream from an SDL_RWops object */
105
modplug_data *modplug_new_RW(SDL_RWops *src, int freesrc)
106
{
107
108
109
110
modplug_data *music = NULL;
Sint64 offset;
size_t sz;
char *buf;
111
112
113
114
115
116
/* Make sure the modplug library is loaded */
if ( !Mix_Init(MIX_INIT_MODPLUG) ) {
return NULL;
}
117
118
119
120
121
122
123
124
125
126
offset = SDL_RWtell(src);
SDL_RWseek(src, 0, RW_SEEK_END);
sz = (size_t)(SDL_RWtell(src) - offset);
SDL_RWseek(src, offset, RW_SEEK_SET);
buf = (char*)SDL_malloc(sz);
if (buf) {
if (SDL_RWread(src, buf, sz, 1) == 1) {
music = (modplug_data*)SDL_malloc(sizeof(modplug_data));
if (music) {
music->playing = 0;
127
music->file = modplug.ModPlug_Load(buf, (int)sz);
128
if (!music->file) {
129
SDL_free(music);
130
music = NULL;
131
}
132
} else {
133
134
135
136
SDL_OutOfMemory();
}
}
SDL_free(buf);
137
} else {
138
139
SDL_OutOfMemory();
}
140
141
if (music && freesrc) {
SDL_RWclose(src);
142
143
}
return music;
144
145
146
147
148
}
/* Start playback of a given modplug stream */
void modplug_play(modplug_data *music)
{
149
modplug.ModPlug_Seek(music->file,0);
150
music->playing=1;
151
152
153
154
155
}
/* Return non-zero if a stream is currently playing */
int modplug_playing(modplug_data *music)
{
156
return music && music->playing;
157
158
159
160
161
}
/* Play some of a stream previously started with modplug_play() */
int modplug_playAudio(modplug_data *music, Uint8 *stream, int len)
{
162
163
164
165
166
if (current_output_channels > 2) {
int small_len = 2 * len / current_output_channels;
int i;
Uint8 *src, *dst;
167
i=modplug.ModPlug_Read(music->file, stream, small_len);
168
169
if(i<small_len)
{
170
SDL_memset(stream+i,0,small_len-i);
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
music->playing=0;
}
/* and extend to len by copying channels */
src = stream + small_len;
dst = stream + len;
switch (settings.mBits) {
case 8:
for ( i=small_len/2; i; --i ) {
src -= 2;
dst -= current_output_channels;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[0];
dst[3] = src[1];
if (current_output_channels == 6) {
dst[4] = src[0];
dst[5] = src[1];
}
}
break;
case 16:
for ( i=small_len/4; i; --i ) {
src -= 4;
dst -= 2 * current_output_channels;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[0];
dst[5] = src[1];
dst[6] = src[2];
dst[7] = src[3];
if (current_output_channels == 6) {
dst[8] = src[0];
dst[9] = src[1];
dst[10] = src[2];
dst[11] = src[3];
}
}
break;
}
} else {
214
int i=modplug.ModPlug_Read(music->file, stream, len);
215
216
if(i<len)
{
217
SDL_memset(stream+i,0,len-i);
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
music->playing=0;
}
}
if ( music_swap8 ) {
Uint8 *dst;
int i;
dst = stream;
for ( i=len; i; --i ) {
*dst++ ^= 0x80;
}
} else
if ( music_swap16 ) {
Uint8 *dst, tmp;
int i;
dst = stream;
for ( i=(len/2); i; --i ) {
tmp = dst[0];
dst[0] = dst[1];
dst[1] = tmp;
dst += 2;
}
}
return 0;
243
244
245
246
247
}
/* Stop playback of a stream previously started with modplug_play() */
void modplug_stop(modplug_data *music)
{
248
music->playing=0;
249
250
251
252
253
}
/* Close the given modplug stream */
void modplug_delete(modplug_data *music)
{
254
modplug.ModPlug_Unload(music->file);
255
SDL_free(music);
256
257
258
259
260
}
/* Jump (seek) to a given position (time is in seconds) */
void modplug_jump_to_time(modplug_data *music, double time)
{
261
modplug.ModPlug_Seek(music->file,(int)(time*1000));
262
263
}
264
#endif /* MODPLUG_MUSIC */