1 /*---------------------------------------------------------------------------*
2   Project:  Revolution AX stream demo
3   File:     axstream.c
4 
5   Copyright (C)1998-2006 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: axstream.c,v $
14   Revision 1.4  02/02/2006 08:12:18  aka
15   Modified using MEM functions instead of OSAlloc()/OSFree().
16 
17   Revision 1.3  02/01/2006 05:16:03  aka
18   Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif.
19 
20   Revision 1.2  11/08/2005 02:55:02  aka
21   Changed suiting to Revolution's audio spec.
22 
23   Revision 1.1  11/04/2005 05:01:39  aka
24   Imported from dolphin tree.
25 
26     10    04/04/21 11:18a Akagi
27     Added considering alignment of stream buffers.
28 
29     9     03/04/24 08:45:00 Dante
30     Removed ramBufferLenAdpcm
31 
32     8     03/04/15 8:08 Dante
33     Modified to read APDCP header instead of hard coded information &
34     coefficients.
35 
36     7     7/01/02 4:18p Billyjack
37     changed ramBufferLenPcm16 = 827260; to ramBufferLenPcm16 = 827270; used
38     to be off by 10 bytes at the end where it was silent
39 
40     6     12/11/01 7:02p Billyjack
41     - keep interrupts disabled during audio frame callback
42 
43     5     8/03/01 4:32p Billyjack
44     added OSEnableInterrupts() and OSRestoreInterrupts() to AX audio frame
45     callback per change in AX lib.
46 
47     4     7/06/01 11:50a Billyjack
48     commented DCInvalidateRange for DVD to RAM transfers
49 
50     3     5/14/01 1:39p Billyjack
51     - reworked for DVDDATA file location and names
52     - uses ARGetBaseAddress where applicable
53 
54     2     5/09/01 6:09p Billyjack
55     now uses the mix lib
56 
57     1     3/26/01 2:32p Billyjack
58     created
59 
60   $NoKeywords: $
61  *---------------------------------------------------------------------------*/
62 #include <string.h>
63 #include <demo.h>
64 #include <revolution.h>
65 #include <revolution/mix.h>
66 #ifdef HOLLYWOOD_REV
67 #include <revolution/mem.h>
68 #endif
69 
70 static u32          frames;
71 static u32          flag;
72 
73 #define STREAM_NONE         0
74 #define STREAM_INITIALIZING 1
75 #define STREAM_STARTED      2
76 #define STREAM_STOPPING     3
77 #define STREAM_STOPPED      4
78 
79 static AXVPB        *streamL;
80 static AXVPB        *streamR;
81 
82 static u32          ramBufferLen;       // length in bytes
83 static u32          ramBufferLPcm16;    // base address for left buffer
84 static u32          ramBufferRPcm16;    // base address for right buffer
85 
86 static u32          ramBufferLenPcm16;  // length in bytes
87 static u32          ramBufferLPcm8;     // base address for left buffer
88 static u32          ramBufferRPcm8;     // base address for right buffer
89 static u32          ramBufferLenPcm8;   // length in bytes
90 
91 static u32          ramBufferLAdpcm;    // base address for left buffer
92 static u32          ramBufferRAdpcm;    // base address for right buffer
93 
94 #ifndef HOLLYWOOD_REV
95 #define MAX_ARAM_BLOCKS     2
96 static u32 aramMemArray[MAX_ARAM_BLOCKS];
97 
98 static u32          aramBufferL0;
99 static u32          aramBufferL1;
100 static u32          aramBufferLEnd;
101 static u32          aramBufferR0;
102 static u32          aramBufferR1;
103 static u32          aramBufferREnd;
104 static u32          streamLastPositionR;
105 
106 static u32          ramBufferL;         // base address for left buffer
107 static u32          ramBufferR;         // base address for right buffer
108 
109 static u32          ramBufferPosition;  // read position in byte offset
110 
111 static ARQRequest   taskL;
112 static ARQRequest   taskR;
113 
114 #define STREAM_BLOCK_LEN        0x1000
115 
116 #define STREAM_BUFFERL_START    (4096)                                          // in bytes
117 #define STREAM_BUFFERL_HALF     (STREAM_BUFFERL_START + STREAM_BLOCK_LEN)       // in bytes
118 #define STREAM_BUFFERL_END      (STREAM_BUFFERL_START + (STREAM_BLOCK_LEN * 2)) // in bytes
119 
120 #define STREAM_BUFFERR_START    (STREAM_BUFFERL_START + (STREAM_BLOCK_LEN * 2)) // in bytes
121 #define STREAM_BUFFERR_HALF     (STREAM_BUFFERR_START + STREAM_BLOCK_LEN)       // in bytes
122 #define STREAM_BUFFERR_END      (STREAM_BUFFERR_START + (STREAM_BLOCK_LEN * 2)) // in bytes
123 
124 static u8           streamBufferL[STREAM_BLOCK_LEN] ATTRIBUTE_ALIGN(ARQ_DMA_ALIGNMENT);
125 static u8           streamBufferR[STREAM_BLOCK_LEN] ATTRIBUTE_ALIGN(ARQ_DMA_ALIGNMENT);
126 
127 #else
128 
129 // Exp Heap
130 static MEMHeapHandle hExpHeap;
131 
132 // zero buffer size
133 #define ZEROBUFFER_BYTES 256
134 static u8 *zeroBuffer;
135 
136 #endif
137 
138 /*---------------------------------------------------------------------------*
139  *---------------------------------------------------------------------------*/
140 #ifndef HOLLYWOOD_REV
fillAram(int buffer)141 static void fillAram(int buffer)
142 {
143     u32 aramByteAddressL;
144     u32 aramByteAddressR;
145 
146     // set ARAM destination
147     if (buffer)
148     {
149         aramByteAddressL = STREAM_BUFFERL_HALF;
150         aramByteAddressR = STREAM_BUFFERR_HALF;
151     }
152     else
153     {
154         aramByteAddressL = STREAM_BUFFERL_START;
155         aramByteAddressR = STREAM_BUFFERR_START;
156     }
157 
158     // check to see if we are passed the end of the input buffer
159     if (ramBufferPosition == ramBufferLen) // passed end, fill with 0s
160     {
161         memset(streamBufferL, 0, STREAM_BLOCK_LEN);
162         memset(streamBufferR, 0, STREAM_BLOCK_LEN);
163     }
164     else
165     {
166         u32 bytesLeft = ramBufferLen - ramBufferPosition;
167 
168         // first see if we have enough buffers left for the entire 4K
169         if (bytesLeft >= STREAM_BLOCK_LEN)
170         {
171             memcpy(streamBufferL, (void*)((u8*)ramBufferL + ramBufferPosition), STREAM_BLOCK_LEN);
172             memcpy(streamBufferR, (void*)((u8*)ramBufferR + ramBufferPosition), STREAM_BLOCK_LEN);
173 
174             ramBufferPosition += STREAM_BLOCK_LEN;
175         }
176         else
177         {
178             memset(streamBufferL, 0, STREAM_BLOCK_LEN);
179             memset(streamBufferR, 0, STREAM_BLOCK_LEN);
180 
181             if (bytesLeft)
182             {
183                 memcpy(streamBufferL, (void*)(ramBufferL + ramBufferPosition), bytesLeft);
184                 memcpy(streamBufferR, (void*)(ramBufferR + ramBufferPosition), bytesLeft);
185             }
186 
187             ramBufferPosition = ramBufferLen;
188         }
189     }
190 
191     if (buffer == 0)    // if we just updated the first buffer program loop context for ADPCM
192     {
193         AXPBADPCMLOOP   loop;
194 
195         loop.loop_pred_scale    = (u16)(*((u8*)(streamBufferL)));
196         loop.loop_yn1           = 0;
197         loop.loop_yn2           = 0;
198 
199         AXSetVoiceAdpcmLoop(streamL, &loop);
200 
201         loop.loop_pred_scale    = (u16)(*((u8*)(streamBufferR)));
202         loop.loop_yn1           = 0;
203         loop.loop_yn2           = 0;
204 
205         AXSetVoiceAdpcmLoop(streamR, &loop);
206     }
207 
208     DCFlushRange(streamBufferL, STREAM_BLOCK_LEN);
209     DCFlushRange(streamBufferR, STREAM_BLOCK_LEN);
210 
211     ARQPostRequest(
212         &taskL,
213         0,
214         ARQ_TYPE_MRAM_TO_ARAM,
215         ARQ_PRIORITY_HIGH,
216         (u32)streamBufferL,
217         aramByteAddressL,
218         STREAM_BLOCK_LEN,
219         NULL
220         );
221 
222     ARQPostRequest(
223         &taskR,
224         0,
225         ARQ_TYPE_MRAM_TO_ARAM,
226         ARQ_PRIORITY_HIGH,
227         (u32)streamBufferR,
228         aramByteAddressR,
229         STREAM_BLOCK_LEN,
230         NULL
231         );
232 }
233 #endif
234 
235 /*---------------------------------------------------------------------------*
236  *---------------------------------------------------------------------------*/
callbackAudioFrame(void)237 static void callbackAudioFrame(void)
238 {
239     // tell the mixer to update settings
240     MIXUpdateSettings();
241 
242     switch (flag)
243     {
244     case STREAM_NONE:
245     case STREAM_INITIALIZING:
246 
247         break;
248 
249     case STREAM_STARTED:
250 
251         if (streamR)
252         {
253 #ifndef HOLLYWOOD_REV
254             u32 currentPosition;
255 
256             // get current position of stream
257             currentPosition = *((u32*)&streamR->pb.addr.currentAddressHi);
258 
259             // see if we need to fill any buffers
260             if (currentPosition < streamLastPositionR)  // fill buffer 1
261                 fillAram(1);
262 
263             if ((currentPosition >= aramBufferR1) &&
264                 (streamLastPositionR < aramBufferR1))    // fill buffer 0
265                 fillAram(0);
266 
267             streamLastPositionR = currentPosition;
268 #else
269             if (streamR->pb.state == AX_PB_STATE_STOP)
270             {
271                 flag = STREAM_STOPPING;
272             }
273 #endif
274         }
275 
276         break;
277 
278     case STREAM_STOPPING:
279 
280         if(streamL)
281         {
282             MIXReleaseChannel(streamL);
283             AXFreeVoice(streamL);
284             streamL = NULL;
285         }
286 
287         if(streamR)
288         {
289             MIXReleaseChannel(streamR);
290             AXFreeVoice(streamR);
291             streamR = NULL;
292         }
293 
294         flag = STREAM_STOPPED;
295 
296         break;
297 
298     case STREAM_STOPPED:
299 
300         flag = STREAM_NONE;
301 
302         break;
303 
304     }
305 
306     frames++;
307 }
308 
309 
310 /*---------------------------------------------------------------------------*
311  *---------------------------------------------------------------------------*/
312 #ifndef HOLLYWOOD_REV
startVoices(u32 task)313 static void startVoices(u32 task)
314 {
315     ARQRequest *p = (ARQRequest*)task;
316 
317     if (streamL)    AXSetVoiceState(streamL, AX_PB_STATE_RUN);
318     if (streamR)    AXSetVoiceState(streamR, AX_PB_STATE_RUN);
319 
320     flag = STREAM_STARTED;
321 }
322 #endif
323 
324 /*---------------------------------------------------------------------------*
325  *---------------------------------------------------------------------------*/
326 #ifndef HOLLYWOOD_REV
startStreamPcm16(void)327 static void startStreamPcm16(void)
328 {
329     if (flag != STREAM_NONE)
330         return;
331 
332     // allocate voices for use
333     streamL = AXAcquireVoice(15, NULL, 0);
334     streamR = AXAcquireVoice(15, NULL, 0);
335 
336     // set source buffer to PCM16 data
337     ramBufferL      = ramBufferLPcm16;
338     ramBufferR      = ramBufferRPcm16;
339     ramBufferLen    = ramBufferLenPcm16;
340 
341     // initialize the ARAM buffer addresses in word mode
342     aramBufferL0    = STREAM_BUFFERL_START  / 2;
343     aramBufferL1    = STREAM_BUFFERL_HALF   / 2;
344     aramBufferLEnd  = (STREAM_BUFFERL_END    / 2) - 1;
345     aramBufferR0    = STREAM_BUFFERR_START  / 2;
346     aramBufferR1    = STREAM_BUFFERR_HALF   / 2;
347     aramBufferREnd  = (STREAM_BUFFERR_END    / 2) - 1;
348 
349     // setup the voice, kick off a ARQ task to fill the buffer and use the
350     // callback to start the voice
351     if (streamL)
352     {
353         AXPBADDR        addr;
354 
355         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
356 
357         addr.loopFlag           = AXPBADDR_LOOP_ON;
358         addr.format             = AX_PB_FORMAT_PCM16;
359         addr.loopAddressHi      = (u16)(aramBufferL0 >> 16);
360         addr.loopAddressLo      = (u16)(aramBufferL0 & 0xFFFF);
361         addr.endAddressHi       = (u16)(aramBufferLEnd >> 16);
362         addr.endAddressLo       = (u16)(aramBufferLEnd & 0xFFFF);
363         addr.currentAddressHi   = (u16)(aramBufferL0 >> 16);
364         addr.currentAddressLo   = (u16)(aramBufferL0 & 0xFFFF);
365 
366         AXSetVoiceAddr(streamL, &addr);                     // input addressing
367         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
368     }
369 
370     if (streamR)
371     {
372         AXPBADDR        addr;
373 
374         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
375 
376         addr.loopFlag           = AXPBADDR_LOOP_ON;
377         addr.format             = AX_PB_FORMAT_PCM16;
378         addr.loopAddressHi      = (u16)(aramBufferR0 >> 16);
379         addr.loopAddressLo      = (u16)(aramBufferR0 & 0xFFFF);
380         addr.endAddressHi       = (u16)(aramBufferREnd >> 16);
381         addr.endAddressLo       = (u16)(aramBufferREnd & 0xFFFF);
382         addr.currentAddressHi   = (u16)(aramBufferR0 >> 16);
383         addr.currentAddressLo   = (u16)(aramBufferR0 & 0xFFFF);
384 
385         AXSetVoiceAddr(streamR, &addr);                   // input addressing
386         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);     // no SRC
387     }
388 
389     // use the right side for buffer position
390     streamLastPositionR = 0;
391 
392     // fill the ARAM buffers then use the ARQ callback to start
393     // the voices
394     ARQPostRequest(
395         &taskL,
396         0,
397         ARQ_TYPE_MRAM_TO_ARAM,
398         ARQ_PRIORITY_HIGH,
399         (u32)ramBufferL,
400         STREAM_BUFFERL_START,
401         STREAM_BLOCK_LEN * 2,
402         NULL
403         );
404 
405     ARQPostRequest(
406         &taskR,
407         0,
408         ARQ_TYPE_MRAM_TO_ARAM,
409         ARQ_PRIORITY_HIGH,
410         (u32)ramBufferR,
411         STREAM_BUFFERR_START,
412         STREAM_BLOCK_LEN * 2,
413         &startVoices
414         );
415 
416     ramBufferPosition   = STREAM_BLOCK_LEN * 2;
417     streamLastPositionR = aramBufferR0;
418 
419     flag = STREAM_INITIALIZING;
420 }
421 #else
startStreamPcm16(void)422 static void startStreamPcm16(void)
423 {
424     if (flag != STREAM_NONE)
425         return;
426 
427     // allocate voices for use
428     streamL = AXAcquireVoice(15, NULL, 0);
429     streamR = AXAcquireVoice(15, NULL, 0);
430 
431     // setup the voice, kick off a ARQ task to fill the buffer and use the
432     // callback to start the voice
433     if (streamL)
434     {
435         AXPBADDR        addr;
436         u32             cu_addr;
437         u32             le_addr;
438         u32             zr_addr;
439 
440         cu_addr = ramBufferLPcm16 >> 1;
441         le_addr = (ramBufferLPcm16 + ramBufferLenPcm16 - 2) >> 1;
442         zr_addr = (OSCachedToPhysical(zeroBuffer)) >> 1;
443 
444         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
445 
446         addr.loopFlag           = AXPBADDR_LOOP_OFF;
447         addr.format             = AX_PB_FORMAT_PCM16;
448         addr.loopAddressHi      = (u16)(zr_addr >> 16);
449         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
450         addr.endAddressHi       = (u16)(le_addr >> 16);
451         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
452         addr.currentAddressHi   = (u16)(cu_addr >> 16);
453         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
454 
455         AXSetVoiceAddr(streamL, &addr);                     // input addressing
456         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
457 
458         AXSetVoiceState(streamL, AX_PB_STATE_RUN);
459     }
460 
461     if (streamR)
462     {
463         AXPBADDR        addr;
464         u32             cu_addr;
465         u32             le_addr;
466         u32             zr_addr;
467 
468         cu_addr = ramBufferRPcm16 >> 1;
469         le_addr = (ramBufferRPcm16 + ramBufferLenPcm16 - 2) >> 1;
470         zr_addr = (OSCachedToPhysical(zeroBuffer)) >> 1;
471 
472         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
473 
474         addr.loopFlag           = AXPBADDR_LOOP_OFF;
475         addr.format             = AX_PB_FORMAT_PCM16;
476         addr.loopAddressHi      = (u16)(zr_addr >> 16);
477         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
478         addr.endAddressHi       = (u16)(le_addr >> 16);
479         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
480         addr.currentAddressHi   = (u16)(cu_addr >> 16);
481         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
482 
483         AXSetVoiceAddr(streamR, &addr);                   // input addressing
484         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);     // no SRC
485 
486         AXSetVoiceState(streamR, AX_PB_STATE_RUN);
487     }
488 
489     flag = STREAM_STARTED;
490 }
491 #endif
492 
493 /*---------------------------------------------------------------------------*
494  *---------------------------------------------------------------------------*/
495 #ifndef HOLLYWOOD_REV
startStreamPcm8(void)496 static void startStreamPcm8(void)
497 {
498     if (flag != STREAM_NONE)
499         return;
500 
501     // allocate a voice for use
502     streamL = AXAcquireVoice(15, NULL, 0);
503     streamR = AXAcquireVoice(15, NULL, 0);
504 
505     // set source buffer to PCM16 data
506     ramBufferL      = ramBufferLPcm8;
507     ramBufferR      = ramBufferRPcm8;
508     ramBufferLen    = ramBufferLenPcm8;
509 
510     // initialize the ARAM buffer addresses in word mode
511     aramBufferL0    = STREAM_BUFFERL_START;
512     aramBufferL1    = STREAM_BUFFERL_HALF;
513     aramBufferLEnd  = STREAM_BUFFERL_END - 1;
514     aramBufferR0    = STREAM_BUFFERR_START;
515     aramBufferR1    = STREAM_BUFFERR_HALF;
516     aramBufferREnd  = STREAM_BUFFERR_END - 1;
517 
518     // setup the voice, kick off a ARQ task to fill the buffer and use the
519     // callback to start the voice
520     if (streamL)
521     {
522         AXPBADDR        addr;
523 
524         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
525 
526         addr.loopFlag           = AXPBADDR_LOOP_ON;
527         addr.format             = AX_PB_FORMAT_PCM8;
528         addr.loopAddressHi      = (u16)(aramBufferL0 >> 16);
529         addr.loopAddressLo      = (u16)(aramBufferL0 & 0xFFFF);
530         addr.endAddressHi       = (u16)(aramBufferLEnd >> 16);
531         addr.endAddressLo       = (u16)(aramBufferLEnd & 0xFFFF);
532         addr.currentAddressHi   = (u16)(aramBufferL0 >> 16);
533         addr.currentAddressLo   = (u16)(aramBufferL0 & 0xFFFF);
534 
535         AXSetVoiceAddr(streamL, &addr);                     // input addressing
536         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
537     }
538 
539     if (streamR)
540     {
541         AXPBADDR        addr;
542 
543         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
544 
545         addr.loopFlag           = AXPBADDR_LOOP_ON;
546         addr.format             = AX_PB_FORMAT_PCM8;
547         addr.loopAddressHi      = (u16)(aramBufferR0 >> 16);
548         addr.loopAddressLo      = (u16)(aramBufferR0 & 0xFFFF);
549         addr.endAddressHi       = (u16)(aramBufferREnd >> 16);
550         addr.endAddressLo       = (u16)(aramBufferREnd & 0xFFFF);
551         addr.currentAddressHi   = (u16)(aramBufferR0 >> 16);
552         addr.currentAddressLo   = (u16)(aramBufferR0 & 0xFFFF);
553 
554         AXSetVoiceAddr(streamR, &addr);                     // input addressing
555         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);       // no SRC
556     }
557 
558     // use the right side for buffer position
559     streamLastPositionR = 0;
560 
561     // fill the ARAM buffers then use the ARQ callback to start
562     // the voices
563     ARQPostRequest(
564         &taskL,
565         0,
566         ARQ_TYPE_MRAM_TO_ARAM,
567         ARQ_PRIORITY_HIGH,
568         (u32)ramBufferL,
569         STREAM_BUFFERL_START,
570         STREAM_BLOCK_LEN * 2,
571         NULL
572         );
573 
574     ARQPostRequest(
575         &taskR,
576         0,
577         ARQ_TYPE_MRAM_TO_ARAM,
578         ARQ_PRIORITY_HIGH,
579         (u32)ramBufferR,
580         STREAM_BUFFERR_START,
581         STREAM_BLOCK_LEN * 2,
582         &startVoices
583         );
584 
585     ramBufferPosition   = STREAM_BLOCK_LEN * 2;
586     streamLastPositionR = aramBufferR0;
587 
588     flag = STREAM_INITIALIZING;
589 }
590 #else
startStreamPcm8(void)591 static void startStreamPcm8(void)
592 {
593     if (flag != STREAM_NONE)
594         return;
595 
596     // allocate a voice for use
597     streamL = AXAcquireVoice(15, NULL, 0);
598     streamR = AXAcquireVoice(15, NULL, 0);
599 
600     // setup the voice, kick off a ARQ task to fill the buffer and use the
601     // callback to start the voice
602     if (streamL)
603     {
604         AXPBADDR        addr;
605         u32             cu_addr;
606         u32             le_addr;
607         u32             zr_addr;
608 
609         cu_addr = ramBufferLPcm8;
610         le_addr = ramBufferLPcm8 + ramBufferLenPcm8 - 1;
611         zr_addr = OSCachedToPhysical(zeroBuffer);
612 
613         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
614 
615         addr.loopFlag           = AXPBADDR_LOOP_OFF;
616         addr.format             = AX_PB_FORMAT_PCM8;
617         addr.loopAddressHi      = (u16)(zr_addr >> 16);
618         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
619         addr.endAddressHi       = (u16)(le_addr >> 16);
620         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
621         addr.currentAddressHi   = (u16)(cu_addr >> 16);
622         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
623 
624         AXSetVoiceAddr(streamL, &addr);                     // input addressing
625         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
626 
627         AXSetVoiceState(streamL, AX_PB_STATE_RUN);
628     }
629 
630     if (streamR)
631     {
632         AXPBADDR        addr;
633         u32             cu_addr;
634         u32             le_addr;
635         u32             zr_addr;
636 
637         cu_addr = ramBufferRPcm8;
638         le_addr = ramBufferRPcm8 + ramBufferLenPcm8 - 1;
639         zr_addr = OSCachedToPhysical(zeroBuffer);
640 
641         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
642 
643         addr.loopFlag           = AXPBADDR_LOOP_OFF;
644         addr.format             = AX_PB_FORMAT_PCM8;
645         addr.loopAddressHi      = (u16)(zr_addr >> 16);
646         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
647         addr.endAddressHi       = (u16)(le_addr >> 16);
648         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
649         addr.currentAddressHi   = (u16)(cu_addr >> 16);
650         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
651 
652         AXSetVoiceAddr(streamR, &addr);                     // input addressing
653         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);       // no SRC
654 
655         AXSetVoiceState(streamR, AX_PB_STATE_RUN);
656     }
657 
658     flag = STREAM_STARTED;
659 }
660 #endif
661 
662 /*---------------------------------------------------------------------------*
663  *---------------------------------------------------------------------------*/
664 #ifndef HOLLYWOOD_REV
startStreamAdpcm(void)665 static void startStreamAdpcm(void)
666 {
667     if (flag != STREAM_NONE)
668         return;
669 
670     // allocate a voice for use
671     streamL = AXAcquireVoice(15, NULL, 0);
672     streamR = AXAcquireVoice(15, NULL, 0);
673 
674     // set source buffer to ADPCM data
675     ramBufferL      = ramBufferLAdpcm + sizeof(DSPADPCM);
676     ramBufferR      = ramBufferRAdpcm + sizeof(DSPADPCM);
677 
678     // initialize the ARAM buffer addresses in nibble mode, keep in mind that
679     // it is illegal to put start, loop, or end address on the ADPCM frame
680     // header
681     aramBufferL0    = (STREAM_BUFFERL_START  * 2) + 2;  // +2 to skip header
682     aramBufferL1    = STREAM_BUFFERL_HALF   * 2;
683     aramBufferLEnd  = (STREAM_BUFFERL_END    * 2) -1;
684     aramBufferR0    = (STREAM_BUFFERR_START  * 2) + 2;  // +2 to skip header
685     aramBufferR1    = STREAM_BUFFERR_HALF   * 2;
686     aramBufferREnd  = (STREAM_BUFFERR_END    * 2) -1;
687 
688     // setup the voice, kick off a ARQ task to fill the buffer and use the
689     // callback to start the voice
690     if (streamL)
691     {
692         AXPBADDR        addr;
693         AXPBADPCM       adpcm;
694         DSPADPCM        *dspHeader = (DSPADPCM *)ramBufferLAdpcm;
695 
696         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
697 
698         addr.loopFlag           = AXPBADDR_LOOP_ON;
699         addr.format             = AX_PB_FORMAT_ADPCM;
700         addr.loopAddressHi      = (u16)(aramBufferL0 >> 16);
701         addr.loopAddressLo      = (u16)(aramBufferL0 & 0xFFFF);
702         addr.endAddressHi       = (u16)(aramBufferLEnd >> 16);
703         addr.endAddressLo       = (u16)(aramBufferLEnd & 0xFFFF);
704         addr.currentAddressHi   = (u16)(aramBufferL0 >> 16);
705         addr.currentAddressLo   = (u16)(aramBufferL0 & 0xFFFF);
706 
707         adpcm.a[0][0]           = dspHeader->coef[0];
708         adpcm.a[0][1]           = dspHeader->coef[1];
709         adpcm.a[1][0]           = dspHeader->coef[2];
710         adpcm.a[1][1]           = dspHeader->coef[3];
711         adpcm.a[2][0]           = dspHeader->coef[4];
712         adpcm.a[2][1]           = dspHeader->coef[5];
713         adpcm.a[3][0]           = dspHeader->coef[6];
714         adpcm.a[3][1]           = dspHeader->coef[7];
715         adpcm.a[4][0]           = dspHeader->coef[8];
716         adpcm.a[4][1]           = dspHeader->coef[9];
717         adpcm.a[5][0]           = dspHeader->coef[10];
718         adpcm.a[5][1]           = dspHeader->coef[11];
719         adpcm.a[6][0]           = dspHeader->coef[12];
720         adpcm.a[6][1]           = dspHeader->coef[13];
721         adpcm.a[7][0]           = dspHeader->coef[14];
722         adpcm.a[7][1]           = dspHeader->coef[15];
723         adpcm.gain              = dspHeader->gain;
724         adpcm.pred_scale        = dspHeader->ps;
725         adpcm.yn1               = dspHeader->yn1;
726         adpcm.yn2               = dspHeader->yn2;
727 
728         ramBufferLen = OSRoundUp32B(dspHeader->num_adpcm_nibbles) >> 1;
729 
730         AXSetVoiceType(streamL, AX_PB_TYPE_STREAM);         // no loop context
731         AXSetVoiceAddr(streamL, &addr);                     // input addressing
732         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
733         AXSetVoiceAdpcm(streamL, &adpcm);                   // ADPCM coefficients
734     }
735 
736     if (streamR)
737     {
738         AXPBADDR        addr;
739         AXPBADPCM       adpcm;
740         DSPADPCM        *dspHeader = (DSPADPCM *)ramBufferRAdpcm;
741 
742         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
743 
744         addr.loopFlag           = AXPBADDR_LOOP_ON;
745         addr.format             = AX_PB_FORMAT_ADPCM;
746         addr.loopAddressHi      = (u16)(aramBufferR0 >> 16);
747         addr.loopAddressLo      = (u16)(aramBufferR0 & 0xFFFF);
748         addr.endAddressHi       = (u16)(aramBufferREnd >> 16);
749         addr.endAddressLo       = (u16)(aramBufferREnd & 0xFFFF);
750         addr.currentAddressHi   = (u16)(aramBufferR0 >> 16);
751         addr.currentAddressLo   = (u16)(aramBufferR0 & 0xFFFF);
752 
753         adpcm.a[0][0]           = dspHeader->coef[0];
754         adpcm.a[0][1]           = dspHeader->coef[1];
755         adpcm.a[1][0]           = dspHeader->coef[2];
756         adpcm.a[1][1]           = dspHeader->coef[3];
757         adpcm.a[2][0]           = dspHeader->coef[4];
758         adpcm.a[2][1]           = dspHeader->coef[5];
759         adpcm.a[3][0]           = dspHeader->coef[6];
760         adpcm.a[3][1]           = dspHeader->coef[7];
761         adpcm.a[4][0]           = dspHeader->coef[8];
762         adpcm.a[4][1]           = dspHeader->coef[9];
763         adpcm.a[5][0]           = dspHeader->coef[10];
764         adpcm.a[5][1]           = dspHeader->coef[11];
765         adpcm.a[6][0]           = dspHeader->coef[12];
766         adpcm.a[6][1]           = dspHeader->coef[13];
767         adpcm.a[7][0]           = dspHeader->coef[14];
768         adpcm.a[7][1]           = dspHeader->coef[15];
769         adpcm.gain              = dspHeader->gain;
770         adpcm.pred_scale        = dspHeader->ps;
771         adpcm.yn1               = dspHeader->yn1;
772         adpcm.yn2               = dspHeader->yn2;
773 
774         AXSetVoiceType(streamR, AX_PB_TYPE_STREAM);       // no loop context
775         AXSetVoiceAddr(streamR, &addr);                   // input addressing
776         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);     // no SRC
777         AXSetVoiceAdpcm(streamR, &adpcm);                 // ADPCM coefficients
778     }
779 
780     // use the right side for buffer position
781     streamLastPositionR = 0;
782 
783     // fill the ARAM buffers then use the ARQ callback to start
784     // the voices
785     ARQPostRequest(
786         &taskL,
787         0,
788         ARQ_TYPE_MRAM_TO_ARAM,
789         ARQ_PRIORITY_HIGH,
790         (u32)ramBufferL,
791         STREAM_BUFFERL_START,
792         STREAM_BLOCK_LEN * 2,
793         NULL
794         );
795 
796     ARQPostRequest(
797         &taskR,
798         0,
799         ARQ_TYPE_MRAM_TO_ARAM,
800         ARQ_PRIORITY_HIGH,
801         (u32)ramBufferR,
802         STREAM_BUFFERR_START,
803         STREAM_BLOCK_LEN * 2,
804         &startVoices
805         );
806 
807     ramBufferPosition   = STREAM_BLOCK_LEN * 2;
808     streamLastPositionR = aramBufferR0;
809 
810     flag = STREAM_INITIALIZING;
811 }
812 #else
startStreamAdpcm(void)813 static void startStreamAdpcm(void)
814 {
815     if (flag != STREAM_NONE)
816         return;
817 
818     // allocate a voice for use
819     streamL = AXAcquireVoice(15, NULL, 0);
820     streamR = AXAcquireVoice(15, NULL, 0);
821 
822     // setup the voice, kick off a ARQ task to fill the buffer and use the
823     // callback to start the voice
824     if (streamL)
825     {
826         AXPBADDR        addr;
827         AXPBADPCM       adpcm;
828         DSPADPCM        *dspHeader = (DSPADPCM *)OSPhysicalToCached(ramBufferLAdpcm);
829         u32             cu_addr;
830         u32             le_addr;
831         u32             zr_addr;
832 
833         cu_addr = ((ramBufferLAdpcm + sizeof(DSPADPCM)) << 1) + dspHeader->ca;
834         le_addr = ((ramBufferLAdpcm + sizeof(DSPADPCM)) << 1) + dspHeader->ea;
835         zr_addr = ((OSCachedToPhysical(zeroBuffer)) << 1) + 2;
836 
837         MIXInitChannel(streamL, 0, 0, -904, -904, -904, 0, 127, 0);
838 
839         addr.loopFlag           = AXPBADDR_LOOP_OFF;
840         addr.format             = AX_PB_FORMAT_ADPCM;
841         addr.loopAddressHi      = (u16)(zr_addr >> 16);
842         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
843         addr.endAddressHi       = (u16)(le_addr >> 16);
844         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
845         addr.currentAddressHi   = (u16)(cu_addr >> 16);
846         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
847 
848         adpcm.a[0][0]           = dspHeader->coef[0];
849         adpcm.a[0][1]           = dspHeader->coef[1];
850         adpcm.a[1][0]           = dspHeader->coef[2];
851         adpcm.a[1][1]           = dspHeader->coef[3];
852         adpcm.a[2][0]           = dspHeader->coef[4];
853         adpcm.a[2][1]           = dspHeader->coef[5];
854         adpcm.a[3][0]           = dspHeader->coef[6];
855         adpcm.a[3][1]           = dspHeader->coef[7];
856         adpcm.a[4][0]           = dspHeader->coef[8];
857         adpcm.a[4][1]           = dspHeader->coef[9];
858         adpcm.a[5][0]           = dspHeader->coef[10];
859         adpcm.a[5][1]           = dspHeader->coef[11];
860         adpcm.a[6][0]           = dspHeader->coef[12];
861         adpcm.a[6][1]           = dspHeader->coef[13];
862         adpcm.a[7][0]           = dspHeader->coef[14];
863         adpcm.a[7][1]           = dspHeader->coef[15];
864         adpcm.gain              = dspHeader->gain;
865         adpcm.pred_scale        = dspHeader->ps;
866         adpcm.yn1               = dspHeader->yn1;
867         adpcm.yn2               = dspHeader->yn2;
868 
869         AXSetVoiceType(streamL, AX_PB_TYPE_STREAM);         // no loop context
870         AXSetVoiceAddr(streamL, &addr);                     // input addressing
871         AXSetVoiceSrcType(streamL, AX_SRC_TYPE_NONE);       // no SRC
872         AXSetVoiceAdpcm(streamL, &adpcm);                   // ADPCM coefficients
873 
874         AXSetVoiceState(streamL, AX_PB_STATE_RUN);
875     }
876 
877     if (streamR)
878     {
879         AXPBADDR        addr;
880         AXPBADPCM       adpcm;
881         DSPADPCM        *dspHeader = (DSPADPCM *)OSPhysicalToCached(ramBufferRAdpcm);
882         u32             cu_addr;
883         u32             le_addr;
884         u32             zr_addr;
885 
886         cu_addr = ((ramBufferRAdpcm + sizeof(DSPADPCM)) << 1) + dspHeader->ca;
887         le_addr = ((ramBufferRAdpcm + sizeof(DSPADPCM)) << 1) + dspHeader->ea;
888         zr_addr = ((OSCachedToPhysical(zeroBuffer)) << 1) + 2;
889 
890         MIXInitChannel(streamR, 0, 0, -904, -904, -904, 127, 127, 0);
891 
892         addr.loopFlag           = AXPBADDR_LOOP_OFF;
893         addr.format             = AX_PB_FORMAT_ADPCM;
894         addr.loopAddressHi      = (u16)(zr_addr >> 16);
895         addr.loopAddressLo      = (u16)(zr_addr &  0xFFFF);
896         addr.endAddressHi       = (u16)(le_addr >> 16);
897         addr.endAddressLo       = (u16)(le_addr &  0xFFFF);
898         addr.currentAddressHi   = (u16)(cu_addr >> 16);
899         addr.currentAddressLo   = (u16)(cu_addr &  0xFFFF);
900 
901         adpcm.a[0][0]           = dspHeader->coef[0];
902         adpcm.a[0][1]           = dspHeader->coef[1];
903         adpcm.a[1][0]           = dspHeader->coef[2];
904         adpcm.a[1][1]           = dspHeader->coef[3];
905         adpcm.a[2][0]           = dspHeader->coef[4];
906         adpcm.a[2][1]           = dspHeader->coef[5];
907         adpcm.a[3][0]           = dspHeader->coef[6];
908         adpcm.a[3][1]           = dspHeader->coef[7];
909         adpcm.a[4][0]           = dspHeader->coef[8];
910         adpcm.a[4][1]           = dspHeader->coef[9];
911         adpcm.a[5][0]           = dspHeader->coef[10];
912         adpcm.a[5][1]           = dspHeader->coef[11];
913         adpcm.a[6][0]           = dspHeader->coef[12];
914         adpcm.a[6][1]           = dspHeader->coef[13];
915         adpcm.a[7][0]           = dspHeader->coef[14];
916         adpcm.a[7][1]           = dspHeader->coef[15];
917         adpcm.gain              = dspHeader->gain;
918         adpcm.pred_scale        = dspHeader->ps;
919         adpcm.yn1               = dspHeader->yn1;
920         adpcm.yn2               = dspHeader->yn2;
921 
922         AXSetVoiceType(streamR, AX_PB_TYPE_STREAM);       // no loop context
923         AXSetVoiceAddr(streamR, &addr);                   // input addressing
924         AXSetVoiceSrcType(streamR, AX_SRC_TYPE_NONE);     // no SRC
925         AXSetVoiceAdpcm(streamR, &adpcm);                 // ADPCM coefficients
926 
927         AXSetVoiceState(streamR, AX_PB_STATE_RUN);
928     }
929 
930     flag = STREAM_STARTED;
931 }
932 #endif
933 
934 /*---------------------------------------------------------------------------*
935  *---------------------------------------------------------------------------*/
stopStream(void)936 static void stopStream(void)
937 {
938     if (flag != STREAM_STARTED)
939         return;
940 
941     if (streamR)
942     {
943         MIXSetFader(streamL, -960);
944         MIXSetFader(streamR, -960);
945     }
946 
947     flag = STREAM_STOPPING;
948 }
949 
950 
951 /*---------------------------------------------------------------------------*
952  *---------------------------------------------------------------------------*/
953 #define mROUNDUP32(x)      (((u32)(x) + 32 - 1) & ~(32 - 1))
putSamplesIntoRam(char * path)954 static u32 putSamplesIntoRam(char *path)
955 {
956     DVDFileInfo handle;
957     u32         round_length;
958     s32         read_length;
959     void        *buffer;
960 
961     // sine64.raw
962     if (!DVDOpen(path, &handle))
963     {
964         char ch[1024];
965 
966         sprintf(ch, "Cannot open %s", path);
967 
968         ASSERTMSG(0, ch);
969     }
970 
971     // make sure file length s not 0
972     ASSERTMSG(DVDGetLength(&handle), "File length is 0\n");
973 
974     round_length = mROUNDUP32(DVDGetLength(&handle));
975 #ifndef HOLLYWOOD_REV
976     buffer       = OSAlloc(round_length);
977 #else
978     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
979 #endif
980 
981     // make sure we got a buffer
982     ASSERTMSG(buffer, "Unable to allocate buffer\n");
983 
984     read_length     = DVDRead(&handle, buffer, (s32)(round_length), 0);
985 
986     // make sure we read the file correctly
987     ASSERTMSG(read_length > 0, "Read length <= 0\n");
988 
989 #ifndef HOLLYWOOD_REV
990     return (u32)buffer;
991 #else
992     return OSCachedToPhysical(buffer);
993 #endif
994 }
995 
996 
997 /*---------------------------------------------------------------------------*
998  *---------------------------------------------------------------------------*/
main(void)999 void main(void)
1000 {
1001     PADStatus    pads[PAD_MAX_CONTROLLERS];
1002 #ifdef HOLLYWOOD_REV
1003     void         *arenaMem2Lo;
1004     void         *arenaMem2Hi;
1005 #endif
1006 
1007     DEMOInit(NULL);
1008 
1009 #ifndef HOLLYWOOD_REV
1010     ARInit(aramMemArray, MAX_ARAM_BLOCKS);
1011     ARQInit();
1012 #else
1013     // initialize Exp Heap on MEM2
1014     arenaMem2Lo = OSGetMEM2ArenaLo();
1015     arenaMem2Hi = OSGetMEM2ArenaHi();
1016     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
1017 #endif
1018 
1019     AIInit(NULL);
1020     AXInit();
1021     MIXInit();
1022 
1023     frames  = 0;
1024 
1025     // put samples in to RAM
1026     ramBufferLPcm16     = putSamplesIntoRam("/axdemo/stream/left.pcm16");
1027     ramBufferRPcm16     = putSamplesIntoRam("/axdemo/stream/right.pcm16");
1028     ramBufferLenPcm16   = 827270;
1029 
1030     ramBufferLPcm8      = putSamplesIntoRam("/axdemo/stream/left.pcm8");
1031     ramBufferRPcm8      = putSamplesIntoRam("/axdemo/stream/right.pcm8");
1032     ramBufferLenPcm8    = 413635;
1033 
1034     ramBufferLAdpcm     = putSamplesIntoRam("/axdemo/stream/left.adpcm");
1035     ramBufferRAdpcm     = putSamplesIntoRam("/axdemo/stream/right.adpcm");
1036 
1037 #ifdef HOLLYWOOD_REV
1038     // Zero Buffer
1039     zeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8);
1040     memset(zeroBuffer, 0, ZEROBUFFER_BYTES);
1041     DCFlushRange(zeroBuffer, ZEROBUFFER_BYTES);
1042 #endif
1043 
1044     // register user callback for audio frames notification
1045     AXRegisterCallback(&callbackAudioFrame);
1046 
1047     OSReport("Press the A button to play PCM16 stream.\n");
1048     OSReport("Press the B button to play PCM8 stream.\n");
1049     OSReport("Press the X button to play DSP ADPCM stream.\n");
1050     OSReport("Press the Y button to stop the stream.\n");
1051 
1052     OSReport("Press Menu button to exit program\n");
1053 
1054     while (1)
1055     {
1056 
1057         if (streamR)
1058         {
1059             OSReport("L:%x R:%x\n",
1060                      *(u32*)&streamL->pb.addr.currentAddressHi,
1061                      *(u32*)&streamR->pb.addr.currentAddressHi
1062                 );
1063         }
1064 
1065         // wait for retrace
1066         VIWaitForRetrace();
1067 
1068         // check pad
1069         PADRead(pads);
1070 
1071         // see if we should quit
1072         if (pads[0].button & PAD_BUTTON_MENU)
1073             break;
1074 
1075         // run PCM16 stream
1076         if (pads[0].button & PAD_BUTTON_A)
1077             startStreamPcm16();
1078 
1079         // run PCM8 stream
1080         if (pads[0].button & PAD_BUTTON_B)
1081             startStreamPcm8();
1082 
1083         // run ADPCM stream
1084         if (pads[0].button & PAD_BUTTON_X)
1085             startStreamAdpcm();
1086 
1087         // stop stream
1088         if (pads[0].button & PAD_BUTTON_Y)
1089             stopStream();
1090     }
1091 
1092     MIXQuit();
1093     AXQuit();
1094 
1095     OSReport("AX ran %x audio frames\n", frames);
1096 
1097     OSHalt("End of program\n");
1098 }
1099