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