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