code cleanup (dhewg)
[libogc.git] / libasnd / asndlib.c
blob8e002c07b128b76479c3ff0c3d8846e6415637a9
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/machine/processor.h>
36 #include "asndlib.h"
37 #include "dsp_mixer.h"
39 #undef SND_BUFFERSIZE
41 #define MAX_SND_VOICES 16
42 #define SND_BUFFERSIZE (4096) // donĀ“t modify this value
44 #define VOICE_UPDATEADD 256
45 #define VOICE_UPDATE 128
46 #define VOICE_VOLUPDATE 64
47 #define VOICE_PAUSE 32
48 #define VOICE_SETLOOP 4
50 typedef struct
52 void *out_buf; // output buffer 4096 bytes aligned to 32
54 u32 delay_samples; // samples per delay to start (48000 == 1sec)
56 u32 flags; // (step<<16) | (loop<<2) | (type & 3) used in DSP side
58 u32 start_addr; // internal addr counter
59 u32 end_addr; // end voice physical pointer(bytes without alignament, but remember it reads in blocks of 32 bytes (use padding to the end))
61 u32 freq; // freq operation
63 s16 left, right; // internally used to store de last sample played
65 u32 counter; // internally used to convert freq to 48000Hz samples
67 u16 volume_l,volume_r; // volume (from 0 to 256)
69 u32 start_addr2; // initial voice2 physical pointer (bytes aligned 32 bytes) (to do a ring)
70 u32 end_addr2; // end voice2 physical pointer(bytes without alignament, but remember it reads in blocks of 32 bytes (use padding to the end))
72 u16 volume2_l,volume2_r; // volume (from 0 to 256) for voice 2
74 u32 backup_addr; // initial voice physical pointer backup (bytes aligned to 32 bytes): It is used for test pointers purpose
76 u32 tick_counter; // voice tick counter
78 ASNDVoiceCallback cb;
80 u32 _pad;
81 } t_sound_data;
83 static dsptask_t dsp_task;
85 static vu32 time_of_process;
86 static vu32 dsp_complete = 1;
87 static vu32 dsp_task_starttime = 0;
88 static vu32 curr_audio_buf = 0;
89 static vu32 dsp_done = 0;
91 static vs32 snd_chan = 0;
92 static vs32 global_pause = 1;
93 static vu32 global_counter = 0;
95 static vu32 DSP_DI_HANDLER = 1;
96 static void (*global_callback)()=NULL;
98 static u32 asnd_inited = 0;
99 static t_sound_data sound_data[MAX_SND_VOICES];
101 static t_sound_data sound_data_dma ATTRIBUTE_ALIGN(32);
102 static s16 audio_buf[2][SND_BUFFERSIZE] ATTRIBUTE_ALIGN(32);
104 extern u32 gettick();
106 static __inline__ char* snd_set0b( char *p, int n)
108 while(n>0) {*p++=0;n--;}
109 return p;
112 static __inline__ s32* snd_set0w( s32 *p, int n)
114 while(n>0) {*p++=0;n--;}
115 return p;
118 static void __dsp_initcallback(dsptask_t *task)
120 DSP_SendMailTo(0x0123); // command to fix the data operation
121 while(DSP_CheckMailTo());
123 DSP_SendMailTo(MEM_VIRTUAL_TO_PHYSICAL((&sound_data_dma))); //send the data operation mem
124 while(DSP_CheckMailTo());
126 dsp_complete=1;
127 DSP_DI_HANDLER=0;
130 static void __dsp_requestcallback(dsptask_t *task)
132 s32 n;
134 if(DSP_DI_HANDLER) return;
136 DCInvalidateRange(&sound_data_dma, sizeof(t_sound_data));
138 if(snd_chan>=MAX_SND_VOICES) {
139 if(!global_pause) global_counter++;
140 if(!dsp_complete) time_of_process = (gettick()-dsp_task_starttime)*1000/TB_TIMER_CLOCK;
142 dsp_complete = 1;
143 return;
146 sound_data_dma.freq=sound_data[snd_chan].freq;
147 sound_data_dma.cb=sound_data[snd_chan].cb;
148 if(sound_data[snd_chan].flags & VOICE_UPDATE) // new song
150 sound_data[snd_chan].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
151 //sound_data[snd_chan].out_buf= (void *) MEM_VIRTUAL_TO_PHYSICAL((void *) audio_buf[curr_audio_buf]);
152 sound_data_dma=sound_data[snd_chan];
154 else
157 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
159 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
160 sound_data_dma.volume_l=sound_data_dma.volume2_l=sound_data[snd_chan].volume2_l;
161 sound_data_dma.volume_r=sound_data_dma.volume2_r=sound_data[snd_chan].volume2_r;
165 //if(mail==0xbebe0003) sound_data_dma.flags|=VOICE_SETCALLBACK;
167 if(sound_data_dma.start_addr>=sound_data_dma.end_addr || !sound_data_dma.start_addr)
169 sound_data_dma.backup_addr=sound_data_dma.start_addr=sound_data_dma.start_addr2;
170 sound_data_dma.end_addr=sound_data_dma.end_addr2;
171 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data_dma.start_addr2=0;sound_data_dma.end_addr2=0;}
172 sound_data_dma.volume_l=sound_data_dma.volume2_l;
173 sound_data_dma.volume_r=sound_data_dma.volume2_r;
176 if(sound_data[snd_chan].start_addr2 && (sound_data[snd_chan].flags & VOICE_UPDATEADD))
178 sound_data[snd_chan].flags &=~VOICE_UPDATEADD;
179 if(!sound_data[snd_chan].start_addr || !sound_data_dma.start_addr)
181 sound_data_dma.backup_addr=sound_data_dma.start_addr=sound_data[snd_chan].start_addr2;
182 sound_data_dma.end_addr=sound_data[snd_chan].end_addr2;
183 sound_data_dma.start_addr2=sound_data[snd_chan].start_addr2;
184 sound_data_dma.end_addr2=sound_data[snd_chan].end_addr2;
185 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data_dma.start_addr2=0;sound_data_dma.end_addr2=0;}
186 sound_data_dma.volume_l=sound_data[snd_chan].volume2_l;
187 sound_data_dma.volume_r=sound_data[snd_chan].volume2_r;
189 else
191 sound_data_dma.start_addr2=sound_data[snd_chan].start_addr2;
192 sound_data_dma.end_addr2=sound_data[snd_chan].end_addr2;
193 sound_data_dma.volume2_l=sound_data[snd_chan].volume2_l;
194 sound_data_dma.volume2_r=sound_data[snd_chan].volume2_r;
199 if(!sound_data[snd_chan].cb && (!sound_data_dma.start_addr && !sound_data_dma.start_addr2)) sound_data[snd_chan].flags=0;
200 sound_data_dma.flags=sound_data[snd_chan].flags & ~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_UPDATEADD);
201 sound_data[snd_chan]=sound_data_dma;
204 if(sound_data[snd_chan].flags>>16)
206 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++;
209 snd_chan++;
211 if(!sound_data[snd_chan].cb && (!sound_data[snd_chan].start_addr && !sound_data[snd_chan].start_addr2)) sound_data[snd_chan].flags=0;
213 while(snd_chan<16 && !(sound_data[snd_chan].flags>>16)) snd_chan++;
215 if(snd_chan>=MAX_SND_VOICES)
217 snd_chan++;
218 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
219 DSP_SendMailTo(0x666);
220 while(DSP_CheckMailTo());
221 return;
224 sound_data_dma=sound_data[snd_chan];
226 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
227 DSP_SendMailTo(0x222); // send the voice and mix the samples of the buffer
228 while(DSP_CheckMailTo());
230 // callback strategy for next channel
231 n=snd_chan+1;
233 while(n<16 && !(sound_data[n].flags>>16)) n++;
235 if(n<16)
237 if(!sound_data[n].start_addr2 && (sound_data[n].flags>>16) && sound_data[n].cb) sound_data[n].cb(n);
239 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
241 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
244 if(sound_data[n].flags & VOICE_UPDATE) // new song
246 sound_data[n].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
249 if(!sound_data[n].cb && (!sound_data[n].start_addr && !sound_data[n].start_addr2)) sound_data[n].flags=0;
253 static void __dsp_donecallback(dsptask_t *task)
255 dsp_done = 1;
258 static void audio_dma_callback()
260 u32 n;
262 AUDIO_StopDMA();
263 AUDIO_InitDMA((u32)audio_buf[curr_audio_buf],SND_BUFFERSIZE);
264 if(DSP_DI_HANDLER || global_pause) {
265 snd_set0w((s32 *)audio_buf[curr_audio_buf],SND_BUFFERSIZE/4);
266 DCFlushRange(audio_buf[curr_audio_buf],SND_BUFFERSIZE);
269 AUDIO_StartDMA();
271 if(DSP_DI_HANDLER || global_pause) return;
272 if(dsp_complete==0) return;
274 curr_audio_buf ^= 1;
275 dsp_complete = 0;
277 for(n=0;n<MAX_SND_VOICES;n++) sound_data[n].out_buf = (void *)MEM_VIRTUAL_TO_PHYSICAL((void *)audio_buf[curr_audio_buf]);
279 if(global_callback) global_callback();
281 snd_chan = 0;
282 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);
284 if(sound_data[snd_chan].flags & VOICE_VOLUPDATE)
286 sound_data[snd_chan].flags &=~VOICE_VOLUPDATE;
289 if(sound_data[snd_chan].flags & VOICE_UPDATE) // new song
291 sound_data[snd_chan].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD);
293 else
296 if(sound_data[snd_chan].start_addr>=sound_data[snd_chan].end_addr)
298 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;
299 sound_data[snd_chan].end_addr=sound_data[snd_chan].end_addr2;sound_data[snd_chan].end_addr2=0;
300 sound_data[snd_chan].volume_l=sound_data[snd_chan].volume2_l;
301 sound_data[snd_chan].volume_r=sound_data[snd_chan].volume2_r;
304 if(sound_data[snd_chan].start_addr2 && (sound_data[snd_chan].flags & VOICE_UPDATEADD))
306 sound_data[snd_chan].flags &=~VOICE_UPDATEADD;
308 if(!sound_data[snd_chan].start_addr)
310 sound_data[snd_chan].backup_addr=sound_data[snd_chan].start_addr=sound_data[snd_chan].start_addr2;
311 sound_data[snd_chan].end_addr=sound_data[snd_chan].end_addr2;
312 if(!(sound_data[snd_chan].flags & VOICE_SETLOOP)) {sound_data[snd_chan].start_addr2=0;sound_data[snd_chan].end_addr2=0;}
313 sound_data[snd_chan].volume_l=sound_data[snd_chan].volume2_l;
314 sound_data[snd_chan].volume_r=sound_data[snd_chan].volume2_r;
320 if(!sound_data[snd_chan].cb && (!sound_data[snd_chan].start_addr && !sound_data[snd_chan].start_addr2)) sound_data[snd_chan].flags=0;
322 sound_data_dma=sound_data[snd_chan];
323 DCFlushRange(&sound_data_dma, sizeof(t_sound_data));
325 dsp_task_starttime = gettick();
326 DSP_SendMailTo(0x111); // send the first voice and clear the buffer
327 while(DSP_CheckMailTo());
329 // callback strategy for next channel
330 n=snd_chan+1;
332 while(n<16 && !(sound_data[n].flags>>16)) n++;
334 if(n<16)
336 if(!sound_data[n].start_addr2 && (sound_data[n].flags>>16) && sound_data[n].cb) sound_data[n].cb(n);
338 if(sound_data[n].flags & (VOICE_VOLUPDATE | VOICE_UPDATEADD))
340 sound_data[n].flags &=~(VOICE_VOLUPDATE | VOICE_UPDATEADD);
343 if(sound_data[n].flags & VOICE_UPDATE) // new song
345 sound_data[n].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE| VOICE_PAUSE | VOICE_UPDATEADD);
348 if(!sound_data[n].cb && (!sound_data[n].start_addr && !sound_data[n].start_addr2)) sound_data[n].flags=0;
352 void ASND_Init()
354 u32 i,level;
356 DSP_Init();
357 AUDIO_Init(NULL);
358 AUDIO_StopDMA(); // in case audio was previously inited and a DMA callback set
359 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
361 _CPU_ISR_Disable(level);
362 if(!asnd_inited) {
363 asnd_inited = 1;
364 global_pause = 1;
365 curr_audio_buf = 0;
366 DSP_DI_HANDLER = 1;
367 dsp_complete = 0;
368 dsp_done = 0;
370 snd_set0w((s32*)audio_buf[0], SND_BUFFERSIZE>>2);
371 snd_set0w((s32*)audio_buf[1], SND_BUFFERSIZE>>2);
372 DCFlushRange(audio_buf[0],SND_BUFFERSIZE);
373 DCFlushRange(audio_buf[1],SND_BUFFERSIZE);
375 for(i=0;i<MAX_SND_VOICES;i++)
376 snd_set0w((s32*)&sound_data[i],sizeof(t_sound_data)/4);
378 dsp_task.prio = 255;
379 dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(dsp_mixer);
380 dsp_task.iram_len = size_dsp_mixer;
381 dsp_task.iram_addr = 0x0000;
382 dsp_task.init_vec = 0x10;
383 dsp_task.res_cb = NULL;
384 dsp_task.req_cb = __dsp_requestcallback;
385 dsp_task.init_cb =__dsp_initcallback;
386 dsp_task.done_cb =__dsp_donecallback;
387 DSP_AddTask(&dsp_task);
389 AUDIO_RegisterDMACallback(audio_dma_callback);
390 AUDIO_InitDMA((u32)audio_buf[curr_audio_buf],SND_BUFFERSIZE);
391 AUDIO_StartDMA();
392 curr_audio_buf ^= 1;
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&=3;
438 switch(format)
440 case 0:
441 flag_h=1<<16;break;
442 case 1:
443 flag_h=2<<16;break;
444 case 2:
445 flag_h=2<<16;break;
446 case 3:
447 flag_h=4<<16;break;
450 format|= flag_h | VOICE_UPDATE;
452 _CPU_ISR_Disable(level);
454 sound_data[voice].left=0;
455 sound_data[voice].right=0;
456 sound_data[voice].counter=0;
458 sound_data[voice].freq=pitch;
460 sound_data[voice].delay_samples=delay;
462 sound_data[voice].volume_l= volume_l;
463 sound_data[voice].volume_r= volume_r;
465 sound_data[voice].backup_addr=sound_data[voice].start_addr=MEM_VIRTUAL_TO_PHYSICAL(snd);
466 sound_data[voice].end_addr=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
468 sound_data[voice].start_addr2=0;
469 sound_data[voice].end_addr2=0;
471 sound_data[voice].volume2_l= volume_l;
472 sound_data[voice].volume2_r= volume_r;
474 sound_data[voice].flags=format;
475 sound_data[voice].tick_counter=0;
477 sound_data[voice].cb = callback;
478 _CPU_ISR_Restore(level);
480 return SND_OK;
483 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
485 s32 ASND_SetInfiniteVoice(s32 voice, s32 format, s32 pitch,s32 delay, void *snd, s32 size_snd, s32 volume_l, s32 volume_r)
487 u32 level;
488 u32 flag_h=0;
490 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
492 if(size_snd<=0 || snd==NULL) return SND_INVALID; // invalid voice
494 DCFlushRange(snd, size_snd);
496 if(pitch<1) pitch=1;
497 if(pitch>MAX_PITCH) pitch=MAX_PITCH;
499 volume_l &=255;
500 volume_r &=255;
502 delay=(u32) (48000LL*((u64) delay)/1000LL);
504 format&=3;
506 switch(format)
508 case 0:
509 flag_h=1<<16;break;
510 case 1:
511 flag_h=2<<16;break;
512 case 2:
513 flag_h=2<<16;break;
514 case 3:
515 flag_h=4<<16;break;
518 format|= flag_h | VOICE_UPDATE | VOICE_SETLOOP;
520 _CPU_ISR_Disable(level);
522 sound_data[voice].left=0;
523 sound_data[voice].right=0;
524 sound_data[voice].counter=0;
526 sound_data[voice].freq=pitch;
528 sound_data[voice].delay_samples=delay;
530 sound_data[voice].volume_l= volume_l;
531 sound_data[voice].volume_r= volume_r;
533 sound_data[voice].backup_addr=sound_data[voice].start_addr=MEM_VIRTUAL_TO_PHYSICAL(snd);
534 sound_data[voice].end_addr=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
536 sound_data[voice].start_addr2=sound_data[voice].start_addr;
537 sound_data[voice].end_addr2=sound_data[voice].end_addr;
539 sound_data[voice].volume2_l= volume_l;
540 sound_data[voice].volume2_r= volume_r;
542 sound_data[voice].flags=format;
543 sound_data[voice].tick_counter=0;
545 sound_data[voice].cb=NULL;
546 _CPU_ISR_Restore(level);
548 return SND_OK;
551 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
553 s32 ASND_AddVoice(s32 voice, void *snd, s32 size_snd)
555 u32 level;
556 s32 ret=SND_OK;
558 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
560 if(size_snd<=0 || snd==NULL) return SND_INVALID; // invalid voice
562 if((sound_data[voice].flags & (VOICE_UPDATE | VOICE_UPDATEADD)) || !(sound_data[voice].flags>>16)) return SND_INVALID; // busy or unused voice
564 DCFlushRange(snd, size_snd);
565 _CPU_ISR_Disable(level);
567 if(sound_data[voice].start_addr2==0)
570 sound_data[voice].start_addr2=MEM_VIRTUAL_TO_PHYSICAL(snd);
571 sound_data[voice].end_addr2=MEM_VIRTUAL_TO_PHYSICAL(snd)+(size_snd);
573 sound_data[voice].flags&=~VOICE_SETLOOP;
574 sound_data[voice].flags|=VOICE_UPDATEADD;
575 } else ret=SND_BUSY;
577 _CPU_ISR_Restore(level);
579 return ret;
582 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
584 s32 ASND_TestVoiceBufferReady(s32 voice)
586 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice: not ready (of course XD)
587 if(sound_data[voice].start_addr && sound_data[voice].start_addr2) return 0; // not ready
589 return 1; // ready
592 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
594 s32 ASND_TestPointer(s32 voice, void *pointer)
596 u32 level;
597 u32 addr2=(u32) MEM_VIRTUAL_TO_PHYSICAL(pointer);
598 int ret=SND_OK;
600 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
602 _CPU_ISR_Disable(level);
604 if(sound_data[voice].backup_addr==addr2 /*&& sound_data[voice].end_addr>(addr2)*/) ret=SND_BUSY;
605 else
606 if(sound_data[voice].start_addr2==addr2 /*&& sound_data[voice].end_addr2>(addr2)*/) ret=SND_BUSY;
608 _CPU_ISR_Restore(level);
610 return ret;
613 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
615 s32 ASND_PauseVoice(s32 voice, s32 pause)
617 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
618 if(pause) sound_data[voice].flags|=VOICE_PAUSE; else sound_data[voice].flags&=~VOICE_PAUSE;
620 return SND_OK;
623 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
625 s32 ASND_StopVoice(s32 voice)
627 u32 level;
629 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
631 _CPU_ISR_Disable(level);
633 sound_data[voice].backup_addr=sound_data[voice].start_addr=sound_data[voice].start_addr2=0;
634 sound_data[voice].end_addr=sound_data[voice].end_addr2=0;
635 sound_data[voice].flags=0;
637 _CPU_ISR_Restore(level);
639 return SND_OK;
642 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
644 s32 ASND_StatusVoice(s32 voice)
646 u32 level;
647 s32 status=SND_WORKING;
649 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
651 _CPU_ISR_Disable(level);
652 if(!(sound_data[voice].flags>>16)) status=SND_UNUSED;
653 if(sound_data[voice].flags & VOICE_PAUSE) status=SND_WAITING;
654 _CPU_ISR_Restore(level);
656 return status;
659 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
661 s32 ASND_ChangeVolumeVoice(s32 voice, s32 volume_l, s32 volume_r)
663 u32 level;
665 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
667 volume_l &=255;
668 volume_r &=255;
670 _CPU_ISR_Disable(level);
671 sound_data[voice].flags |=VOICE_VOLUPDATE;
672 sound_data[voice].volume_l= sound_data[voice].volume2_l= volume_l;
673 sound_data[voice].volume_r= sound_data[voice].volume2_r= volume_r;
674 _CPU_ISR_Restore(level);
676 return SND_OK;
679 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
681 u32 ASND_GetTickCounterVoice(s32 voice)
683 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice
685 return (sound_data[voice].tick_counter * SND_BUFFERSIZE/4);
688 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
690 u32 ASND_GetTimerVoice(s32 voice)
692 if(voice<0 || voice>=MAX_SND_VOICES) return 0; // invalid voice
694 return (sound_data[voice].tick_counter * SND_BUFFERSIZE/4)/48;
697 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
699 void ASND_Pause(s32 pause)
701 global_pause=pause;
705 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
707 s32 ASND_Is_Paused()
709 return global_pause;
712 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
714 u32 ASND_GetTime()
716 return (global_counter * SND_BUFFERSIZE/4)/48;
719 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
721 u32 ASND_GetSampleCounter()
723 return (global_counter * SND_BUFFERSIZE/4);
726 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
728 u32 ASND_GetSamplesPerTick()
730 return (SND_BUFFERSIZE/4);
733 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
735 void ASND_SetTime(u32 time)
737 global_counter=48*time;
740 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
742 void ASND_SetCallback(void (*callback)())
744 global_callback=callback;
747 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
749 s32 ASND_GetAudioRate()
751 return 48000;
754 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
756 s32 ASND_GetFirstUnusedVoice()
759 s32 n;
761 for(n=1;n<MAX_SND_VOICES;n++)
762 if(!(sound_data[n].flags>>16)) return n;
764 if(!(sound_data[0].flags>>16)) return 0; // voice 0 is a special case
766 return SND_INVALID; // all voices used
770 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
772 s32 ASND_ChangePitchVoice(s32 voice, s32 pitch)
774 u32 level;
776 if(voice<0 || voice>=MAX_SND_VOICES) return SND_INVALID; // invalid voice
778 if(pitch<1) pitch=1;
779 if(pitch>144000) pitch=144000;
781 _CPU_ISR_Disable(level);
782 sound_data[voice].freq= pitch;
783 _CPU_ISR_Restore(level);
785 return SND_OK;
788 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
790 u32 ASND_GetDSP_PercentUse()
792 return (time_of_process)*100/21333; // time_of_process = nanoseconds , 1024 samples= 21333 nanoseconds
795 /*------------------------------------------------------------------------------------------------------------------------------------------------------*/
797 int ANote2Freq(int note, int freq_base,int note_base)
799 int n;
800 static int one=1;
801 static u32 tab_piano_frac[12];
803 if(one)
805 float note=1.0f;
806 one=0;
807 for(n=0;n<12;n++) // table note
809 tab_piano_frac[n]=(u32)(10000.0f*note);
810 note*=1.0594386f;
814 // obtiene octava 3 (notas 36 a 47)
816 n=(note/12)-(note_base/12);
817 if(n>=0) freq_base<<=n;
818 else freq_base>>= -n;
821 if(freq_base<=0x1ffff) // Math precision
822 n=(s32) (((u32)freq_base)*tab_piano_frac[(note % 12)]/tab_piano_frac[(note_base % 12)]);
823 else
824 n=(s32) (((u64)freq_base)*((u64) tab_piano_frac[(note % 12)])/((u64) tab_piano_frac[(note_base % 12)]));
827 return n;
830 // END