1 /*---------------------------------------------------------------------------*
2   Project:  Revolution PMIC simple demo
3   File:     audio.c
4 
5   Copyright (C)2008 Nintendo  All Rights Reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: audio.c,v $
14   Revision 1.4  2008/08/06 01:39:14  carlmu
15   Added graphic demo.
16 
17   Revision 1.3  2008/08/04 23:51:51  carlmu
18   Added quit function for audio.
19 
20   Revision 1.2  2008/04/23 00:09:19  aka
21   Modified an argument of PMICChangeRate().
22 
23   Revision 1.1  2008/01/22 02:50:04  aka
24   initial check-in.
25 
26   $NoKeywords: $
27  *---------------------------------------------------------------------------*/
28 
29 #include <string.h>
30 #include <revolution.h>
31 #include <revolution/mem.h>
32 #include <revolution/mix.h>
33 #include <revolution/seq.h>
34 #include <revolution/syn.h>
35 #include <revolution/pmic.h>
36 
37 #include "audio.h"
38 
39 /*---------------------------------------------------------------------------*
40    definitions
41  *---------------------------------------------------------------------------*/
42 
43 #define USE_HEADPHONE
44 #undef  USE_HEADPHONE
45 
46 #define USE_64TAP_SRC
47 //#undef  USE_64TAP_SRC
48 
49 // audio data
50 #define AUDIO_GM_WT                  "/axdemo/synth/gm16adpcm.wt"
51 #define AUDIO_GM_PCM                 "/axdemo/synth/gm16adpcm.pcm"
52 #define AUDIO_MIDI_FILE              "/axdemo/midi/candy.mid"
53 
54 // audio processing unit
55 #define AUDIO_SAMPLES_PER_FRAME      (32 * 3) // 32KHz x 3msec
56 #define AUDIO_BYTES_PER_FRAME        (AUDIO_SAMPLES_PER_FRAME * 2 * 2)
57 
58 // for voice processing
59 #define STACK_SIZE                   (256 * 1024) // 256KB
60 #define THREAD_PRIORITY               20
61 
62 #define SRC_TAPS                      64
63 #define SRC_BUFF_SAMPLES             (SRC_TAPS + 16 * 3) // taps + 16KHz x 3msec
64 
65 #define PROC_BUFF_SAMPLES            (32000 * 10) // 32KHz * 10sec
66 
67 typedef struct
68 {
69     s32         samples; // buffer size
70     s32         top;     // write ptr
71     s32         buttom;  // read  ptr
72     s16*        buffer;  // <- mono
73 
74 } PROCInfo;
75 
76 #define PROC_VOICE_GAIN               2 // 2bit SLA = + 12dB
77 
78 /*---------------------------------------------------------------------------*
79    variables
80  *---------------------------------------------------------------------------*/
81 
82 // for AXs
83 static u8*              axBuff;
84 static u8*              mixBuff;
85 static u8*              synBuff;
86 static u8*              waveTbl;
87 static u8*              pcmData;
88 static u8*              midiData;
89 static SEQSEQUENCE      sequence;
90 
91 // for AI
92 static s16*             aiBuff[2];
93 static AIDCallback      old_aiCb;
94 
95 // for ISO-OUT
96 static s16*             isoBuff;
97 
98 // for voice processing
99 static OSThread         procThread;
100 static u8               procStack[STACK_SIZE];
101 static OSThreadQueue    procWait;
102 
103 static s16*             srcBuff;
104 static s16              srcCoef[2][SRC_TAPS] =
105 {
106     {
107           -23,       10,     -11,      12,     -10,       7,       -1,       -6,
108            18,      -31,      49,     -69,      94,    -120,      149,     -177,
109           208,     -235,     262,    -281,     296,    -299,      292,     -267,
110           223,     -149,      37,     140,    -426,     962,    -2313,    14176,
111          5461,    -2586,    1754,   -1326,    1049,    -842,      678,     -540,
112           424,     -322,     236,    -162,     101,     -49,        9,       23,
113           -45,       62,     -70,      75,     -74,      72,      -65,       58,
114           -49,       41,     -32,      25,     -18,      13,      -12,        8,
115     },
116 
117     {
118             8,      -12,      13,     -18,      25,     -32,       41,      -49,
119            58,      -65,      72,     -74,      75,     -70,       62,      -45,
120            23,        9,     -49,     101,    -162,     236,     -322,      424,
121          -540,      678,    -842,    1049,   -1326,    1754,    -2586,     5461,
122         14176,    -2313,     962,    -426,     140,      37,     -149,      223,
123          -267,      292,    -299,     296,    -281,     262,     -235,      208,
124          -177,      149,    -120,      94,     -69,      49,      -31,       18,
125            -6,       -1,       7,     -10,      12,     -11,       10,      -23
126     }
127 };
128 
129 static PROCInfo         procInfo;
130 
131 // for voice playback
132 static BOOL             playVoice = FALSE;
133 
134 /*---------------------------------------------------------------------------*
135    funcs
136  *---------------------------------------------------------------------------*/
137 
138 static void  audioCb   ( void );
139 static u8*   loadFile  ( char *path, MEMHeapHandle* heap );
140 static void  aiCb      ( void );
141 static void* voiceProc ( void *param );
142 static s32   fillVoice ( s16* buffer, s32 samples);
143 
144 /*---------------------------------------------------------------------------*
145   Name:         AUDIOInit
146 
147   Description:  initialize audio.
148 
149   Arguments:    heap    for mem allocation.
150 
151   Returns:      TRUE/FALSE
152  *---------------------------------------------------------------------------*/
153 
AUDIOInit(MEMHeapHandle * heap,MicFunc procFunc)154 BOOL AUDIOInit(MEMHeapHandle* heap, MicFunc procFunc)
155 {
156     BOOL old;
157 
158     //
159     // init AXs.
160     //
161     axBuff  = MEMAllocFromExpHeapEx(*heap, AXGetMemorySize (AX_MAX_VOICES), 32);
162     mixBuff = MEMAllocFromExpHeapEx(*heap, MIXGetMemorySize(AX_MAX_VOICES), 32);
163     synBuff = MEMAllocFromExpHeapEx(*heap, SYNGetMemorySize(AX_MAX_VOICES), 32);
164 
165     if (!axBuff || !mixBuff || !synBuff)
166     {
167         return FALSE;
168     }
169 
170     AIInit(NULL);                            // initialize AI
171     AXInitSpecifyMem(AX_MAX_VOICES, axBuff); // initialize AX
172     MIXInitSpecifyMem(mixBuff);              // initialize mixer
173     SYNInitSpecifyMem(synBuff);              // initialize synthesizer
174     SEQInit();                               // initialize sequencer
175 
176     AXRegisterCallback(audioCb);
177 
178     //
179     // play MIDI.
180     //
181 
182     waveTbl  = loadFile(AUDIO_GM_WT,     heap);
183     pcmData  = loadFile(AUDIO_GM_PCM,    heap);
184     midiData = loadFile(AUDIO_MIDI_FILE, heap);
185 
186     if (!waveTbl || !pcmData || !midiData)
187     {
188         return FALSE;
189     }
190 
191     SEQAddSequence(&sequence,
192                    midiData,
193                    waveTbl,
194                    pcmData,
195                    NULL,
196                    16,
197                    15,
198                    1);
199 
200     SEQSetState (&sequence, SEQ_STATE_RUNLOOPED);
201     SEQSetVolume(&sequence, -120);
202 
203     //
204     // create voice processing thread.
205     //
206 
207     srcBuff = MEMAllocFromExpHeapEx(*heap, SRC_BUFF_SAMPLES * sizeof(s16), 32);
208     memset(srcBuff, 0, SRC_BUFF_SAMPLES * sizeof(s16));
209 
210     procInfo.samples = PROC_BUFF_SAMPLES;
211     procInfo.top     = 0;
212     procInfo.buttom  = 0;
213     procInfo.buffer  = MEMAllocFromExpHeapEx(*heap, PROC_BUFF_SAMPLES * sizeof(s16), 32);
214 
215     OSInitThreadQueue(&procWait);
216 
217     if (procFunc == NULL) {
218 	procFunc = voiceProc;
219     }
220 
221     OSCreateThread(&procThread,
222                    procFunc,
223                    NULL,
224                    procStack + STACK_SIZE,
225                    STACK_SIZE,
226                    THREAD_PRIORITY,
227                    OS_THREAD_ATTR_DETACH);
228 
229     OSResumeThread(&procThread);
230 
231     //
232     // snatch AI callback.
233     //
234 
235     aiBuff[0]= MEMAllocFromExpHeapEx(*heap, AUDIO_BYTES_PER_FRAME, 32);
236     aiBuff[1]= MEMAllocFromExpHeapEx(*heap, AUDIO_BYTES_PER_FRAME, 32);
237 
238     isoBuff = MEMAllocFromExpHeapEx(*heap, (AUDIO_SAMPLES_PER_FRAME / 2) * sizeof(s16) * 2, 32);
239     // 16KHz * s16 * stereo
240 
241     old = OSDisableInterrupts();
242     old_aiCb = AIRegisterDMACallback(aiCb);
243     OSRestoreInterrupts(old);
244 
245     return TRUE;
246 }
247 
248 /*---------------------------------------------------------------------------*
249   Name:         AUDIOQuit
250 
251   Description:  shut down audio system.
252 
253   Arguments:    none.
254 
255   Returns:      none.
256  *---------------------------------------------------------------------------*/
257 
AUDIOQuit(void)258 void AUDIOQuit(void)
259 {
260     SEQQuit();
261     SYNQuit();
262     MIXQuit();
263     AXQuit();
264 }
265 
266 /*---------------------------------------------------------------------------*
267   Name:         AUDIOStartPlay
268 
269   Description:  start playing P-Mic's data.
270 
271   Arguments:    none.
272 
273   Returns:      none.
274  *---------------------------------------------------------------------------*/
275 
AUDIOStartPlay(void)276 void AUDIOStartPlay(void)
277 {
278     playVoice = TRUE;
279 }
280 
281 /*---------------------------------------------------------------------------*
282   Name:         AUDIOStopPlay
283 
284   Description:  stop playing P-Mic's data.
285 
286   Arguments:    none.
287 
288   Returns:      none.
289  *---------------------------------------------------------------------------*/
290 
AUDIOStopPlay(void)291 void AUDIOStopPlay(void)
292 {
293     playVoice = FALSE;
294 
295     procInfo.top     = 0;
296     procInfo.buttom  = 0;
297 }
298 
299 /*---------------------------------------------------------------------------*
300   Name:         AUDIOSleepThread
301 
302   Description:  Used by (external) pmic processing function, since the
303                 threadqueue is not public.
304 
305   Arguments:    none.
306 
307   Returns:      none.
308  *---------------------------------------------------------------------------*/
309 
AUDIOSleepThread(void)310 void AUDIOSleepThread(void)
311 {
312     OSSleepThread(&procWait);
313 }
314 
315 /*---------------------------------------------------------------------------*
316  *---------------------------------------------------------------------------*
317  *---------------------------------------------------------------------------*
318  *---------------------------------------------------------------------------*/
319 
320 /*---------------------------------------------------------------------------*
321   Name:         audioCb
322 
323   Description:  callback for AX apps.
324 
325   Arguments:    none.
326 
327   Returns:      none.
328  *---------------------------------------------------------------------------*/
329 
audioCb(void)330 static void audioCb(void)
331 {
332     SEQRunAudioFrame();
333     SYNRunAudioFrame();
334     MIXUpdateSettings();
335 }
336 
337 /*---------------------------------------------------------------------------*
338   Name:         loadFile
339 
340   Description:  load file from DVD.
341 
342   Arguments:    path    file name with path info.
343                 heap    for mem allocation.
344 
345   Returns:      data address.
346  *---------------------------------------------------------------------------*/
347 
loadFile(char * path,MEMHeapHandle * heap)348 static u8* loadFile(char *path, MEMHeapHandle* heap)
349 {
350     DVDFileInfo handle;
351     u32         round_length;
352     s32         read_length;
353     void*       buffer;
354 
355     if (!DVDOpen(path, &handle))
356     {
357         return NULL;
358     }
359 
360     if (DVDGetLength(&handle) == 0)
361     {
362         return NULL;
363     }
364 
365     round_length = OSRoundUp32B(DVDGetLength(&handle));
366     buffer       = MEMAllocFromExpHeapEx(*heap, round_length,  32);
367 
368     if (buffer == NULL)
369     {
370         return NULL;
371     }
372 
373     read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
374 
375     if (read_length <= 0)
376     {
377         return NULL;
378     }
379 
380     return buffer;
381 }
382 
383 /*---------------------------------------------------------------------------*
384   Name:         aiCb
385 
386   Description:  new AI callback func.
387 
388   Arguments:    none.
389 
390   Returns:      none.
391  *---------------------------------------------------------------------------*/
392 
aiCb(void)393 static void aiCb(void)
394 {
395     static s16* last_buff = NULL;
396     static s32  buff_ptr  = 0;
397     static BOOL init      = TRUE;
398 
399     s16*  curr_buff;
400     s32   retval;
401 
402     // hand over AI buffer address.
403     curr_buff = last_buff;
404 
405     // call old AI callback func.
406     old_aiCb();
407 
408     // get AI buffer address set in the old AI callback func.
409     last_buff = (s16 *)OSPhysicalToCached(AIGetDMAStartAddr());
410 
411     // set new AI buffer.
412     AIInitDMA((u32)aiBuff[buff_ptr], AUDIO_BYTES_PER_FRAME);
413 
414     // fill the new AI buffer.
415     if (playVoice)
416     {
417         // fill P-Mic's data to the new AI buffer.
418         if (!fillVoice(aiBuff[buff_ptr], AUDIO_BYTES_PER_FRAME / 2))
419         {
420             playVoice = FALSE;
421         }
422     }
423     else
424     {
425         if (curr_buff)
426         {
427             DCInvalidateRange(curr_buff, AUDIO_BYTES_PER_FRAME); // to make sure
428             memcpy(aiBuff[buff_ptr], curr_buff, AUDIO_BYTES_PER_FRAME);
429         }
430         else
431         {
432             memset(aiBuff[buff_ptr], 0, AUDIO_BYTES_PER_FRAME);
433         }
434     }
435 
436     // send final AI data in the new AI buffer to P-Mic (ISO-OUT).
437 
438 #ifdef USE_64TAP_SRC
439 
440     // retval is -1 if PMIC lib is not initialized
441     retval = PMICChangeRate(aiBuff[buff_ptr],
442                             AUDIO_BYTES_PER_FRAME / 2,
443                             AI_SAMPLERATE_32KHZ,
444                             isoBuff,
445                             init);
446 #else
447     {
448 	extern BOOL PMICIsUp();
449 
450 	s16 *pIn = aiBuff[buff_ptr];
451 	s16 *pOut = isoBuff;
452 	u32 i;
453 
454 	for(i=0; i<AUDIO_SAMPLES_PER_FRAME/2; i++) {
455 	    *pOut++ = *pIn++; // right sample
456 	    *pOut++ = *pIn++; // left sample
457 	    pIn+=2; // skip next pair for 32Khz->16Khz
458 	}
459 
460 	if (PMICIsUp())
461 	    retval = AUDIO_SAMPLES_PER_FRAME;
462 	else
463 	    retval = -1;
464     }
465 #endif
466 
467     if (retval > 0)
468     {
469 #ifdef USE_HEADPHONE
470         memset(isoBuff, 0, (u32)(retval * sizeof(s16)));
471 #endif
472         PMICWrite(isoBuff, retval);
473         init = FALSE;
474     }
475 
476     // finish touching the new AI buffer.
477     DCFlushRange(aiBuff[buff_ptr], AUDIO_BYTES_PER_FRAME);
478     buff_ptr ^= 1;
479 
480     // report to voice processing thread.
481     OSWakeupThread(&procWait);
482 }
483 
484 /*---------------------------------------------------------------------------*
485   Name:         voiceProc
486 
487   Description:  convert P-Mic's data from 16KHz to 32KHz.
488 
489   Arguments:    param    no use.
490 
491   Returns:      none.
492  *---------------------------------------------------------------------------*/
493 
voiceProc(void * param)494 static void* voiceProc(void *param)
495 {
496 #pragma unused(param)
497 
498     s32  wptr;
499     s32  limits;
500     s16* buffer;
501     s32  writables;
502     s32  needs;
503     s32  reads;
504     s32  ii, jj;
505     s32  acc_1st, acc_2nd;
506     s16* inptr;
507 
508     while (1)
509     {
510         AUDIOSleepThread();
511 
512         wptr   = procInfo.top;
513         limits = procInfo.samples;
514         buffer = procInfo.buffer;
515 
516         // check space of output buffer.
517         // # don't overwrite here <- P-Mic lib may overwrite...
518         writables = (limits - wptr) & ~0x1;
519         if (writables <= 0)
520         {
521             continue;
522         }
523 
524         // get P-Mic's data (16KHz).
525         needs = writables >> 1;
526         if (needs >= SRC_BUFF_SAMPLES - (SRC_TAPS - 1))
527         {
528             needs = SRC_BUFF_SAMPLES - (SRC_TAPS - 1);
529         }
530 
531         reads = PMICRead(&srcBuff[SRC_TAPS - 1], needs);
532         if (reads <= 0)
533         {
534             continue;
535         }
536 
537         // do SRC from 16KHz to 32KHz.
538         for (ii = 0; ii < reads; ii++)
539         {
540             inptr = &srcBuff[ii];
541 
542 #ifdef USE_64TAP_SRC
543 
544             acc_1st = 0;
545             acc_2nd = 0;
546 
547             for (jj = 0; jj < SRC_TAPS; jj++)
548             {
549                 acc_1st += 2 * srcCoef[0][jj] * *inptr;
550                 acc_2nd += 2 * srcCoef[1][jj] * *inptr++;
551             }
552 
553             acc_1st = (acc_1st + 0x4000) >> 15;
554             acc_2nd = (acc_2nd + 0x4000) >> 15;
555 
556             if (acc_1st > 32767)
557             {
558                 acc_1st = 32767;
559             }
560             else if (acc_1st < -32768)
561             {
562                 acc_1st = -32768;
563             }
564 
565             if (acc_2nd > 32767)
566             {
567                 acc_2nd = 32767;
568             }
569             else if (acc_2nd < -32768)
570             {
571                 acc_2nd = -32768;
572             }
573 #else
574 	    acc_1st = *inptr++;
575 	    acc_2nd = (acc_1st + (*inptr)) >> 1;
576 #endif
577 
578             buffer[wptr++] = (s16)acc_1st;
579             buffer[wptr++] = (s16)acc_2nd;
580         }
581 
582         // move histories.
583         for (jj = 0; jj < SRC_TAPS - 1; jj++)
584         {
585             srcBuff[jj] = srcBuff[ii + jj];
586         }
587 
588         procInfo.top = wptr;
589     }
590 }
591 
592 /*---------------------------------------------------------------------------*
593   Name:         fillVoice
594 
595   Description:  fill P-Mic's data (already converted to 32KHz).
596 
597   Arguments:    buffer     output buffer.
598                 samples    samples to output.
599 
600   Returns:      num of outputs.
601  *---------------------------------------------------------------------------*/
602 
fillVoice(s16 * buffer,s32 samples)603 static s32 fillVoice(s16* buffer, s32 samples)
604 {
605     s32  needs;
606     s32  rptr;
607     s32  lefts;
608     s16* data;
609     s32  outputs;
610     s32  ii;
611     s32  stmp32;
612 
613     needs = samples >> 1; // stereo -> mono
614 
615     rptr   = procInfo.buttom;
616     lefts  = procInfo.top - rptr;
617     data   = procInfo.buffer;
618 
619     outputs = needs > lefts? lefts: needs;
620 
621     for (ii = 0; ii < outputs; ii++)
622     {
623         stmp32 = (s32)data[rptr++] << PROC_VOICE_GAIN;
624         if (stmp32 > 32767)
625         {
626             stmp32 = 32767;
627         }
628         else if (stmp32 < -32768)
629         {
630             stmp32 = -32768;
631         }
632 
633         *buffer++ = (s16)stmp32; // Rch
634         *buffer++ = (s16)stmp32; // Lch
635     }
636 
637     for (; ii < needs; ii++)
638     {
639         *buffer++ = 0; // Rch
640         *buffer++ = 0; // Lch
641     }
642 
643     procInfo.buttom  = rptr;
644 
645     return outputs << 1; // mono -> stereo
646 }
647