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
[DSP_STREAMBUFFER_SIZE
*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 buf_addr
;
173 buf_addr
= __aesndaramblocks
[pb
->voiceno
];
174 if(buffer
) buf_addr
+= DSP_STREAMBUFFER_SIZE
;
176 copy_len
= (pb
->mram_end
- pb
->mram_curr
);
177 if(copy_len
>DSP_STREAMBUFFER_SIZE
) copy_len
= DSP_STREAMBUFFER_SIZE
;
179 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
180 if(copy_len
<DSP_STREAMBUFFER_SIZE
) memset(stream_buffer
+ copy_len
,0,DSP_STREAMBUFFER_SIZE
- copy_len
);
182 DCFlushRange(stream_buffer
,DSP_STREAMBUFFER_SIZE
);
183 ARQ_PostRequestAsync(&arq_request
[pb
->voiceno
],pb
->voiceno
,ARQ_MRAMTOARAM
,ARQ_PRIO_HI
,buf_addr
,(u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
),DSP_STREAMBUFFER_SIZE
,NULL
);
185 pb
->mram_curr
+= copy_len
;
188 static __inline__
void __aesndhandlerequest(AESNDPB
*pb
)
190 register u32 buf_addr
;
191 register u32 copy_len
;
193 if(pb
->mram_curr
>=pb
->mram_end
) {
194 if(pb
->flags
&VOICE_ONCE
) {
195 pb
->flags
|= VOICE_STOPPED
;
197 } else if(pb
->flags
&VOICE_LOOP
) pb
->mram_curr
= pb
->mram_start
;
198 else if(pb
->cb
) pb
->cb(pb
,VOICE_STATE_STREAM
);
202 register u32 curr_pos
= pb
->buf_curr
;
203 if(curr_pos
<pb
->stream_last
)
204 __aesndfillbuffer(pb
,1);
205 if(curr_pos
>=(pb
->buf_start
+ (DSP_STREAMBUFFER_SIZE
>>pb
->shift
)) &&
206 pb
->stream_last
<(pb
->buf_start
+ (DSP_STREAMBUFFER_SIZE
>>pb
->shift
)))
207 __aesndfillbuffer(pb
,0);
209 pb
->stream_last
= curr_pos
;
213 buf_addr
= __aesndaramblocks
[pb
->voiceno
];
214 pb
->buf_start
= buf_addr
>>pb
->shift
;
215 pb
->buf_end
= (buf_addr
+ (DSP_STREAMBUFFER_SIZE
*2) - (1<<pb
->shift
))>>pb
->shift
;
216 pb
->buf_curr
= pb
->buf_start
;
218 copy_len
= (pb
->mram_end
- pb
->mram_curr
);
219 if(copy_len
>(DSP_STREAMBUFFER_SIZE
*2)) copy_len
= (DSP_STREAMBUFFER_SIZE
*2);
221 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
222 if(copy_len
<(DSP_STREAMBUFFER_SIZE
*2)) memset(stream_buffer
+ copy_len
,0,(DSP_STREAMBUFFER_SIZE
*2) - copy_len
);
224 DCFlushRange(stream_buffer
,(DSP_STREAMBUFFER_SIZE
*2));
225 ARQ_PostRequestAsync(&arq_request
[pb
->voiceno
],pb
->voiceno
,ARQ_MRAMTOARAM
,ARQ_PRIO_HI
,buf_addr
,(u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
),(DSP_STREAMBUFFER_SIZE
*2),__aesndarqcallback
);
227 pb
->mram_curr
+= copy_len
;
229 #elif defined(HW_RVL)
230 static u8 stream_buffer
[MAX_VOICES
][DSP_STREAMBUFFER_SIZE
*2] ATTRIBUTE_ALIGN(32);
232 static void __aesndfillbuffer(AESNDPB
*pb
,u32 buffer
)
234 register u32 copy_len
;
235 register u32 buf_addr
;
237 buf_addr
= (u32
)stream_buffer
[pb
->voiceno
];
238 if(buffer
) buf_addr
+= DSP_STREAMBUFFER_SIZE
;
240 copy_len
= (pb
->mram_end
- pb
->mram_curr
);
241 if(copy_len
>DSP_STREAMBUFFER_SIZE
) copy_len
= DSP_STREAMBUFFER_SIZE
;
243 memcpy((void*)buf_addr
,(void*)pb
->mram_curr
,copy_len
);
244 if(copy_len
<DSP_STREAMBUFFER_SIZE
) memset((void*)(buf_addr
+ copy_len
),0,DSP_STREAMBUFFER_SIZE
- copy_len
);
246 DCFlushRange((void*)buf_addr
,DSP_STREAMBUFFER_SIZE
);
248 pb
->mram_curr
+= copy_len
;
251 static __inline__
void __aesndhandlerequest(AESNDPB
*pb
)
253 register u32 buf_addr
;
254 register u32 copy_len
;
256 if(pb
->mram_curr
>=pb
->mram_end
) {
257 if(pb
->flags
&VOICE_ONCE
) {
259 pb
->flags
|= VOICE_STOPPED
;
261 } else if(pb
->flags
&VOICE_LOOP
) pb
->mram_curr
= pb
->mram_start
;
262 else if(pb
->cb
) pb
->cb(pb
,VOICE_STATE_STREAM
);
266 register u32 curr_pos
= pb
->buf_curr
;
267 if(curr_pos
<pb
->stream_last
)
268 __aesndfillbuffer(pb
,1);
269 if(curr_pos
>=(pb
->buf_start
+ (DSP_STREAMBUFFER_SIZE
>>pb
->shift
)) &&
270 pb
->stream_last
<(pb
->buf_start
+ (DSP_STREAMBUFFER_SIZE
>>pb
->shift
)))
271 __aesndfillbuffer(pb
,0);
273 pb
->stream_last
= curr_pos
;
277 buf_addr
= (u32
)MEM_VIRTUAL_TO_PHYSICAL(stream_buffer
[pb
->voiceno
]);
278 pb
->buf_start
= buf_addr
>>pb
->shift
;
279 pb
->buf_end
= (buf_addr
+ (DSP_STREAMBUFFER_SIZE
*2) - (1<<pb
->shift
))>>pb
->shift
;
280 pb
->buf_curr
= pb
->buf_start
;
282 copy_len
= (pb
->mram_end
- pb
->mram_curr
);
283 if(copy_len
>(DSP_STREAMBUFFER_SIZE
*2)) copy_len
= (DSP_STREAMBUFFER_SIZE
*2);
285 memcpy(stream_buffer
,(void*)pb
->mram_curr
,copy_len
);
286 if(copy_len
<(DSP_STREAMBUFFER_SIZE
*2)) memset(stream_buffer
+ copy_len
,0,(DSP_STREAMBUFFER_SIZE
*2) - copy_len
);
288 DCFlushRange(stream_buffer
,(DSP_STREAMBUFFER_SIZE
*2));
290 pb
->mram_curr
+= copy_len
;
291 pb
->flags
|= VOICE_RUNNING
;
295 static void __dsp_initcallback(dsptask_t
*task
)
297 DSP_SendMailTo(0xface0080);
298 while(DSP_CheckMailTo());
300 DSP_SendMailTo(MEM_VIRTUAL_TO_PHYSICAL(&__aesndcommand
));
301 while(DSP_CheckMailTo());
304 __aesnddspcomplete
= 1;
307 static void __dsp_resumecallback(dsptask_t
*task
)
311 static void __dsp_requestcallback(dsptask_t
*task
)
313 if(__aesnddspabrequested
==1) {
314 __aesnddspprocesstime
= (gettime() - __aesnddspstarttime
);
315 __aesnddspabrequested
= 0;
316 __aesnddspcomplete
= 1;
320 DCInvalidateRange(&__aesndcommand
,PB_STRUCT_SIZE
);
322 if(__aesndcommand
.flags
&VOICE_FINISHED
) {
323 __aesndcommand
.flags
&= ~VOICE_FINISHED
;
325 __aesndhandlerequest(&__aesndcommand
);
327 if(__aesndcommand
.flags
&VOICE_STOPPED
&& __aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_STOPPED
);
329 __aesndcopycommand(&__aesndvoicepb
[__aesndcurrvoice
],&__aesndcommand
);
332 while(__aesndcurrvoice
<MAX_VOICES
&& (!(__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_USED
) || (__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_STOPPED
))) __aesndcurrvoice
++;
333 if(__aesndcurrvoice
<MAX_VOICES
) {
334 __aesndcopycommand(&__aesndcommand
,&__aesndvoicepb
[__aesndcurrvoice
]);
336 if(__aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_RUNNING
);
338 DCFlushRange(&__aesndcommand
,PB_STRUCT_SIZE
);
339 DSP_SendMailTo(0xface0020);
340 while(DSP_CheckMailTo());
345 if(__aesndcurrvoice
>=MAX_VOICES
) {
346 DSP_SendMailTo(0xface0100);
347 while(DSP_CheckMailTo());
349 __aesnddspabrequested
= 1;
353 static void __dsp_donecallback(dsptask_t
*task
)
356 __aesnddspcomplete
= 0;
357 __aesnddspabrequested
= 0;
360 static void __audio_dma_callback()
365 if(__aesndglobalpause
==true || __aesndvoicesstopped
==true)
368 ptr
= audio_buffer
[__aesndcurrab
];
370 if(__aesndcommand
.audioCB
) __aesndcommand
.audioCB(ptr
,SND_BUFFERSIZE
);
371 AUDIO_InitDMA((u32
)ptr
,SND_BUFFERSIZE
);
373 if(__aesndglobalpause
==true) return;
374 if(!__aesnddspcomplete
|| !__aesnddspinit
) return;
376 __aesndcurrvoice
= 0;
377 __aesnddspprocesstime
= 0;
378 while(__aesndcurrvoice
<MAX_VOICES
&& (!(__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_USED
) || (__aesndvoicepb
[__aesndcurrvoice
].flags
&VOICE_STOPPED
))) __aesndcurrvoice
++;
379 if(__aesndcurrvoice
>=MAX_VOICES
) {
380 __aesndvoicesstopped
= true;
384 __aesnddspcomplete
= 0;
385 __aesndvoicesstopped
= false;
386 __aesndcopycommand(&__aesndcommand
,&__aesndvoicepb
[__aesndcurrvoice
]);
388 if(__aesndcommand
.cb
) __aesndcommand
.cb(&__aesndcommand
,VOICE_STATE_RUNNING
);
390 __aesndcommand
.out_buf
= (u32
)MEM_VIRTUAL_TO_PHYSICAL(audio_buffer
[__aesndcurrab
]);
391 DCFlushRange(&__aesndcommand
,PB_STRUCT_SIZE
);
393 __aesnddspstarttime
= gettime();
394 DSP_SendMailTo(0xface0010);
395 while(DSP_CheckMailTo());
399 static void __aesndloaddsptask(dsptask_t
*task
,const void *dsp_code
,u32 dsp_code_size
,const void *dram_image
,u32 dram_size
)
402 task
->iram_maddr
= (void*)MEM_VIRTUAL_TO_PHYSICAL(dsp_code
);
403 task
->iram_len
= dsp_code_size
;
404 task
->iram_addr
= 0x0000;
405 task
->dram_maddr
= (void*)MEM_VIRTUAL_TO_PHYSICAL(dram_image
);
406 task
->dram_len
= dram_size
;
407 task
->dram_addr
= 0x0000;
408 task
->init_vec
= 0x0010;
409 task
->res_cb
= __dsp_resumecallback
;
410 task
->req_cb
= __dsp_requestcallback
;
411 task
->init_cb
= __dsp_initcallback
;
412 task
->done_cb
= __dsp_donecallback
;
421 __aesndarambase
= AR_Init(__aesndarammemory
,MAX_VOICES
);
427 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ
);
429 _CPU_ISR_Disable(level
);
434 __aesnddspcomplete
= 0;
435 __aesndglobalpause
= false;
436 __aesndvoicesstopped
= true;
439 for(i
=0;i
<MAX_VOICES
;i
++) __aesndaramblocks
[i
] = AR_Alloc(DSP_STREAMBUFFER_SIZE
*2);
441 snd_set0w((int*)mute_buffer
,SND_BUFFERSIZE
>>2);
442 snd_set0w((int*)stream_buffer
,SND_BUFFERSIZE
>>1);
443 snd_set0w((int*)audio_buffer
[0],SND_BUFFERSIZE
>>2);
444 snd_set0w((int*)audio_buffer
[1],SND_BUFFERSIZE
>>2);
445 DCFlushRange(mute_buffer
,SND_BUFFERSIZE
);
446 DCFlushRange(audio_buffer
[0],SND_BUFFERSIZE
);
447 DCFlushRange(audio_buffer
[1],SND_BUFFERSIZE
);
449 snd_set0w((int*)&__aesndcommand
,sizeof(struct aesndpb_t
)>>2);
450 for(i
=0;i
<MAX_VOICES
;i
++)
451 snd_set0w((int*)&__aesndvoicepb
[i
],sizeof(struct aesndpb_t
)>>2);
453 __aesndloaddsptask(&__aesnddsptask
,dspmixer
,dspmixer_size
,__dspdram
,DSP_DRAMSIZE
);
456 AUDIO_RegisterDMACallback(__audio_dma_callback
);
457 AUDIO_InitDMA((u32
)audio_buffer
[__aesndcurrab
],SND_BUFFERSIZE
);
460 _CPU_ISR_Restore(level
);
467 _CPU_ISR_Disable(level
);
470 AUDIO_RegisterDMACallback(NULL
);
472 DSP_SendMailTo(0xfacedead);
473 while(DSP_CheckMailTo());
476 _CPU_ISR_Flash(level
);
477 } while(__aesnddspinit
);
481 _CPU_ISR_Restore(level
);
484 void AESND_Pause(bool pause
)
488 _CPU_ISR_Disable(level
);
489 __aesndglobalpause
= pause
;
490 _CPU_ISR_Restore(level
);
493 u32
AESND_GetDSPProcessTime()
498 _CPU_ISR_Disable(level
);
499 time
= ticks_to_microsecs(__aesnddspprocesstime
);
500 _CPU_ISR_Restore(level
);
505 f32
AESND_GetDSPProcessUsage()
510 _CPU_ISR_Disable(level
);
511 usage
= (ticks_to_microsecs(__aesnddspprocesstime
)*100)/2000.0f
;
512 _CPU_ISR_Restore(level
);
517 AESNDAudioCallback
AESND_RegisterAudioCallback(AESNDAudioCallback cb
)
520 AESNDAudioCallback aCB
;
522 _CPU_ISR_Disable(level
);
523 aCB
= __aesndcommand
.audioCB
;
524 __aesndcommand
.audioCB
= cb
;
525 _CPU_ISR_Restore(level
);
530 AESNDPB
* AESND_AllocateVoice(AESNDVoiceCallback cb
)
535 _CPU_ISR_Disable(level
);
536 for(i
=0;i
<MAX_VOICES
;i
++) {
537 pb
= &__aesndvoicepb
[i
];
538 if(!(pb
->flags
&VOICE_USED
)) {
540 pb
->flags
= (VOICE_USED
|VOICE_STOPPED
);
541 pb
->pds
= pb
->yn1
= pb
->yn2
= 0;
554 _CPU_ISR_Restore(level
);
559 void AESND_FreeVoice(AESNDPB
*pb
)
563 _CPU_ISR_Disable(level
);
564 snd_set0w((int*)pb
,sizeof(struct aesndpb_t
)>>2);
565 _CPU_ISR_Restore(level
);
568 void AESND_PlayVoice(AESNDPB
*pb
,u32 format
,const void *buffer
,u32 len
,u32 freq
,u32 delay
,bool looped
)
571 void *ptr
= (void*)buffer
;
573 _CPU_ISR_Disable(level
);
574 __aesndsetvoiceformat(pb
,format
);
575 __aesndsetvoicefreq(pb
,freq
);
576 __aesndsetvoicebuffer(pb
,ptr
,len
);
578 pb
->flags
&= ~(VOICE_RUNNING
|VOICE_STOPPED
|VOICE_LOOP
|VOICE_ONCE
);
580 pb
->flags
|= VOICE_LOOP
;
582 pb
->flags
|= VOICE_ONCE
;
584 pb
->buf_start
= pb
->buf_curr
= pb
->buf_end
= pb
->stream_last
= 0;
585 pb
->delay
= (delay
*48);
586 pb
->pds
= pb
->yn1
= pb
->yn2
= 0;
588 _CPU_ISR_Restore(level
);
591 void AESND_SetVoiceBuffer(AESNDPB
*pb
,const void *buffer
,u32 len
)
594 void *ptr
= (void*)buffer
;
596 _CPU_ISR_Disable(level
);
597 __aesndsetvoicebuffer(pb
,ptr
,len
);
598 _CPU_ISR_Restore(level
);
601 void AESND_SetVoiceFormat(AESNDPB
*pb
,u32 format
)
605 _CPU_ISR_Disable(level
);
606 __aesndsetvoiceformat(pb
,format
);
607 _CPU_ISR_Restore(level
);
610 void AESND_SetVoiceVolume(AESNDPB
*pb
,u16 volume_l
,u16 volume_r
)
614 _CPU_ISR_Disable(level
);
615 pb
->volume_l
= volume_l
;
616 pb
->volume_r
= volume_r
;
617 _CPU_ISR_Restore(level
);
620 void AESND_SetVoiceFrequency(AESNDPB
*pb
,u32 freq
)
624 _CPU_ISR_Disable(level
);
625 __aesndsetvoicefreq(pb
,freq
);
626 _CPU_ISR_Restore(level
);
629 void AESND_SetVoiceStream(AESNDPB
*pb
,bool stream
)
633 _CPU_ISR_Disable(level
);
635 pb
->flags
|= VOICE_STREAM
;
637 pb
->flags
&= ~VOICE_STREAM
;
638 _CPU_ISR_Restore(level
);
641 void AESND_SetVoiceLoop(AESNDPB
*pb
,bool loop
)
645 _CPU_ISR_Disable(level
);
647 pb
->flags
|= VOICE_LOOP
;
649 pb
->flags
&= ~VOICE_LOOP
;
650 _CPU_ISR_Restore(level
);
653 void AESND_SetVoiceMute(AESNDPB
*pb
,bool mute
)
657 _CPU_ISR_Disable(level
);
659 pb
->flags
|= VOICE_PAUSE
;
661 pb
->flags
&= ~VOICE_PAUSE
;
662 _CPU_ISR_Restore(level
);
665 void AESND_SetVoiceStop(AESNDPB
*pb
,bool stop
)
669 _CPU_ISR_Disable(level
);
671 pb
->flags
|= VOICE_STOPPED
;
673 pb
->flags
&= ~VOICE_STOPPED
;
674 _CPU_ISR_Restore(level
);
677 AESNDVoiceCallback
AESND_RegisterVoiceCallback(AESNDPB
*pb
,AESNDVoiceCallback cb
)
680 AESNDVoiceCallback rcb
= NULL
;
682 _CPU_ISR_Disable(level
);
685 _CPU_ISR_Restore(level
);