1 // Modified by Francisco Mu�oz 'Hermes' MAY 2008
2 // Changed to use libAESND
3 // linke aginst libaesnd.a - -laesnd
10 #include "gcmodplay.h"
12 //#define _GCMOD_DEBUG
14 #define STACKSIZE 8192
15 #define SNDBUFFERSIZE (5760) //that's the maximum buffer size
17 static BOOL thr_running
= FALSE
;
18 static BOOL sndPlaying
= FALSE
;
19 static MODSNDBUF sndBuffer
;
21 static u32 shiftVal
= 0;
22 static vu32 curr_audio
= 0;
23 static u8 audioBuf
[2][SNDBUFFERSIZE
] ATTRIBUTE_ALIGN(32);
25 static lwpq_t player_queue
;
27 static u8 player_stack
[STACKSIZE
] ATTRIBUTE_ALIGN(8);
28 static void* player(void *);
31 static s32 mod_freq
= 48000;
32 static AESNDPB
*modvoice
= NULL
;
36 static u64 mixtime
= 0;
37 static u64 reqcbtime
= 0;
38 extern u32
diff_usec(unsigned long long start
,unsigned long long end
);
39 extern u32
diff_msec(unsigned long long start
,unsigned long long end
);
42 static void* player(void *arg
)
49 while(sndPlaying
==TRUE
) {
50 LWP_ThreadSleep(player_queue
);
51 if(sndPlaying
==TRUE
) {
55 sndBuffer
.callback(sndBuffer
.usr_data
,((u8
*)audioBuf
[curr_audio
]),SNDBUFFERSIZE
);
67 static void __aesndvoicecallback(AESNDPB
*pb
,u32 state
)
70 static u64 rqstart
= 0,rqend
= 0;
73 if(rqstart
) reqcbtime
= rqend
- rqstart
;
76 case VOICE_STATE_STOPPED
:
77 case VOICE_STATE_RUNNING
:
79 case VOICE_STATE_STREAM
:
80 AESND_SetVoiceBuffer(pb
,(void*)audioBuf
[curr_audio
],SNDBUFFERSIZE
);
81 LWP_ThreadSignal(player_queue
);
92 static void dmaCallback()
95 static u64 adstart
= 0,adend
= 0;
98 if(adstart
) printf("dmaCallback(%d us)\n",diff_usec(adstart
,adend
));
102 AUDIO_InitDMA((u32
)audioBuf
[curr_audio
],SNDBUFFERSIZE
);
103 LWP_ThreadSignal(player_queue
);
111 static void mixCallback(void *usrdata
,u8
*stream
,u32 len
)
114 MODPlay
*mp
= (MODPlay
*)usrdata
;
117 if(mp
->manual_polling
)
118 mod
->notify
= &mp
->paused
;
122 mod
->mixingbuf
= stream
;
123 mod
->mixingbuflen
= len
;
126 for(i
=0;i
<(len
>>1);i
++)
127 ((u16
*)stream
)[i
] = 0;
131 #ifndef __AESNDLIB_H__
132 DCFlushRange(stream
,len
);
136 static s32
SndBufStart(MODSNDBUF
*sndbuf
)
138 if(sndPlaying
) return -1;
140 memcpy(&sndBuffer
,sndbuf
,sizeof(MODSNDBUF
));
143 if(sndBuffer
.chans
==2)
145 if(sndBuffer
.fmt
==16)
148 memset(audioBuf
[0],0,SNDBUFFERSIZE
);
149 memset(audioBuf
[1],0,SNDBUFFERSIZE
);
151 DCFlushRange(audioBuf
[0],SNDBUFFERSIZE
);
152 DCFlushRange(audioBuf
[1],SNDBUFFERSIZE
);
158 if(LWP_CreateThread(&hplayer
,player
,NULL
,player_stack
,STACKSIZE
,80)!=-1) {
159 #ifndef __AESNDLIB_H__
160 AUDIO_RegisterDMACallback(dmaCallback
);
161 AUDIO_InitDMA((u32
)audioBuf
[curr_audio
],SNDBUFFERSIZE
);
164 AESND_SetVoiceStop(modvoice
,false);
173 static void SndBufStop()
175 if(!sndPlaying
) return;
176 #ifndef __AESNDLIB_H__
178 AUDIO_RegisterDMACallback(NULL
);
180 AESND_SetVoiceStop(modvoice
,true);
184 LWP_ThreadSignal(player_queue
);
185 LWP_JoinThread(hplayer
,NULL
);
188 static s32
updateWaveFormat(MODPlay
*mod
)
190 BOOL p
= mod
->playing
;
196 mod
->soundBuf
.chans
= 2;
197 mod
->mod
.channels
= 2;
199 mod
->soundBuf
.chans
= 1;
200 mod
->mod
.channels
= 1;
203 mod
->soundBuf
.freq
= mod
->playfreq
;
204 mod
->mod
.freq
= mod
->playfreq
;
208 mod
->mod
.samplescounter
= 0;
209 mod
->mod
.samplespertick
= mod
->mod
.bpmtab
[mod
->mod
.bpm
-32];
212 mod
->soundBuf
.fmt
= 16;
213 mod
->soundBuf
.usr_data
= mod
;
214 mod
->soundBuf
.callback
= mixCallback
;
215 mod
->soundBuf
.samples
= (f32
)mod
->playfreq
/50.0F
;
218 SndBufStart(&mod
->soundBuf
);
223 void MODPlay_Init(MODPlay
*mod
)
225 memset(mod
,0,sizeof(MODPlay
));
227 #ifndef __AESNDLIB_H__
230 modvoice
= AESND_AllocateVoice(__aesndvoicecallback
);
232 AESND_SetVoiceFormat(modvoice
,VOICE_STEREO16
);
233 AESND_SetVoiceFrequency(modvoice
,mod_freq
);
234 AESND_SetVoiceVolume(modvoice
,255,255);
235 AESND_SetVoiceStream(modvoice
,true);
238 MODPlay_SetFrequency(mod
,48000);
239 MODPlay_SetStereo(mod
,TRUE
);
241 LWP_InitQueue(&player_queue
);
248 mod
->numSFXChans
= 0;
249 mod
->manual_polling
= FALSE
;
252 s32
MODPlay_SetFrequency(MODPlay
*mod
,u32 freq
)
254 if(freq
==mod
->playfreq
) return 0;
255 if(freq
==32000 || freq
==48000) {
256 #ifndef __AESNDLIB_H__
258 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ
);
260 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ
);
264 mod
->playfreq
= freq
;
265 updateWaveFormat(mod
);
271 void MODPlay_SetStereo(MODPlay
*mod
,BOOL stereo
)
273 if(stereo
==mod
->stereo
) return;
275 mod
->stereo
= stereo
;
276 updateWaveFormat(mod
);
279 void MODPlay_Unload(MODPlay
*mod
)
285 s32
MODPlay_SetMOD(MODPlay
*mod
,const void *mem
)
289 if(MOD_SetMOD(&mod
->mod
,(u8
*)mem
)==0) {
290 MODPlay_AllocSFXChannels(mod
,mod
->numSFXChans
);
296 s32
MODPlay_Start(MODPlay
*mod
)
298 if(mod
->playing
) return -1;
299 if(mod
->mod
.modraw
==NULL
) return -1;
301 updateWaveFormat(mod
);
302 MOD_Start(&mod
->mod
);
303 if(SndBufStart(&mod
->soundBuf
)<0) return -1;
308 s32
MODPlay_Stop(MODPlay
*mod
)
310 if(!mod
->playing
) return -1;
313 mod
->playing
= FALSE
;
317 s32
MODPlay_AllocSFXChannels(MODPlay
*mod
,u32 sfxchans
)
319 if(mod
->mod
.modraw
==NULL
) return -1;
321 if(MOD_AllocSFXChannels(&mod
->mod
,sfxchans
)==0) {
322 mod
->numSFXChans
= sfxchans
;
328 s32
MODPlay_Pause(MODPlay
*mod
,BOOL pause
)
330 if(!mod
->playing
) return -1;
335 s32
MODPlay_TriggerNote(MODPlay
*mod
,u32 chan
,u8 inst
,u16 freq
,u8 vol
)
337 if(mod
->mod
.modraw
==0) return -1;
338 return MOD_TriggerNote(&mod
->mod
,chan
,inst
,freq
,vol
);
343 /* void MODPlay_SetVolume(MODPlay *mod, s32 musicvolume, s32 sfxvolume)
345 Set the volume levels for the MOD music (call it after MODPlay_SetMOD())
347 mod: the MODPlay pointer
349 musicvolume: in range 0 to 64
350 sfxvolume: in range 0 to 64
354 void MODPlay_SetVolume(MODPlay
*mod
, s32 musicvolume
, s32 sfxvolume
)
356 if(musicvolume
<0) musicvolume
=0;
357 if(musicvolume
>64) musicvolume
=64;
359 if(sfxvolume
<0) sfxvolume
=0;
360 if(sfxvolume
>64) sfxvolume
=64;
362 mod
->mod
.musicvolume
= musicvolume
;
363 mod
->mod
.sfxvolume
= sfxvolume
;
367 u32
MODPlay_MixingTime()
369 return ticks_to_microsecs(mixtime
);
372 u32
MODPlay_RequestTime()
374 return ticks_to_microsecs(reqcbtime
);