6 #include <ogc/lwp_watchdog.h>
7 #include <ogc/machine/processor.h>
12 #define PB_STRUCT_SIZE 64
13 #define DSP_DRAMSIZE 8192
15 #define VOICE_PAUSE 0x00000004
16 #define VOICE_LOOP 0x00000008
17 #define VOICE_ONCE 0x00000010
18 #define VOICE_STREAM 0x00000020
20 #define VOICE_FINISHED 0x00100000
21 #define VOICE_STOPPED 0x00200000
22 #define VOICE_RUNNING 0x40000000
23 #define VOICE_USED 0x80000000
41 s16 left
,right
; //28,30
42 u16 volume_l
,volume_r
; //32,34
57 AESNDVoiceCallback cb
;
59 AESNDAudioCallback audioCB
;
62 static dsptask_t __aesnddsptask
;
64 static vu32 __aesndinit
= 0;
65 static vu32 __aesndcurrab
= 0;
66 static vu32 __aesnddspinit
= 0;
67 static vu32 __aesndcurrvoice
= 0;
68 static vu32 __aesnddspcomplete
= 0;
69 static vu64 __aesnddspstarttime
= 0;
70 static vu64 __aesnddspprocesstime
= 0;
71 static vu32 __aesnddspabrequested
= 0;
72 static volatile bool __aesndglobalpause
= false;
73 static volatile bool __aesndvoicesstopped
= true;
76 static u32 __aesndarambase
= 0;
77 static u32 __aesndaramblocks
[MAX_VOICES
];
78 static u32 __aesndarammemory
[MAX_VOICES
];
81 static AESNDPB __aesndvoicepb
[MAX_VOICES
];
82 static AESNDPB __aesndcommand
ATTRIBUTE_ALIGN(32);
83 static u8 __dspdram
[DSP_DRAMSIZE
] ATTRIBUTE_ALIGN(32);
84 static u8 mute_buffer
[SND_BUFFERSIZE
] ATTRIBUTE_ALIGN(32);
85 static u8 audio_buffer
[2][SND_BUFFERSIZE
] ATTRIBUTE_ALIGN(32);
87 static __inline__
void snd_set0b(char *p
,int n
)
89 while(n
>0) { *p
++ = 0; n
--; }
92 static __inline__
void snd_set0w(int *p
,int n
)
94 while(n
>0) { *p
++ = 0; n
--; }
97 static __inline__
void __aesndcopycommand(AESNDPB
*dst
,AESNDPB
*src
)
99 dst
->buf_start
= src
->buf_start
;
100 dst
->buf_end
= src
->buf_end
;
101 dst
->buf_curr
= src
->buf_curr
;
107 dst
->freq_h
= src
->freq_h
;
108 dst
->freq_l
= src
->freq_l
;
109 dst
->counter
= src
->counter
;
111 dst
->left
= src
->left
;
112 dst
->right
= src
->right
;
114 dst
->volume_l
= src
->volume_l
;
115 dst
->volume_r
= src
->volume_r
;
117 dst
->flags
= src
->flags
;
118 dst
->delay
= src
->delay
;
120 dst
->mram_start
= src
->mram_start
;
121 dst
->mram_curr
= src
->mram_curr
;
122 dst
->mram_end
= src
->mram_end
;
123 dst
->stream_last
= src
->stream_last
;
125 dst
->voiceno
= src
->voiceno
;
126 dst
->shift
= src
->shift
;
130 static __inline__
void __aesndsetvoiceformat(AESNDPB
*pb
,u32 format
)
132 pb
->flags
= (pb
->flags
&~0x03)|(format
&0x03);
133 switch((format
&0x03)) {
145 static __inline__
void __aesndsetvoicebuffer(AESNDPB
*pb
,void* buffer
,u32 len
)
147 pb
->mram_start
= (u32
)buffer
;
148 pb
->mram_curr
= (u32
)buffer
;
149 pb
->mram_end
= (u32
)buffer
+ len
;
152 static __inline__
void __aesndsetvoicefreq(AESNDPB
*pb
,u32 freq
)
154 register u32 ratio
= 0x00010000*((f32
)freq
/(f32
)DSP_DEFAULT_FREQ
);
155 pb
->freq_h
= (u16
)(ratio
>>16);
156 pb
->freq_l
= (u16
)(ratio
&0xffff);
160 static ARQRequest arq_request
[MAX_VOICES
];
161 static u8 stream_buffer
[SND_BUFFERSIZE
*2] ATTRIBUTE_ALIGN(32);
163 static void __aesndarqcallback(ARQRequest
*req
)
165 __aesndvoicepb
[req
->owner
].flags
|= VOICE_RUNNING
;
168 static void __aesndfillbuffer(AESNDPB
*pb
,u32 buffer
)
170 register u32 copy_len
;
171 register u32 rem_len
;
172 register u32 buf_addr
;
174 buf_addr
= __aesndaramblocks
[pb
->voiceno
];
175 if(buffer
) buf_addr
+= SND_BUFFERSIZE
;
177 rem_len
= (pb
->mram_end
- pb
->mram_curr
);
178 copy_len
= (rem_len
<SND_BUFFERSIZE
) ? rem_len
: SND_BUFFERSIZE
;
180 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
181 if(copy_len
<SND_BUFFERSIZE
) memset(stream_buffer
+ copy_len
,0,SND_BUFFERSIZE
- copy_len
);
183 DCFlushRange(stream_buffer
,SND_BUFFERSIZE
);
184 ARQ_PostRequestAsync(&arq_request
[pb
->voiceno
],pb
->voiceno
,ARQ_MRAMTOARAM
,ARQ_PRIO_HI
,buf_addr
,(u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
),SND_BUFFERSIZE
,NULL
);
186 pb
->mram_curr
+= copy_len
;
189 static __inline__
void __aesndhandlerequest(AESNDPB
*pb
)
191 register u32 buf_addr
;
192 register u32 copy_len
;
193 register u32 rem_len
;
195 if(pb
->mram_curr
>=pb
->mram_end
) {
196 if(pb
->flags
&VOICE_ONCE
) {
197 pb
->flags
|= VOICE_STOPPED
;
199 } else if(pb
->flags
&VOICE_LOOP
) pb
->mram_curr
= pb
->mram_start
;
200 else if(pb
->cb
) pb
->cb(pb
,VOICE_STATE_STREAM
);
204 register u32 curr_pos
= pb
->buf_curr
;
205 if(curr_pos
<pb
->stream_last
)
206 __aesndfillbuffer(pb
,1);
207 if(curr_pos
>=(pb
->buf_start
+ (SND_BUFFERSIZE
>>pb
->shift
)) &&
208 pb
->stream_last
<(pb
->buf_start
+ (SND_BUFFERSIZE
>>pb
->shift
)))
209 __aesndfillbuffer(pb
,0);
211 pb
->stream_last
= curr_pos
;
215 buf_addr
= __aesndaramblocks
[pb
->voiceno
];
216 pb
->buf_start
= buf_addr
>>pb
->shift
;
217 pb
->buf_end
= (buf_addr
+ (SND_BUFFERSIZE
*2) - (1<<pb
->shift
))>>pb
->shift
;
218 pb
->buf_curr
= pb
->buf_start
;
220 rem_len
= (pb
->mram_end
- pb
->mram_curr
);
221 copy_len
= (rem_len
<(SND_BUFFERSIZE
*2)) ? rem_len
: (SND_BUFFERSIZE
*2);
223 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
224 if(copy_len
<(SND_BUFFERSIZE
*2)) memset(stream_buffer
+ copy_len
,0,(SND_BUFFERSIZE
*2) - copy_len
);
226 DCFlushRange(stream_buffer
,(SND_BUFFERSIZE
*2));
227 ARQ_PostRequestAsync(&arq_request
[pb
->voiceno
],pb
->voiceno
,ARQ_MRAMTOARAM
,ARQ_PRIO_HI
,buf_addr
,(u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
),(SND_BUFFERSIZE
*2),__aesndarqcallback
);
229 pb
->mram_curr
+= copy_len
;
231 #elif defined(HW_RVL)
232 static u8 stream_buffer
[MAX_VOICES
][SND_BUFFERSIZE
*2] ATTRIBUTE_ALIGN(32);
234 static void __aesndfillbuffer(AESNDPB
*pb
,u32 buffer
)
236 register u32 copy_len
;
237 register u32 rem_len
;
238 register u32 buf_addr
;
240 buf_addr
= (u32
)stream_buffer
[pb
->voiceno
];
241 if(buffer
) buf_addr
+= SND_BUFFERSIZE
;
243 rem_len
= (pb
->mram_end
- pb
->mram_curr
);
244 copy_len
= (rem_len
<SND_BUFFERSIZE
) ? rem_len
: SND_BUFFERSIZE
;
246 memcpy((void*)buf_addr
,(void*)pb
->mram_curr
,copy_len
);
247 if(copy_len
<SND_BUFFERSIZE
) memset((void*)(buf_addr
+ copy_len
),0,SND_BUFFERSIZE
- copy_len
);
249 DCFlushRange((void*)buf_addr
,SND_BUFFERSIZE
);
251 pb
->mram_curr
+= copy_len
;
254 static __inline__
void __aesndhandlerequest(AESNDPB
*pb
)
256 register u32 buf_addr
;
257 register u32 copy_len
;
258 register u32 rem_len
;
260 if(pb
->mram_curr
>=pb
->mram_end
) {
261 if(pb
->flags
&VOICE_ONCE
) {
262 pb
->flags
|= VOICE_STOPPED
;
264 } else if(pb
->flags
&VOICE_LOOP
) pb
->mram_curr
= pb
->mram_start
;
265 else if(pb
->cb
) pb
->cb(pb
,VOICE_STATE_STREAM
);
269 register u32 curr_pos
= pb
->buf_curr
;
270 if(curr_pos
<pb
->stream_last
)
271 __aesndfillbuffer(pb
,1);
272 if(curr_pos
>=(pb
->buf_start
+ (SND_BUFFERSIZE
>>pb
->shift
)) &&
273 pb
->stream_last
<(pb
->buf_start
+ (SND_BUFFERSIZE
>>pb
->shift
)))
274 __aesndfillbuffer(pb
,0);
276 pb
->stream_last
= curr_pos
;
280 buf_addr
= (u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
[pb
->voiceno
]);
281 pb
->buf_start
= buf_addr
>>pb
->shift
;
282 pb
->buf_end
= (buf_addr
+ (SND_BUFFERSIZE
*2) - (1<<pb
->shift
))>>pb
->shift
;
283 pb
->buf_curr
= pb
->buf_start
;
285 rem_len
= (pb
->mram_end
- pb
->mram_curr
);
286 copy_len
= (rem_len
<(SND_BUFFERSIZE
*2)) ? rem_len
: (SND_BUFFERSIZE
*2);
288 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
289 if(copy_len
<(SND_BUFFERSIZE
*2)) memset(stream_buffer
+ copy_len
,0,(SND_BUFFERSIZE
*2) - copy_len
);
291 DCFlushRange(stream_buffer
,(SND_BUFFERSIZE
*2));
293 pb
->mram_curr
+= copy_len
;
294 pb
->flags
|= VOICE_RUNNING
;
298 static void __dsp_initcallback(dsptask_t
*task
)
300 DSP_SendMailTo(0xface0080);
301 while(DSP_CheckMailTo());
303 DSP_SendMailTo(MEM_VIRTUAL_TO_PHYSICAL(&__aesndcommand
));
304 while(DSP_CheckMailTo());
307 __aesnddspcomplete
= 1;
310 static void __dsp_resumecallback(dsptask_t
*task
)
314 static void __dsp_requestcallback(dsptask_t
*task
)
316 if(__aesnddspabrequested
==1) {
317 __aesnddspprocesstime
= (gettime() - __aesnddspstarttime
);
318 __aesnddspabrequested
= 0;
319 __aesnddspcomplete
= 1;
323 DCInvalidateRange(&__aesndcommand
,PB_STRUCT_SIZE
);
325 if(__aesndcommand
.flags
&VOICE_FINISHED
) {
326 __aesndcommand
.flags
&= ~VOICE_FINISHED
;
328 __aesndhandlerequest(&__aesndcommand
);
330 if(__aesndcommand
.flags
&VOICE_STOPPED
&& __aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_STOPPED
);
332 __aesndcopycommand(&__aesndvoicepb
[__aesndcurrvoice
],&__aesndcommand
);
335 while(__aesndcurrvoice
<MAX_VOICES
&& (!(__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_USED
) || (__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_STOPPED
))) __aesndcurrvoice
++;
336 if(__aesndcurrvoice
<MAX_VOICES
) {
337 __aesndcopycommand(&__aesndcommand
,&__aesndvoicepb
[__aesndcurrvoice
]);
339 if(__aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_RUNNING
);
341 DCFlushRange(&__aesndcommand
,PB_STRUCT_SIZE
);
342 DSP_SendMailTo(0xface0020);
343 while(DSP_CheckMailTo());
348 if(__aesndcurrvoice
>=MAX_VOICES
) {
349 DSP_SendMailTo(0xface0100);
350 while(DSP_CheckMailTo());
352 __aesnddspabrequested
= 1;
356 static void __dsp_donecallback(dsptask_t
*task
)
359 __aesnddspcomplete
= 0;
360 __aesnddspabrequested
= 0;
363 static void __audio_dma_callback()
368 if(__aesndglobalpause
==true || __aesndvoicesstopped
==true)
371 ptr
= audio_buffer
[__aesndcurrab
];
373 if(__aesndcommand
.audioCB
) __aesndcommand
.audioCB(ptr
,SND_BUFFERSIZE
);
374 AUDIO_InitDMA((u32
)ptr
,SND_BUFFERSIZE
);
376 if(__aesndglobalpause
==true) return;
377 if(!__aesnddspcomplete
|| !__aesnddspinit
) return;
379 __aesndcurrvoice
= 0;
380 __aesnddspprocesstime
= 0;
381 while(__aesndcurrvoice
<MAX_VOICES
&& (!(__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_USED
) || (__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_STOPPED
))) __aesndcurrvoice
++;
382 if(__aesndcurrvoice
>=MAX_VOICES
) {
383 __aesndvoicesstopped
= true;
387 __aesnddspcomplete
= 0;
388 __aesndvoicesstopped
= false;
389 __aesndcopycommand(&__aesndcommand
,&__aesndvoicepb
[__aesndcurrvoice
]);
391 if(__aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_RUNNING
);
393 __aesndcommand
.out_buf
= (u32
)MEM_VIRTUAL_TO_PHYSICAL(audio_buffer
[__aesndcurrab
]);
394 DCFlushRange(&__aesndcommand
,PB_STRUCT_SIZE
);
396 __aesnddspstarttime
= gettime();
397 DSP_SendMailTo(0xface0010);
398 while(DSP_CheckMailTo());
402 static void __aesndloaddsptask(dsptask_t
*task
,const void *dsp_code
,u32 dsp_code_size
,const void *dram_image
,u32 dram_size
)
405 task
->iram_maddr
= (void*)MEM_VIRTUAL_TO_PHYSICAL(dsp_code
);
406 task
->iram_len
= dsp_code_size
;
407 task
->iram_addr
= 0x0000;
408 task
->dram_maddr
= (void*)MEM_VIRTUAL_TO_PHYSICAL(dram_image
);
409 task
->dram_len
= dram_size
;
410 task
->dram_addr
= 0x0000;
411 task
->init_vec
= 0x0010;
412 task
->res_cb
= __dsp_resumecallback
;
413 task
->req_cb
= __dsp_requestcallback
;
414 task
->init_cb
= __dsp_initcallback
;
415 task
->done_cb
= __dsp_donecallback
;
424 __aesndarambase
= AR_Init(__aesndarammemory
,MAX_VOICES
);
430 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ
);
432 _CPU_ISR_Disable(level
);
437 __aesnddspcomplete
= 0;
438 __aesndglobalpause
= false;
439 __aesndvoicesstopped
= true;
442 for(i
=0;i
<MAX_VOICES
;i
++) __aesndaramblocks
[i
] = AR_Alloc(SND_BUFFERSIZE
*2);
444 snd_set0w((int*)mute_buffer
,SND_BUFFERSIZE
>>2);
445 snd_set0w((int*)stream_buffer
,SND_BUFFERSIZE
>>1);
446 snd_set0w((int*)audio_buffer
[0],SND_BUFFERSIZE
>>2);
447 snd_set0w((int*)audio_buffer
[1],SND_BUFFERSIZE
>>2);
448 DCFlushRange(mute_buffer
,SND_BUFFERSIZE
);
449 DCFlushRange(audio_buffer
[0],SND_BUFFERSIZE
);
450 DCFlushRange(audio_buffer
[1],SND_BUFFERSIZE
);
452 snd_set0w((int*)&__aesndcommand
,sizeof(struct aesndpb_t
)>>2);
453 for(i
=0;i
<MAX_VOICES
;i
++)
454 snd_set0w((int*)&__aesndvoicepb
[i
],sizeof(struct aesndpb_t
)>>2);
456 __aesndloaddsptask(&__aesnddsptask
,dspmixer
,dspmixer_size
,__dspdram
,DSP_DRAMSIZE
);
459 AUDIO_RegisterDMACallback(__audio_dma_callback
);
460 AUDIO_InitDMA((u32
)audio_buffer
[__aesndcurrab
],SND_BUFFERSIZE
);
463 _CPU_ISR_Restore(level
);
470 _CPU_ISR_Disable(level
);
473 AUDIO_RegisterDMACallback(NULL
);
475 DSP_SendMailTo(0xfacedead);
476 while(DSP_CheckMailTo());
479 _CPU_ISR_Flash(level
);
480 } while(__aesnddspinit
);
484 _CPU_ISR_Restore(level
);
487 void AESND_Pause(bool pause
)
491 _CPU_ISR_Disable(level
);
492 __aesndglobalpause
= pause
;
493 _CPU_ISR_Restore(level
);
496 u32
AESND_GetDSPProcessTime()
501 _CPU_ISR_Disable(level
);
502 time
= ticks_to_microsecs(__aesnddspprocesstime
);
503 _CPU_ISR_Restore(level
);
508 f32
AESND_GetDSPProcessUsage()
513 _CPU_ISR_Disable(level
);
514 usage
= (ticks_to_microsecs(__aesnddspprocesstime
)*100)/2000.0f
;
515 _CPU_ISR_Restore(level
);
520 AESNDAudioCallback
AESND_RegisterAudioCallback(AESNDAudioCallback cb
)
523 AESNDAudioCallback aCB
;
525 _CPU_ISR_Disable(level
);
526 aCB
= __aesndcommand
.audioCB
;
527 __aesndcommand
.audioCB
= cb
;
528 _CPU_ISR_Restore(level
);
533 AESNDPB
* AESND_AllocateVoice(AESNDVoiceCallback cb
)
538 _CPU_ISR_Disable(level
);
539 for(i
=0;i
<MAX_VOICES
;i
++) {
540 pb
= &__aesndvoicepb
[i
];
541 if(!(pb
->flags
&VOICE_USED
)) {
543 pb
->flags
= (VOICE_USED
|VOICE_STOPPED
);
544 pb
->pds
= pb
->yn1
= pb
->yn2
= 0;
557 _CPU_ISR_Restore(level
);
562 void AESND_FreeVoice(AESNDPB
*pb
)
566 _CPU_ISR_Disable(level
);
567 snd_set0w((int*)pb
,sizeof(struct aesndpb_t
)>>2);
568 _CPU_ISR_Restore(level
);
571 void AESND_PlayVoice(AESNDPB
*pb
,u32 format
,const void *buffer
,u32 len
,u32 freq
,u32 delay
,bool looped
)
574 void *ptr
= (void*)buffer
;
576 _CPU_ISR_Disable(level
);
577 __aesndsetvoiceformat(pb
,format
);
578 __aesndsetvoicefreq(pb
,freq
);
579 __aesndsetvoicebuffer(pb
,ptr
,len
);
581 pb
->flags
&= ~(VOICE_RUNNING
|VOICE_STOPPED
|VOICE_LOOP
|VOICE_ONCE
);
583 pb
->flags
|= VOICE_LOOP
;
585 pb
->flags
|= VOICE_ONCE
;
587 pb
->buf_start
= pb
->buf_curr
= pb
->buf_end
= pb
->stream_last
= 0;
588 pb
->delay
= (delay
*48);
589 pb
->pds
= pb
->yn1
= pb
->yn2
= 0;
591 _CPU_ISR_Restore(level
);
594 void AESND_SetVoiceBuffer(AESNDPB
*pb
,const void *buffer
,u32 len
)
597 void *ptr
= (void*)buffer
;
599 _CPU_ISR_Disable(level
);
600 __aesndsetvoicebuffer(pb
,ptr
,len
);
601 _CPU_ISR_Restore(level
);
604 void AESND_SetVoiceFormat(AESNDPB
*pb
,u32 format
)
608 _CPU_ISR_Disable(level
);
609 __aesndsetvoiceformat(pb
,format
);
610 _CPU_ISR_Restore(level
);
613 void AESND_SetVoiceVolume(AESNDPB
*pb
,u16 volume_l
,u16 volume_r
)
617 _CPU_ISR_Disable(level
);
618 pb
->volume_l
= volume_l
;
619 pb
->volume_r
= volume_r
;
620 _CPU_ISR_Restore(level
);
623 void AESND_SetVoiceFrequency(AESNDPB
*pb
,u32 freq
)
627 _CPU_ISR_Disable(level
);
628 __aesndsetvoicefreq(pb
,freq
);
629 _CPU_ISR_Restore(level
);
632 void AESND_SetVoiceStream(AESNDPB
*pb
,bool stream
)
636 _CPU_ISR_Disable(level
);
638 pb
->flags
|= VOICE_STREAM
;
640 pb
->flags
&= ~VOICE_STREAM
;
641 _CPU_ISR_Restore(level
);
644 void AESND_SetVoiceLoop(AESNDPB
*pb
,bool loop
)
648 _CPU_ISR_Disable(level
);
650 pb
->flags
|= VOICE_LOOP
;
652 pb
->flags
&= ~VOICE_LOOP
;
653 _CPU_ISR_Restore(level
);
656 void AESND_SetVoiceMute(AESNDPB
*pb
,bool mute
)
660 _CPU_ISR_Disable(level
);
662 pb
->flags
|= VOICE_PAUSE
;
664 pb
->flags
&= ~VOICE_PAUSE
;
665 _CPU_ISR_Restore(level
);
668 void AESND_SetVoiceStop(AESNDPB
*pb
,bool stop
)
672 _CPU_ISR_Disable(level
);
674 pb
->flags
|= VOICE_STOPPED
;
676 pb
->flags
&= ~VOICE_STOPPED
;
677 _CPU_ISR_Restore(level
);
680 AESNDVoiceCallback
AESND_RegisterVoiceCallback(AESNDPB
*pb
,AESNDVoiceCallback cb
)
683 AESNDVoiceCallback rcb
= NULL
;
685 _CPU_ISR_Disable(level
);
688 _CPU_ISR_Restore(level
);