changes from dhewg
[libogc.git] / libaesnd / aesndlib.c
blob923f833cd4e4c34d70eb5c9eb37ba6847680f3fc
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <ogcsys.h>
5 #include <gccore.h>
6 #include <ogc/lwp_watchdog.h>
7 #include <ogc/machine/processor.h>
9 #include "aesndlib.h"
10 #include "dspmixer.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
25 struct aesndpb_t
27 u32 out_buf; //0
29 u32 buf_start; //4
30 u32 buf_end; //8
31 u32 buf_curr; //12
33 u16 yn1; //16
34 u16 yn2; //18
35 u16 pds; //20
37 u16 freq_h; //22
38 u16 freq_l; //24
39 u16 counter; //26
41 s16 left,right; //28,30
42 u16 volume_l,volume_r; //32,34
44 u32 delay; //36
46 u32 flags; //40
48 u8 _pad[20];
50 u32 mram_start;
51 u32 mram_curr;
52 u32 mram_end;
53 u32 stream_last;
55 u32 voiceno;
56 u32 shift;
57 AESNDVoiceCallback cb;
59 AESNDAudioCallback audioCB;
60 } ATTRIBUTE_PACKED;
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;
75 #if defined(HW_DOL)
76 static u32 __aesndarambase = 0;
77 static u32 __aesndaramblocks[MAX_VOICES];
78 static u32 __aesndarammemory[MAX_VOICES];
79 #endif
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;
103 dst->yn1 = src->yn1;
104 dst->yn2 = src->yn2;
105 dst->pds = src->pds;
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;
127 dst->cb = src->cb;
130 static __inline__ void __aesndsetvoiceformat(AESNDPB *pb,u32 format)
132 pb->flags = (pb->flags&~0x03)|(format&0x03);
133 switch((format&0x03)) {
134 case VOICE_MONO8:
135 case VOICE_STEREO8:
136 pb->shift = 0;
137 break;
138 case VOICE_MONO16:
139 case VOICE_STEREO16:
140 pb->shift = 1;
141 break;
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);
159 #if defined(HW_DOL)
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;
198 return;
199 } else if(pb->flags&VOICE_LOOP) pb->mram_curr = pb->mram_start;
200 else if(pb->cb) pb->cb(pb,VOICE_STATE_STREAM);
203 if(pb->buf_start) {
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;
212 return;
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;
263 return;
264 } else if(pb->flags&VOICE_LOOP) pb->mram_curr = pb->mram_start;
265 else if(pb->cb) pb->cb(pb,VOICE_STATE_STREAM);
268 if(pb->buf_start) {
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;
277 return;
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;
296 #endif
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());
306 __aesnddspinit = 1;
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;
320 return;
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);
334 __aesndcurrvoice++;
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());
344 return;
348 if(__aesndcurrvoice>=MAX_VOICES) {
349 DSP_SendMailTo(0xface0100);
350 while(DSP_CheckMailTo());
352 __aesnddspabrequested = 1;
356 static void __dsp_donecallback(dsptask_t *task)
358 __aesnddspinit = 0;
359 __aesnddspcomplete = 0;
360 __aesnddspabrequested = 0;
363 static void __audio_dma_callback()
365 void *ptr;
367 __aesndcurrab ^= 1;
368 if(__aesndglobalpause==true || __aesndvoicesstopped==true)
369 ptr = mute_buffer;
370 else
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;
384 return;
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)
404 task->prio = 255;
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;
416 DSP_AddTask(task);
419 void AESND_Init()
421 u32 i,level;
423 #if defined(HW_DOL)
424 __aesndarambase = AR_Init(__aesndarammemory,MAX_VOICES);
425 ARQ_Init();
426 #endif
427 DSP_Init();
428 AUDIO_Init(NULL);
429 AUDIO_StopDMA();
430 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
432 _CPU_ISR_Disable(level);
433 if(!__aesndinit) {
434 __aesndinit = 1;
435 __aesndcurrab = 0;
436 __aesnddspinit = 0;
437 __aesnddspcomplete = 0;
438 __aesndglobalpause = false;
439 __aesndvoicesstopped = true;
441 #if defined(HW_DOL)
442 for(i=0;i<MAX_VOICES;i++) __aesndaramblocks[i] = AR_Alloc(SND_BUFFERSIZE*2);
443 #endif
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);
461 AUDIO_StartDMA();
463 _CPU_ISR_Restore(level);
466 void AESND_Reset()
468 u32 level;
470 _CPU_ISR_Disable(level);
471 if(__aesndinit) {
472 AUDIO_StopDMA();
473 AUDIO_RegisterDMACallback(NULL);
475 DSP_SendMailTo(0xfacedead);
476 while(DSP_CheckMailTo());
478 do {
479 _CPU_ISR_Flash(level);
480 } while(__aesnddspinit);
482 __aesndinit = 0;
484 _CPU_ISR_Restore(level);
487 void AESND_Pause(bool pause)
489 u32 level;
491 _CPU_ISR_Disable(level);
492 __aesndglobalpause = pause;
493 _CPU_ISR_Restore(level);
496 u32 AESND_GetDSPProcessTime()
498 u32 level;
499 u32 time = 0;
501 _CPU_ISR_Disable(level);
502 time = ticks_to_microsecs(__aesnddspprocesstime);
503 _CPU_ISR_Restore(level);
505 return time;
508 f32 AESND_GetDSPProcessUsage()
510 u32 level;
511 f32 usage = 0.0f;
513 _CPU_ISR_Disable(level);
514 usage = (ticks_to_microsecs(__aesnddspprocesstime)*100)/2000.0f;
515 _CPU_ISR_Restore(level);
517 return usage;
520 AESNDAudioCallback AESND_RegisterAudioCallback(AESNDAudioCallback cb)
522 u32 level;
523 AESNDAudioCallback aCB;
525 _CPU_ISR_Disable(level);
526 aCB = __aesndcommand.audioCB;
527 __aesndcommand.audioCB = cb;
528 _CPU_ISR_Restore(level);
530 return aCB;
533 AESNDPB* AESND_AllocateVoice(AESNDVoiceCallback cb)
535 u32 i,level;
536 AESNDPB *pb = NULL;
538 _CPU_ISR_Disable(level);
539 for(i=0;i<MAX_VOICES;i++) {
540 pb = &__aesndvoicepb[i];
541 if(!(pb->flags&VOICE_USED)) {
542 pb->voiceno = i;
543 pb->flags = (VOICE_USED|VOICE_STOPPED);
544 pb->pds = pb->yn1 = pb->yn2 = 0;
545 pb->buf_start = 0;
546 pb->buf_curr = 0;
547 pb->buf_end = 0;
548 pb->counter = 0;
549 pb->volume_l = 255;
550 pb->volume_r = 255;
551 pb->freq_h = 0x0001;
552 pb->freq_l = 0x0000;
553 pb->cb = cb;
554 break;
557 _CPU_ISR_Restore(level);
559 return pb;
562 void AESND_FreeVoice(AESNDPB *pb)
564 u32 level;
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)
573 u32 level;
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);
582 if(looped==true)
583 pb->flags |= VOICE_LOOP;
584 else
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;
590 pb->counter = 0;
591 _CPU_ISR_Restore(level);
594 void AESND_SetVoiceBuffer(AESNDPB *pb,const void *buffer,u32 len)
596 u32 level;
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)
606 u32 level;
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)
615 u32 level;
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)
625 u32 level;
627 _CPU_ISR_Disable(level);
628 __aesndsetvoicefreq(pb,freq);
629 _CPU_ISR_Restore(level);
632 void AESND_SetVoiceStream(AESNDPB *pb,bool stream)
634 u32 level;
636 _CPU_ISR_Disable(level);
637 if(stream==true)
638 pb->flags |= VOICE_STREAM;
639 else
640 pb->flags &= ~VOICE_STREAM;
641 _CPU_ISR_Restore(level);
644 void AESND_SetVoiceLoop(AESNDPB *pb,bool loop)
646 u32 level;
648 _CPU_ISR_Disable(level);
649 if(loop==true)
650 pb->flags |= VOICE_LOOP;
651 else
652 pb->flags &= ~VOICE_LOOP;
653 _CPU_ISR_Restore(level);
656 void AESND_SetVoiceMute(AESNDPB *pb,bool mute)
658 u32 level;
660 _CPU_ISR_Disable(level);
661 if(mute==true)
662 pb->flags |= VOICE_PAUSE;
663 else
664 pb->flags &= ~VOICE_PAUSE;
665 _CPU_ISR_Restore(level);
668 void AESND_SetVoiceStop(AESNDPB *pb,bool stop)
670 u32 level;
672 _CPU_ISR_Disable(level);
673 if(stop==true)
674 pb->flags |= VOICE_STOPPED;
675 else
676 pb->flags &= ~VOICE_STOPPED;
677 _CPU_ISR_Restore(level);
680 AESNDVoiceCallback AESND_RegisterVoiceCallback(AESNDPB *pb,AESNDVoiceCallback cb)
682 u32 level;
683 AESNDVoiceCallback rcb = NULL;
685 _CPU_ISR_Disable(level);
686 rcb = pb->cb;
687 pb->cb = cb;
688 _CPU_ISR_Restore(level);
690 return rcb;