catch up with upsteam
[libogc.git] / libmodplay / gcmodplay.c
blobaacefe3f28595da46891ef7719a7031095d39e9e
1 // Modified by Francisco Mu�oz 'Hermes' MAY 2008
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <gccore.h>
7 #include <asndlib.h>
8 #include "gcmodplay.h"
10 //#define _GCMOD_DEBUG
12 #define STACKSIZE 8192
13 #define SNDBUFFERSIZE 8192 //that's the maximum buffer size for one VBlank we need.
15 static BOOL thr_running = FALSE;
16 static BOOL sndPlaying = FALSE;
17 static MODSNDBUF sndBuffer;
19 static s32 have_samples = 0;
20 static s32 mod_freq = 48000;
22 static u32 shiftVal = 0;
23 static vu32 curr_audio = 0;
24 static u8 audioBuf[2][SNDBUFFERSIZE] ATTRIBUTE_ALIGN(32);
26 static lwpq_t player_queue;
27 static lwp_t hplayer;
28 static u8 player_stack[STACKSIZE];
29 static void* player(void *);
31 #ifdef _GCMOD_DEBUG
32 extern long long gettime();
33 extern u32 diff_usec(unsigned long long start,unsigned long long end);
34 extern u32 diff_msec(unsigned long long start,unsigned long long end);
35 #endif
37 static void* player(void *arg)
39 #ifdef _GCMOD_DEBUG
40 long long start,end;
41 #endif
43 thr_running = TRUE;
44 while(sndPlaying==TRUE) {
45 LWP_ThreadSleep(player_queue);
46 if(sndPlaying==TRUE) {
47 #ifdef _GCMOD_DEBUG
48 printf("player(run callback)\n\n");
49 start = gettime();
50 #endif
51 sndBuffer.callback(sndBuffer.usr_data,((u8*)audioBuf[curr_audio]),SNDBUFFERSIZE);
52 have_samples = 2;
53 #ifdef _GCMOD_DEBUG
54 end = gettime();
55 printf("player(end callback,%d - %d us)\n\n",curr_audio,diff_usec(start,end));
56 #endif
59 thr_running = FALSE;
60 #ifdef _GCMOD_DEBUG
61 printf("player stopped %d\n",thr_running);
62 #endif
63 return 0;
66 static void dmaCallback()
68 #ifdef _GCMOD_DEBUG
69 static long long start = 0,end = 0;
71 end = gettime();
72 if(start) printf("dmaCallback(%p,%d,%d - after %d ms)\n",(void*)audioBuf[curr_audio],SNDBUFFERSIZE,curr_audio,diff_msec(start,end));
73 #endif
75 #ifndef __SNDLIB_H__
76 curr_audio ^= 1;
77 AUDIO_InitDMA((u32)audioBuf[curr_audio],SNDBUFFERSIZE);
78 LWP_ThreadSignal(player_queue);
79 #else
80 if(have_samples==0) {
81 have_samples = 1;
82 LWP_ThreadSignal(player_queue);
83 return;
85 if(have_samples==1) return;
87 if(have_samples==2) {
88 if(SND_AddVoice(0,audioBuf[curr_audio], SNDBUFFERSIZE)!=0) return; // Sorry I am busy: try again
89 have_samples=0;
90 curr_audio ^= 1;
92 #endif
94 #ifdef _GCMOD_DEBUG
95 start = gettime();
96 printf("dmaCallback(%p,%d,%d,%d us) leave\n",(void*)audioBuf[curr_audio],SNDBUFFERSIZE,curr_audio,diff_usec(end,start));
97 #endif
100 static void mixCallback(void *usrdata,u8 *stream,u32 len)
102 u32 i;
103 MODPlay *mp = (MODPlay*)usrdata;
104 MOD *mod = &mp->mod;
105 #ifdef _GCMOD_DEBUG
106 printf("mixCallback(%p,%p,%d) enter\n",stream,usrdata,len);
107 #endif
108 if(mp->manual_polling)
109 mod->notify = &mp->paused;
110 else
111 mod->notify = NULL;
113 mod->mixingbuf = stream;
114 mod->mixingbuflen = len;
116 if(mp->paused) {
117 for(i=0;i<(len>>1);i++)
118 ((u16*)stream)[i] = 0;
119 } else
120 MOD_Player(mod);
122 #ifndef __SNDLIB_H__
123 DCFlushRange(stream,len);
124 #endif
126 #ifdef _GCMOD_DEBUG
127 printf("mixCallback(%p,%p,%d,%d) leave\n",stream,usrdata,len,mp->paused);
128 #endif
131 static s32 SndBufStart(MODSNDBUF *sndbuf)
133 if(sndPlaying) return -1;
134 #ifdef _GCMOD_DEBUG
135 printf("SndBufStart(%p) enter\n",sndbuf);
136 #endif
137 memcpy(&sndBuffer,sndbuf,sizeof(MODSNDBUF));
139 shiftVal = 0;
140 if(sndBuffer.chans==2)
141 shiftVal++;
142 if(sndBuffer.fmt==16)
143 shiftVal++;
145 memset(audioBuf[0],0,SNDBUFFERSIZE);
146 memset(audioBuf[1],0,SNDBUFFERSIZE);
148 DCFlushRange(audioBuf[0],SNDBUFFERSIZE);
149 DCFlushRange(audioBuf[1],SNDBUFFERSIZE);
151 while(thr_running);
153 curr_audio = 0;
154 sndPlaying = TRUE;
155 if(LWP_CreateThread(&hplayer,player,NULL,player_stack,STACKSIZE,80)!=-1) {
156 #ifndef __SNDLIB_H__
157 AUDIO_RegisterDMACallback(dmaCallback);
158 AUDIO_InitDMA((u32)audioBuf[curr_audio],SNDBUFFERSIZE);
159 AUDIO_StartDMA();
160 #else
161 SND_SetVoice(0, VOICE_STEREO_16BIT, mod_freq,0, audioBuf[curr_audio], SNDBUFFERSIZE, 255, 255, dmaCallback);
162 have_samples=0;
163 SND_Pause(0);
164 #endif
165 return 1;
167 sndPlaying = FALSE;
169 return -1;
172 static void SndBufStop()
174 if(!sndPlaying) return;
175 #ifndef __SNDLIB_H__
176 AUDIO_StopDMA();
177 AUDIO_RegisterDMACallback(NULL);
178 #else
179 SND_StopVoice(0);
180 #endif
181 curr_audio = 0;
182 sndPlaying = FALSE;
183 LWP_ThreadSignal(player_queue);
184 LWP_JoinThread(hplayer,NULL);
187 static s32 updateWaveFormat(MODPlay *mod)
189 BOOL p = mod->playing;
191 if(p)
192 SndBufStop();
194 if(mod->stereo) {
195 mod->soundBuf.chans = 2;
196 mod->mod.channels = 2;
197 } else {
198 mod->soundBuf.chans = 1;
199 mod->mod.channels = 1;
202 mod->soundBuf.freq = mod->playfreq;
203 mod->mod.freq = mod->playfreq;
204 mod->mod.bits = 16;
206 if(p) {
207 mod->mod.samplescounter = 0;
208 mod->mod.samplespertick = mod->mod.bpmtab[mod->mod.bpm-32];
211 mod->soundBuf.fmt = 16;
212 mod->soundBuf.usr_data = mod;
213 mod->soundBuf.callback = mixCallback;
214 mod->soundBuf.samples = (f32)mod->playfreq/50.0F;
216 if(p)
217 SndBufStart(&mod->soundBuf);
219 return 0;
222 void MODPlay_Init(MODPlay *mod)
224 memset(mod,0,sizeof(MODPlay));
226 #ifndef __SNDLIB_H__
227 AUDIO_Init(NULL);
228 #else
229 SND_Pause(0);
230 SND_StopVoice(0);
231 #endif
232 MODPlay_SetFrequency(mod,48000);
233 MODPlay_SetStereo(mod,TRUE);
235 LWP_InitQueue(&player_queue);
237 sndPlaying = FALSE;
238 thr_running = FALSE;
240 mod->paused = FALSE;
241 mod->bits = TRUE;
242 mod->numSFXChans = 0;
243 mod->manual_polling = FALSE;
246 s32 MODPlay_SetFrequency(MODPlay *mod,u32 freq)
248 if(freq==mod->playfreq) return 0;
249 if(freq==32000 || freq==48000) {
250 #ifndef __SNDLIB_H__
251 if(freq==32000)
252 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ);
253 else
254 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
255 #else
256 mod_freq = 48000;
257 #endif
258 mod->playfreq = freq;
259 updateWaveFormat(mod);
260 return 0;
262 return -1;
265 void MODPlay_SetStereo(MODPlay *mod,BOOL stereo)
267 if(stereo==mod->stereo) return;
269 mod->stereo = stereo;
270 updateWaveFormat(mod);
273 void MODPlay_Unload(MODPlay *mod)
275 MODPlay_Stop(mod);
276 MOD_Free(&mod->mod);
279 s32 MODPlay_SetMOD(MODPlay *mod,const void *mem)
281 MODPlay_Unload(mod);
283 if(MOD_SetMOD(&mod->mod,(u8*)mem)==0) {
284 MODPlay_AllocSFXChannels(mod,mod->numSFXChans);
285 return 0;
287 return -1;
290 s32 MODPlay_Start(MODPlay *mod)
292 if(mod->playing) return -1;
293 if(mod->mod.modraw==NULL) return -1;
295 updateWaveFormat(mod);
296 MOD_Start(&mod->mod);
297 if(SndBufStart(&mod->soundBuf)<0) return -1;
298 mod->playing = TRUE;
299 return 0;
302 s32 MODPlay_Stop(MODPlay *mod)
304 if(!mod->playing) return -1;
306 SndBufStop();
307 mod->playing = FALSE;
308 return 0;
311 s32 MODPlay_AllocSFXChannels(MODPlay *mod,u32 sfxchans)
313 if(mod->mod.modraw==NULL) return -1;
315 if(MOD_AllocSFXChannels(&mod->mod,sfxchans)==0) {
316 mod->numSFXChans = sfxchans;
317 return 0;
319 return -1;
322 s32 MODPlay_Pause(MODPlay *mod,BOOL pause)
324 if(!mod->playing) return -1;
325 mod->paused = pause;
326 return 0;
329 s32 MODPlay_TriggerNote(MODPlay *mod,u32 chan,u8 inst,u16 freq,u8 vol)
331 if(mod->mod.modraw==0) return -1;
332 return MOD_TriggerNote(&mod->mod,chan,inst,freq,vol);
335 // add by Hermes
337 /* void MODPlay_SetVolume(MODPlay *mod, s32 musicvolume, s32 sfxvolume)
339 Set the volume levels for the MOD music (call it after MODPlay_SetMOD())
341 mod: the MODPlay pointer
343 musicvolume: in range 0 to 64
344 sfxvolume: in range 0 to 64
348 void MODPlay_SetVolume(MODPlay *mod, s32 musicvolume, s32 sfxvolume)
350 if(musicvolume<0) musicvolume=0;
351 if(musicvolume>64) musicvolume=64;
353 if(sfxvolume<0) sfxvolume=0;
354 if(sfxvolume>64) sfxvolume=64;
356 mod->mod.musicvolume= musicvolume;
357 mod->mod.sfxvolume = sfxvolume;