silence some warnings (dhewg)
[libogc.git] / libasnd / asndlib.c
blob33cb9cd6cbf74ac71d6b20483fa38b9bcfd2a0f0
1 /* ASNDLIB -> accelerated sound lib using the DSP
3 Copyright (c) 2008 Hermes <www.entuwii.net>
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without modification, are
7 permitted provided that the following conditions are met:
9 - Redistributions of source code must retain the above copyright notice, this list of
10 conditions and the following disclaimer.
11 - Redistributions in binary form must reproduce the above copyright notice, this list
12 of conditions and the following disclaimer in the documentation and/or other
13 materials provided with the distribution.
14 - The names of the contributors may not be used to endorse or promote products derived
15 from this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <stdio.h>
30 #include <unistd.h>
32 #include <ogcsys.h>
33 #include <gccore.h>
34 #include <ogc/lwp_watchdog.h>
35 #include <ogc/machine/processor.h>
37 #include "asndlib.h"
38 #include "dsp_mixer.h"
40 #undef SND_BUFFERSIZE
42 #define MAX_SND_VOICES 16
43 #define SND_BUFFERSIZE (4096) // don't modify this value
45 #define VOICE_UPDATEADD (1<<12)
46 #define VOICE_UPDATE (1<<11)
47 #define VOICE_VOLUPDATE (1<<10)
48 #define VOICE_PAUSE (1<<9)
49 #define VOICE_SETLOOP (1<<8)
51 typedef struct
53 void *out_buf; // output buffer 4096 bytes aligned to 32
55 u32 delay_samples; // samples per delay to start (48000 == 1sec)
57 u32 flags; // (step<<16) | (statuses<<8) | (type & 7) used in DSP side
59 u32 start_addr; // internal addr counter
60 u32 end_addr; // end voice physical pointer(bytes without alignament, but remember it reads in blocks of 32 bytes (use padding to the end))
62 u32 freq; // freq operation
64 s16 left, right; // internally used to store de last sample played
66 u32 counter; // internally used to convert freq to 48000Hz samples
68 u16 volume_l,volume_r; // volume (from 0 to 256)
70 u32 start_addr2; // initial voice2 physical pointer (bytes aligned 32 bytes) (to do a ring)
71 u32 end_addr2; // end voice2 physical pointer(bytes without alignament, but remember it reads in blocks of 32 bytes (use padding to the end))
73 u16 volume2_l,volume2_r; // volume (from 0 to 256) for voice 2
75 u32 backup_addr; // initial voice physical pointer backup (bytes aligned to 32 bytes): It is used for test pointers purpose
77 u32 tick_counter; // voice tick counter
79 ASNDVoiceCallback cb;
81 u32 _pad;
82 } t_sound_data;
84 static dsptask_t dsp_task;
86 static vu64 time_of_process;
87 static vu32 dsp_complete = 1;
88 static vu64 dsp_task_starttime = 0;
89 static vu32 curr_audio_buf = 0;
90 static vu32 dsp_done = 0;
92 static vs32 snd_chan = 0;
93 static vs32 global_pause = 1;
94 static vu32 global_counter = 0;
96 static vu32 DSP_DI_HANDLER = 1;
97 static void (*global_callback)()=NULL;
99 static u32 asnd_inited = 0;
100 static t_sound_data sound_data[MAX_SND_VOICES];
102 static t_sound_data sound_data_dma ATTRIBUTE_ALIGN(32);
103 static s16 mute_buf[SND_BUFFERSIZE] ATTRIBUTE_ALIGN(32);
104 static s16 audio_buf[2][SND_BUFFERSIZE] ATTRIBUTE_ALIGN(32);
106 extern u32 gettick();
108 static __inline__ char* snd_set0b( char *p, int n)
110 while(n>0) {*p++=0;n--;}
111 return p;
114 static __inline__ s32* snd_set0w( s32 *p, int n)
116 while(n>0) {*p++=0;n--;}
117 return p;
120 static void __dsp_initcallback(dsptask_t *task)
122 DSP_SendMailTo(0x0123); // command to fix the data operation
123 while(DSP_CheckMailTo());
125 DSP_SendMailTo(MEM_VIRTUAL_TO_PHYSICAL((&sound_data_dma))); //send the data operation mem
126 while(DSP_CheckMailTo());
128 dsp_complete=1;
129 DSP_DI_HANDLER=0;
132 static void __dsp_requestcallback(dsptask_t *task)
134 s32 n;
136 if(DSP_DI_HANDLER) return;
138 DCInvalidateRange(&sound_data_dma, sizeof(t_sound_data));
140 if(snd_chan>=MAX_SND_VOICES) {
141 if(!dsp_complete) time_of_process = (gettime() - dsp_task_starttime);
142 if(!global_pause) global_counter++;
144 dsp_complete = 1;
145 return;
148 sound_data_dma.freq=sound_data[snd_chan].freq;
149 sound_data_dma.cb=sound_data[snd_chan].cb;
150 if(sound_data[snd_chan].flags & VOICE_UPDATE) // new song
152 sound_data[snd_chan].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
153 //sound_data[snd_chan].out_buf= (void *) MEM_VIRTUAL_TO_PHYSICAL((void *) audio_buf[curr_audio_buf]);
154 sound_data_dma=sound_data[snd_chan];
156 else
159 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
161 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
162 sound_data_dma.volume_l=sound_data_dma.volume2_l=sound_data[snd_chan].volume2_l;
163 sound_data_dma.volume_r=sound_data_dma.volume2_r=sound_data[snd_chan].volume2_r;
167 //if(mail==0xbebe0003) sound_data_dma.flags|=VOICE_SETCALLBACK;
169 if(sound_data_dma.start_addr>=sound_data_dma.end_addr || !sound_data_dma.start_addr)
171 sound_data_dma.backup_addr=sound_data_dma.start_addr=sound_data_dma.start_addr2;
172 sound_data_dma.end_addr=sound_data_dma.end_addr2;
173 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data_dma.start_addr2=0;sound_data_dma.end_addr2=0;}
174 sound_data_dma.volume_l=sound_data_dma.volume2_l;
175 sound_data_dma.volume_r=sound_data_dma.volume2_r;
178 if(sound_data[snd_chan].start_addr2 && (sound_data[snd_chan].flags & VOICE_UPDATEADD))
180 sound_data[snd_chan].flags &=~VOICE_UPDATEADD;
181 if(!sound_data[snd_chan].start_addr || !sound_data_dma.start_addr)
183 sound_data_dma.backup_addr=sound_data_dma.start_addr=sound_data[snd_chan].start_addr2;
184 sound_data_dma.end_addr=sound_data[snd_chan].end_addr2;
185 sound_data_dma.start_addr2=sound_data[snd_chan].start_addr2;
186 sound_data_dma.end_addr2=sound_data[snd_chan].end_addr2;
187 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data_dma.start_addr2=0;sound_data_dma.end_addr2=0;}
188 sound_data_dma.volume_l=sound_data[snd_chan].volume2_l;
189 sound_data_dma.volume_r=sound_data[snd_chan].volume2_r;
191 else
193 sound_data_dma.start_addr2=sound_data[snd_chan].start_addr2;
194 sound_data_dma.end_addr2=sound_data[snd_chan].end_addr2;
195 sound_data_dma.volume2_l=sound_data[snd_chan].volume2_l;
196 sound_data_dma.volume2_r=sound_data[snd_chan].volume2_r;
201 if(!sound_data[snd_chan].cb && (!sound_data_dma.start_addr && !sound_data_dma.start_addr2)) sound_data[snd_chan].flags=0;
202 sound_data_dma.flags=sound_data[snd_chan].flags & ~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_UPDATEADD);
203 sound_data[snd_chan]=sound_data_dma;
206 if(sound_data[snd_chan].flags>>16)
208 if(!sound_data[snd_chan].delay_samples && !(sound_data[snd_chan].flags & VOICE_PAUSE) && (sound_data_dma.start_addr || sound_data_dma.start_addr2)) sound_data[snd_chan].tick_counter++;
211 snd_chan++;
213 if(!sound_data[snd_chan].cb && (!sound_data[snd_chan].start_addr && !sound_data[snd_chan].start_addr2)) sound_data[snd_chan].flags=0;
215 while(snd_chan<16 && !(sound_data[snd_chan].flags>>16)) snd_chan++;
217 if(snd_chan>=MAX_SND_VOICES)
219 snd_chan++;
220 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
221 DSP_SendMailTo(0x666);
222 while(DSP_CheckMailTo());
223 return;
226 sound_data_dma=sound_data[snd_chan];
228 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
229 DSP_SendMailTo(0x222); // send the voice and mix the samples of the buffer
230 while(DSP_CheckMailTo());
232 // callback strategy for next channel
233 n=snd_chan+1;
235 while(n<16 && !(sound_data[n].flags>>16)) n++;
237 if(n<16)
239 if(!sound_data[n].start_addr2 && (sound_data[n].flags>>16) && sound_data[n].cb) sound_data[n].cb(n);
241 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
243 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
246 if(sound_data[n].flags & VOICE_UPDATE) // new song
248 sound_data[n].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
251 if(!sound_data[n].cb && (!sound_data[n].start_addr && !sound_data[n].start_addr2)) sound_data[n].flags=0;
255 static void __dsp_donecallback(dsptask_t *task)
257 dsp_done = 1;
260 static void audio_dma_callback()
262 u32 n;
264 curr_audio_buf ^= 1;
266 if(DSP_DI_HANDLER || global_pause)
267 AUDIO_InitDMA((u32)mute_buf,SND_BUFFERSIZE);
268 else
269 AUDIO_InitDMA((u32)audio_buf[curr_audio_buf],SND_BUFFERSIZE);
271 if(DSP_DI_HANDLER || global_pause) return;
272 if(dsp_complete==0) return;
274 dsp_complete = 0;
276 for(n=0;n<MAX_SND_VOICES;n++) sound_data[n].out_buf = (void *)MEM_VIRTUAL_TO_PHYSICAL((void *)audio_buf[curr_audio_buf]);
278 if(global_callback) global_callback();
280 snd_chan = 0;
281 if(!sound_data[snd_chan].start_addr2 && (sound_data[snd_chan].flags>>16) && sound_data[snd_chan].cb) sound_data[snd_chan].cb(snd_chan);
283 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
285 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
288 if(sound_data[snd_chan].flags & VOICE_UPDATE) // new song
290 sound_data[snd_chan].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
292 else
295 if(sound_data[snd_chan].start_addr>=sound_data[snd_chan].end_addr)
297 sound_data[snd_chan].backup_addr=sound_data[snd_chan].start_addr=sound_data[snd_chan].start_addr2;sound_data[snd_chan].start_addr2=0;
298 sound_data[snd_chan].end_addr=sound_data[snd_chan].end_addr2;sound_data[snd_chan].end_addr2=0;
299 sound_data[snd_chan].volume_l=sound_data[snd_chan].volume2_l;
300 sound_data[snd_chan].volume_r=sound_data[snd_chan].volume2_r;
303 if(sound_data[snd_chan].start_addr2 && (sound_data[snd_chan].flags & VOICE_UPDATEADD))
305 sound_data[snd_chan].flags &=~VOICE_UPDATEADD;
307 if(!sound_data[snd_chan].start_addr)
309 sound_data[snd_chan].backup_addr=sound_data[snd_chan].start_addr=sound_data[snd_chan].start_addr2;
310 sound_data[snd_chan].end_addr=sound_data[snd_chan].end_addr2;
311 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data[snd_chan].start_addr2=0;sound_data[snd_chan].end_addr2=0;}
312 sound_data[snd_chan].volume_l=sound_data[snd_chan].volume2_l;
313 sound_data[snd_chan].volume_r=sound_data[snd_chan].volume2_r;
319 if(!sound_data[snd_chan].cb && (!sound_data[snd_chan].start_addr && !sound_data[snd_chan].start_addr2)) sound_data[snd_chan].flags=0;
321 sound_data_dma=sound_data[snd_chan];
322 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
324 dsp_task_starttime = gettime();
325 DSP_SendMailTo(0x111); // send the first voice and clear the buffer
326 while(DSP_CheckMailTo());
328 // callback strategy for next channel
329 n=snd_chan+1;
331 while(n<16 && !(sound_data[n].flags>>16)) n++;
333 if(n<16)
335 if(!sound_data[n].start_addr2 && (sound_data[n].flags>>16) && sound_data[n].cb) sound_data[n].cb(n);
337 if(sound_data[n].flags & (VOICE_VOLUPDATE | VOICE_UPDATEADD))
339 sound_data[n].flags &=~(VOICE_VOLUPDATE | VOICE_UPDATEADD);
342 if(sound_data[n].flags & VOICE_UPDATE) // new song
344 sound_data[n].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE| VOICE_PAUSE | VOICE_UPDATEADD);
347 if(!sound_data[n].cb && (!sound_data[n].start_addr && !sound_data[n].start_addr2)) sound_data[n].flags=0;
351 void ASND_Init()
353 u32 i,level;
355 DSP_Init();
356 AUDIO_Init(NULL);
357 AUDIO_StopDMA(); // in case audio was previously inited and a DMA callback set
358 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
360 _CPU_ISR_Disable(level);
361 if(!asnd_inited) {
362 asnd_inited = 1;
363 global_pause = 1;
364 curr_audio_buf = 0;
365 DSP_DI_HANDLER = 1;
366 dsp_complete = 0;
367 dsp_done = 0;
369 snd_set0w((s32*)mute_buf, SND_BUFFERSIZE>>2);
370 snd_set0w((s32*)audio_buf[0], SND_BUFFERSIZE>>2);
371 snd_set0w((s32*)audio_buf[1], SND_BUFFERSIZE>>2);
372 DCFlushRange(mute_buf,SND_BUFFERSIZE);
373 DCFlushRange(audio_buf[0],SND_BUFFERSIZE);
374 DCFlushRange(audio_buf[1],SND_BUFFERSIZE);
376 for(i=0;i<MAX_SND_VOICES;i++)
377 snd_set0w((s32*)&sound_data[i],sizeof(t_sound_data)/4);
379 dsp_task.prio = 255;
380 dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(dsp_mixer);
381 dsp_task.iram_len = dsp_mixer_size;
382 dsp_task.iram_addr = 0x0000;
383 dsp_task.init_vec = 0x10;
384 dsp_task.res_cb = NULL;
385 dsp_task.req_cb = __dsp_requestcallback;
386 dsp_task.init_cb =__dsp_initcallback;
387 dsp_task.done_cb =__dsp_donecallback;
388 DSP_AddTask(&dsp_task);
390 AUDIO_RegisterDMACallback(audio_dma_callback);
391 AUDIO_InitDMA((u32)audio_buf[curr_audio_buf],SND_BUFFERSIZE);
392 AUDIO_StartDMA();
394 _CPU_ISR_Restore(level);
397 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
399 void ASND_End()
401 if(asnd_inited) {
402 AUDIO_StopDMA();
403 DSP_DI_HANDLER=1;
404 usleep(100);
405 AUDIO_RegisterDMACallback(NULL);
406 DSP_DI_HANDLER=1;
407 dsp_done = 0;
408 DSP_SendMailTo(0x999);
409 while(DSP_CheckMailTo());
410 while(!dsp_done);
411 asnd_inited=0;
415 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
417 s32 ASND_SetVoice(s32 voice, s32 format, s32 pitch,s32 delay, void *snd, s32 size_snd, s32 volume_l, s32 volume_r, ASNDVoiceCallback callback)
419 u32 level;
420 u32 flag_h=0;
422 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
424 if(size_snd<=0 || snd==NULL) return SND_INVALID; // invalid voice
426 DCFlushRange(snd, size_snd);
428 if(pitch<1) pitch=1;
429 if(pitch>MAX_PITCH) pitch=MAX_PITCH;
431 volume_l &=255;
432 volume_r &=255;
434 delay=(u32) (48000LL*((u64) delay)/1000LL);
436 format&=7;
438 switch(format&3)
440 case 0:
441 flag_h=1<<16;break;
442 case 1:
443 case 2:
444 flag_h=2<<16;break;
445 case 3:
446 flag_h=4<<16;break;
449 format|= flag_h | VOICE_UPDATE;
451 _CPU_ISR_Disable(level);
453 sound_data[voice].left=0;
454 sound_data[voice].right=0;
455 sound_data[voice].counter=0;
457 sound_data[voice].freq=pitch;
459 sound_data[voice].delay_samples=delay;
461 sound_data[voice].volume_l= volume_l;
462 sound_data[voice].volume_r= volume_r;
464 sound_data[voice].backup_addr=sound_data[voice].start_addr=MEM_VIRTUAL_TO_PHYSICAL(snd);
465 sound_data[voice].end_addr=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
467 sound_data[voice].start_addr2=0;
468 sound_data[voice].end_addr2=0;
470 sound_data[voice].volume2_l= volume_l;
471 sound_data[voice].volume2_r= volume_r;
473 sound_data[voice].flags=format;
474 sound_data[voice].tick_counter=0;
476 sound_data[voice].cb = callback;
477 _CPU_ISR_Restore(level);
479 return SND_OK;
482 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
484 s32 ASND_SetInfiniteVoice(s32 voice, s32 format, s32 pitch,s32 delay, void *snd, s32 size_snd, s32 volume_l, s32 volume_r)
486 u32 level;
487 u32 flag_h=0;
489 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
491 if(size_snd<=0 || snd==NULL) return SND_INVALID; // invalid voice
493 DCFlushRange(snd, size_snd);
495 if(pitch<1) pitch=1;
496 if(pitch>MAX_PITCH) pitch=MAX_PITCH;
498 volume_l &=255;
499 volume_r &=255;
501 delay=(u32) (48000LL*((u64) delay)/1000LL);
503 format&=7;
505 switch(format&3)
507 case 0:
508 flag_h=1<<16;break;
509 case 1:
510 case 2:
511 flag_h=2<<16;break;
512 case 3:
513 flag_h=4<<16;break;
516 format|= flag_h | VOICE_UPDATE | VOICE_SETLOOP;
518 _CPU_ISR_Disable(level);
520 sound_data[voice].left=0;
521 sound_data[voice].right=0;
522 sound_data[voice].counter=0;
524 sound_data[voice].freq=pitch;
526 sound_data[voice].delay_samples=delay;
528 sound_data[voice].volume_l= volume_l;
529 sound_data[voice].volume_r= volume_r;
531 sound_data[voice].backup_addr=sound_data[voice].start_addr=MEM_VIRTUAL_TO_PHYSICAL(snd);
532 sound_data[voice].end_addr=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
534 sound_data[voice].start_addr2=sound_data[voice].start_addr;
535 sound_data[voice].end_addr2=sound_data[voice].end_addr;
537 sound_data[voice].volume2_l= volume_l;
538 sound_data[voice].volume2_r= volume_r;
540 sound_data[voice].flags=format;
541 sound_data[voice].tick_counter=0;
543 sound_data[voice].cb=NULL;
544 _CPU_ISR_Restore(level);
546 return SND_OK;
549 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
551 s32 ASND_AddVoice(s32 voice, void *snd, s32 size_snd)
553 u32 level;
554 s32 ret=SND_OK;
556 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
558 if(size_snd<=0 || snd==NULL) return SND_INVALID; // invalid voice
560 if((sound_data[voice].flags & (VOICE_UPDATE | VOICE_UPDATEADD)) || !(sound_data[voice].flags>>16)) return SND_INVALID; // busy or unused voice
562 DCFlushRange(snd, size_snd);
563 _CPU_ISR_Disable(level);
565 if(sound_data[voice].start_addr2==0)
568 sound_data[voice].start_addr2=MEM_VIRTUAL_TO_PHYSICAL(snd);
569 sound_data[voice].end_addr2=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
571 sound_data[voice].flags&=~VOICE_SETLOOP;
572 sound_data[voice].flags|=VOICE_UPDATEADD;
573 } else ret=SND_BUSY;
575 _CPU_ISR_Restore(level);
577 return ret;
580 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
582 s32 ASND_TestVoiceBufferReady(s32 voice)
584 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice: not ready (of course XD)
585 if(sound_data[voice].start_addr && sound_data[voice].start_addr2) return 0; // not ready
587 return 1; // ready
590 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
592 s32 ASND_TestPointer(s32 voice, void *pointer)
594 u32 level;
595 u32 addr2=(u32) MEM_VIRTUAL_TO_PHYSICAL(pointer);
596 int ret=SND_OK;
598 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
600 _CPU_ISR_Disable(level);
602 if(sound_data[voice].backup_addr==addr2 /*&& sound_data[voice].end_addr>(addr2)*/) ret=SND_BUSY;
603 else
604 if(sound_data[voice].start_addr2==addr2 /*&& sound_data[voice].end_addr2>(addr2)*/) ret=SND_BUSY;
606 _CPU_ISR_Restore(level);
608 return ret;
611 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
613 s32 ASND_PauseVoice(s32 voice, s32 pause)
615 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
616 if(pause) sound_data[voice].flags|=VOICE_PAUSE; else sound_data[voice].flags&=~VOICE_PAUSE;
618 return SND_OK;
621 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
623 s32 ASND_StopVoice(s32 voice)
625 u32 level;
627 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
629 _CPU_ISR_Disable(level);
631 sound_data[voice].backup_addr=sound_data[voice].start_addr=sound_data[voice].start_addr2=0;
632 sound_data[voice].end_addr=sound_data[voice].end_addr2=0;
633 sound_data[voice].flags=0;
635 _CPU_ISR_Restore(level);
637 return SND_OK;
640 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
642 s32 ASND_StatusVoice(s32 voice)
644 u32 level;
645 s32 status=SND_WORKING;
647 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
649 _CPU_ISR_Disable(level);
650 if(!(sound_data[voice].flags>>16)) status=SND_UNUSED;
651 if(sound_data[voice].flags & VOICE_PAUSE) status=SND_WAITING;
652 _CPU_ISR_Restore(level);
654 return status;
657 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
659 s32 ASND_ChangeVolumeVoice(s32 voice, s32 volume_l, s32 volume_r)
661 u32 level;
663 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
665 volume_l &=255;
666 volume_r &=255;
668 _CPU_ISR_Disable(level);
669 sound_data[voice].flags |=VOICE_VOLUPDATE;
670 sound_data[voice].volume_l= sound_data[voice].volume2_l= volume_l;
671 sound_data[voice].volume_r= sound_data[voice].volume2_r= volume_r;
672 _CPU_ISR_Restore(level);
674 return SND_OK;
677 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
679 u32 ASND_GetTickCounterVoice(s32 voice)
681 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice
683 return (sound_data[voice].tick_counter * SND_BUFFERSIZE/4);
686 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
688 u32 ASND_GetTimerVoice(s32 voice)
690 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice
692 return (sound_data[voice].tick_counter * SND_BUFFERSIZE/4)/48;
695 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
697 void ASND_Pause(s32 pause)
699 global_pause=pause;
703 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
705 s32 ASND_Is_Paused()
707 return global_pause;
710 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
712 u32 ASND_GetTime()
714 return (global_counter * SND_BUFFERSIZE/4)/48;
717 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
719 u32 ASND_GetSampleCounter()
721 return (global_counter * SND_BUFFERSIZE/4);
724 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
726 u32 ASND_GetSamplesPerTick()
728 return (SND_BUFFERSIZE/4);
731 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
733 void ASND_SetTime(u32 time)
735 global_counter=48*time;
738 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
740 void ASND_SetCallback(void (*callback)())
742 global_callback=callback;
745 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
747 s32 ASND_GetAudioRate()
749 return 48000;
752 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
754 s32 ASND_GetFirstUnusedVoice()
757 s32 n;
759 for(n=1;n<MAX_SND_VOICES;n++)
760 if(!(sound_data[n].flags>>16)) return n;
762 if(!(sound_data[0].flags>>16)) return 0; // voice 0 is a special case
764 return SND_INVALID; // all voices used
768 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
770 s32 ASND_ChangePitchVoice(s32 voice, s32 pitch)
772 u32 level;
774 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
776 if(pitch<1) pitch=1;
777 if(pitch>144000) pitch=144000;
779 _CPU_ISR_Disable(level);
780 sound_data[voice].freq= pitch;
781 _CPU_ISR_Restore(level);
783 return SND_OK;
786 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
788 u32 ASND_GetDSP_PercentUse()
790 return (time_of_process)*100/21333; // time_of_process = nanoseconds , 1024 samples= 21333 nanoseconds
793 u32 ASND_GetDSP_ProcessTime()
795 u32 level,ret;
797 _CPU_ISR_Disable(level);
798 ret = time_of_process;
799 _CPU_ISR_Restore(level);
801 return ticks_to_nanosecs(ret);
804 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
806 int ANote2Freq(int note, int freq_base,int note_base)
808 int n;
809 static int one=1;
810 static u32 tab_piano_frac[12];
812 if(one)
814 float note=1.0f;
815 one=0;
816 for(n=0;n<12;n++) // table note
818 tab_piano_frac[n]=(u32)(10000.0f*note);
819 note*=1.0594386f;
823 // obtiene octava 3 (notas 36 a 47)
825 n=(note/12)-(note_base/12);
826 if(n>=0) freq_base<<=n;
827 else freq_base>>= -n;
830 if(freq_base<=0x1ffff) // Math precision
831 n=(s32) (((u32)freq_base)*tab_piano_frac[(note % 12)]/tab_piano_frac[(note_base % 12)]);
832 else
833 n=(s32) (((u64)freq_base)*((u64) tab_piano_frac[(note % 12)])/((u64) tab_piano_frac[(note_base % 12)]));
836 return n;
839 // END