1 /*---------------------------------------------------------------------------*
2 Project: Revolution AX simple demo
3 File: axsimple.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: axsimple.c,v $
14 Revision 1.4 02/03/2006 12:12:08 aka
15 Revised comment.
16
17 Revision 1.3 02/02/2006 07:56:31 aka
18 Modified using MEM functions instead of OSAlloc()/OSFree().
19
20 Revision 1.2 02/01/2006 05:42:37 aka
21 Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif.
22
23 Revision 1.1 11/04/2005 05:01:39 aka
24 Imported from dolphin tree.
25
26 11 03/04/04 13:25:00 Suzuki
27 remove the definition of DSPADPCM
28
29 10 12/04/02 6:23p Dante
30 Fixed pred_scale, yn1, & yn2 references for AXPBADPCM structure.
31
32 9 02/11/20 7:39 Dante
33 Added looped sample support, and fixed dropped sample callback support
34
35 8 02/11/13 11:06 Dante
36 Bug fix: GetDSPADPCMDataSize32B's conversion from nibbles to bytes must
37 occur after round up. Clean up (removed unused variables).
38
39 7 02/11/13 4:03 Dante
40 Fixed GetDSPADPCMDataSize32B to return bytes not nibbles. Changed
41 OSReports to reflect size.
42
43 6 02/11/12 9:52 Dante
44 Removed redundant SRC commands
45
46 5 02/11/09 12:37 Dante
47 Additions from SDK 2002-Dec-05 Patch1
48
49 4 02/11/09 12:34 Dante
50 Added support for non-native sample rate ADPCM files and a printed
51 intro.
52
53 3 02/10/30 6:31 Dante
54 Set the loop address for one shot samples to the zero buffer
55
56 $NoKeywords: $
57 *---------------------------------------------------------------------------*/
58
59 /*---------------------------------------------------------------------------*
60 This program loads and initializes ADPCM samples. The samples were created
61 using DSPADPCM.exe. The files are expected to have a 96 byte header.
62 *---------------------------------------------------------------------------*/
63
64 #include <demo.h>
65 #include <string.h>
66 #ifdef HOLLYWOOD_REV
67 #include <revolution/mem.h>
68 #endif
69
70 // User defines
71 #define NUM_SAMPLES 10
72 #define NUM_BUTTON_MAPS 11
73 // Filenames for samples to be played
74 char SampleFiles [NUM_SAMPLES][256] =
75 {
76 "axdemo/simple/snare.dsp",
77 "axdemo/simple/tom.dsp",
78 "axdemo/simple/cymbal.dsp",
79 "axdemo/simple/ride.dsp",
80 "axdemo/simple/cowbell.dsp",
81 "axdemo/simple/kick.dsp",
82 "axdemo/simple/bongo1.dsp",
83 "axdemo/simple/bongo2.dsp",
84 "axdemo/simple/bongo3.dsp",
85 "axdemo/simple/bongo4.dsp",
86 };
87 // Button mappings for samples {Button, index in file table}
88 u32 ButtonMap [NUM_BUTTON_MAPS][2] =
89 {
90 {PAD_BUTTON_A, 0},
91 {PAD_BUTTON_B, 1},
92 {PAD_BUTTON_X, 2},
93 {PAD_BUTTON_Y, 3},
94 {PAD_TRIGGER_Z, 4},
95 {PAD_TRIGGER_L, 5},
96 {PAD_TRIGGER_R, 5},
97 {PAD_BUTTON_DOWN, 6},
98 {PAD_BUTTON_UP, 7},
99 {PAD_BUTTON_LEFT, 8},
100 {PAD_BUTTON_RIGHT, 9}
101 };
102
103 // This demo uses a very simple mixing paradigm. All sounds are played at
104 // a volume of 1.0 (0x8000). Please see the MIX library for a more
105 // comprehensive mixing library
106 #ifndef HOLLYWOOD_REV
107 AXPBMIX g_mix = {
108 0x8000, // volume left
109 0x0000, // volume ramp left
110 0x8000, // volume right
111 0x0000, // volume ramp right
112 0x0000, // volume AUX A left
113 0x0000, // volume ramp AUX A left
114 0x0000, // volume AUX A right
115 0x0000, // volume ramp AUX A right
116 0x0000, // volume AUX B left
117 0x0000, // volume ramp AUX B left
118 0x0000, // volume AUX B right
119 0x0000, // volume ramp AUX B right
120 0x0000, // volume AUX B surround
121 0x0000, // volume ramp AUX B surround
122 0x0000, // volume surround
123 0x0000, // volume ramp surround
124 0x0000, // volume AUX A surround
125 0x0000, // volume ramp AUX A surround
126 };
127 #else
128 AXPBMIX g_mix = {
129 0x8000, // volume left
130 0x0000, // volume ramp left
131 0x8000, // volume right
132 0x0000, // volume ramp right
133
134 0x0000, // volume AUX A left
135 0x0000, // volume ramp AUX A left
136 0x0000, // volume AUX A right
137 0x0000, // volume ramp AUX A right
138
139 0x0000, // volume AUX B left
140 0x0000, // volume ramp AUX B left
141 0x0000, // volume AUX B right
142 0x0000, // volume ramp AUX B right
143
144 0x0000, // volume AUX C left
145 0x0000, // volume ramp AUX C left
146 0x0000, // volume AUX C right
147 0x0000, // volume ramp AUX C right
148
149 0x0000, // volume surround
150 0x0000, // volume ramp surround
151 0x0000, // volume AUX A surround
152 0x0000, // volume ramp AUX A surround
153 0x0000, // volume AUX B surround
154 0x0000, // volume ramp AUX B surround
155 0x0000, // volume AUX C surround
156 0x0000, // volume ramp AUX C surround
157 };
158 #endif
159
160 AXPBVE g_ve = {
161 0x8000, // volume at start of frame, 0x8000 = 1.0
162 0 // signed per sample delta (160 samples per frame)
163 };
164
165 // User Structures to keep track of data
166 #ifndef HOLLYWOOD_REV
167 typedef struct
168 {
169 void *mramAddr;
170 void *aramAddr;
171 u32 aramLength;
172 } SampleInfo;
173 #else
174 typedef struct
175 {
176 void *mramAddr;
177
178 } SampleInfo;
179 #endif
180
181 typedef struct
182 {
183 AXVPB *voice;
184 u32 state;
185 } VoiceInfo;
186
187 // Voice Defines
188 #define VOICE_PRIO_HIGH 31
189 #define VOICE_PRIO_MED 15
190 #define VOICE_PRIO_LOW 1
191
192 #define VOICE_STATE_STOPPED 0
193 #define VOICE_STATE_START 1
194 #define VOICE_STATE_STARTED 2
195 #define VOICE_STATE_PLAYING 3
196 #define VOICE_STATE_STOP 4
197
198 #ifdef HOLLYWOOD_REV
199 // Exp Heap
200 static MEMHeapHandle hExpHeap;
201 #endif
202
203 // zero buffer size
204 #define ZEROBUFFER_BYTES 256
205 #ifdef HOLLYWOOD_REV
206 static u8 *zeroBuffer;
207 #endif
208
209 // Utility Macro Functions
210 #define RoundUp64(x) (((u32)(x) + 64 - 1) & ~(64 - 1))
211 #define Bytes2Nibbles(n) (n << 1)
212 #define Nibbles2Bytes(n) (n >> 1)
213 #define GetDSPADPCMDataAddress(a) ((void*)((u32)a + sizeof(DSPADPCM)))
214 #define GetDSPADPCMDataSize32B(a) (RoundUp64(((DSPADPCM*)a)->num_adpcm_nibbles) >> 1)
215 #define GetVoiceCurrentAddr32(v) (*(u32 *)(&((v)->pb.addr.currentAddressHi)))
216 #define GetVoiceLoopAddr32(v) (*(u32 *)(&((v)->pb.addr.loopAddressHi)))
217 #define GetVoiceEndAddr32(v) (*(u32 *)(&((v)->pb.addr.endAddressHi)))
218
219 #ifndef HOLLYWOOD_REV
220 // Pointer to the base address of ARAM. Some of ARAM is reserved.
221 // Note that the zero buffer is located at this address in this demo.
222 void* ARAMBaseAddress;
223 #endif
224
225 // Sample Info
226 static SampleInfo Samples[NUM_SAMPLES];
227 // AX Voice info
228 static VoiceInfo Voices[AX_MAX_VOICES];
229
230 #ifndef HOLLYWOOD_REV
231 // Global Variable used to wait for ARAM DMA callback
232 static volatile BOOL IsVoiceLoading = FALSE;
233 #endif
234
235 // function Prototypes
236 static void * LoadFileIntoRam(char *path);
237 static void AudioFrameCallback(void);
238 #ifndef HOLLYWOOD_REV
239 static void AramRequestCallback(u32 task);
240 static void LoadToARAM(void *pMRAMStart, void* pARAMStart, u32 length);
241 static AXVPB* AquireVoiceADPCM(void *pDSPADPCMData, void* pARAMStart);
242 #else
243 static AXVPB* AquireVoiceADPCM(void *pDSPADPCMData);
244 #endif
245 static void LoadSamples(void);
246 static void PlaySample(SampleInfo *sample);
247 static void VoiceCallback(void * voiceIn);
248 static void PrintIntro(void);
249
250 /*---------------------------------------------------------------------------*
251 *---------------------------------------------------------------------------*/
main()252 void main ()
253 {
254 u32 i;
255 u32 button;
256 #ifdef HOLLYWOOD_REV
257 void *arenaMem2Lo;
258 void *arenaMem2Hi;
259 #endif
260
261 // Initialize OS & Audio
262 DEMOInit(NULL);
263 DEMOPadInit();
264
265 #ifndef HOLLYWOOD_REV
266 ARInit(NULL, 0);
267 ARQInit();
268 #else
269 // initialize Exp Heap on MEM2
270 arenaMem2Lo = OSGetMEM2ArenaLo();
271 arenaMem2Hi = OSGetMEM2ArenaHi();
272 hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
273 #endif
274
275 AIInit(NULL);
276 AXInit();
277
278 #ifndef HOLLYWOOD_REV
279 // Get Base ARAM address.
280 ARAMBaseAddress = (void*) ARGetBaseAddress();
281 #endif
282
283 // Load Voice data into MRAM
284 LoadSamples();
285
286 // Register Callback with AX for audio processing
287 AXRegisterCallback(&AudioFrameCallback);
288
289 // Print Intro
290 PrintIntro();
291
292 // Spin
293 while (1)
294 {
295 VIWaitForRetrace();
296
297
298 // User Input
299 DEMOPadRead();
300 button = DEMOPadGetButtonDown(0);
301 // Stop all sounds when START/PAUSE is pressed
302 if (button & PAD_BUTTON_START)
303 {
304 // Stop all voices
305 for (i = 0; i < AX_MAX_VOICES; i++)
306 {
307 Voices[i].state = VOICE_STATE_STOP;
308 }
309 continue;
310 }
311 // Use Button map to start sounds
312 for (i = 0; i < NUM_BUTTON_MAPS; i++)
313 {
314 if (button & ButtonMap[i][0])
315 {
316 PlaySample(&Samples[ButtonMap[i][1]]);
317 }
318 }
319 }
320 }
321
322 /*---------------------------------------------------------------------------*
323 Name: LoadSamples
324
325 Description: Loads ADPCM files into Main Memory (Header + Data) and
326 ARAM (Data)
327
328 Arguments: none
329
330 Returns: none
331 *---------------------------------------------------------------------------*/
332 #ifndef HOLLYWOOD_REV
LoadSamples(void)333 static void LoadSamples(void)
334 {
335 u32 i;
336 u32 offset = 0; // Variable that stores the offsets from base ARAM address
337 u8 *zeroBuffer; // Address for temporary zero buffer
338 void *pMRAMStart;
339
340 // Create zero buffer
341 zeroBuffer = (u8*)OSAlloc(ZEROBUFFER_BYTES);
342 for (i = 0; i < ZEROBUFFER_BYTES; i++)
343 {
344 zeroBuffer[i] = 0;
345 }
346 // Load Zero Buffer into ARAM
347 LoadToARAM(zeroBuffer, ARAMBaseAddress, ZEROBUFFER_BYTES);
348 // Store offset
349 offset = ZEROBUFFER_BYTES;
350 OSFree(zeroBuffer);
351
352 // Load samples
353 for (i = 0; i < NUM_SAMPLES; i++)
354 {
355 // Load ADPCM file into MRAM (96 byte header included)
356 Samples[i].mramAddr = LoadFileIntoRam(SampleFiles[i]);
357
358 // Sanity Check
359 if (Samples[i].mramAddr == NULL)
360 {
361 OSReport("WARNING! Sample %d not loaded\n", i);
362 continue;
363 }
364
365 // Specify ARAM address (Adding offset from previous files)
366 Samples[i].aramAddr = (void *)((u32)ARAMBaseAddress + offset);
367 // Length of data (Rounded to 32B)
368 Samples[i].aramLength = GetDSPADPCMDataSize32B(Samples[i].mramAddr);
369 // The Start address in memory (after 96 Byte header)
370 pMRAMStart = GetDSPADPCMDataAddress(Samples[i].mramAddr);
371 // Store Length of sample (extracted from header)
372 offset += Samples[i].aramLength;
373
374 // Load Sample into ARAM
375 LoadToARAM(pMRAMStart, Samples[i].aramAddr, Samples[i].aramLength);
376
377 OSReport("axsimple: Loading %s at ARAM 0x%08x [%d bytes]\n",
378 SampleFiles[i],
379 Samples[i].aramAddr,
380 Samples[i].aramLength);
381 }
382 }
383 #else
LoadSamples(void)384 static void LoadSamples(void)
385 {
386 u32 i;
387
388 // Zero Buffer
389 zeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8);
390 memset(zeroBuffer, 0, ZEROBUFFER_BYTES);
391 DCFlushRange(zeroBuffer, ZEROBUFFER_BYTES);
392
393 // Load samples
394 for (i = 0; i < NUM_SAMPLES; i++)
395 {
396 // Load ADPCM file into MRAM (96 byte header included)
397 Samples[i].mramAddr = LoadFileIntoRam(SampleFiles[i]);
398
399 // Sanity Check
400 if (Samples[i].mramAddr == NULL)
401 {
402 OSReport("WARNING! Sample %d not loaded\n", i);
403 continue;
404 }
405 }
406 }
407 #endif
408
409 /*---------------------------------------------------------------------------*
410 Name: PlaySample
411
412 Description: Utility function that will play a sample
413
414 Arguments: sample Pointer to the sample information
415
416 Returns: pointer to the allocated voice
417 *---------------------------------------------------------------------------*/
PlaySample(SampleInfo * sample)418 static void PlaySample(SampleInfo *sample)
419 {
420 AXVPB *voice;
421
422 if (sample->mramAddr == NULL)
423 {
424 OSReport("WARNING! Sample not loaded!\n");
425 return;
426 }
427
428 // Acquire Voice and start
429 #ifndef HOLLYWOOD_REV
430 voice = AquireVoiceADPCM(sample->mramAddr, sample->aramAddr);
431 #else
432 voice = AquireVoiceADPCM(sample->mramAddr);
433 #endif
434 if (voice == NULL)
435 {
436 OSReport("WARNING: Ran out of voices!\n");
437 return;
438 }
439 Voices[voice->index].voice = voice;
440 Voices[voice->index].state = VOICE_STATE_START;
441 }
442
443 /*---------------------------------------------------------------------------*
444 Name: AudioFrameCallback
445
446 Description: Callback that process audio data per 5ms audio frame.
447 In this case, it stops, resets, and starts a voice.
448
449 Arguments: none
450
451 Returns: none
452 *---------------------------------------------------------------------------*/
AudioFrameCallback(void)453 static void AudioFrameCallback(void)
454 {
455 u32 i;
456 BOOL bStopFlag = FALSE;
457
458 // Monitor each voice and process states. This must be done in the
459 // callback
460 for (i = 0; i < AX_MAX_VOICES; i++)
461 {
462
463 // Skip NULL entries
464 if (Voices[i].voice == NULL) continue;
465
466 switch (Voices[i].state)
467 {
468 case VOICE_STATE_STOPPED:
469 break;
470 case VOICE_STATE_START:
471 // Start the voice
472 AXSetVoiceState(Voices[i].voice, AX_PB_STATE_RUN);
473 Voices[i].state = VOICE_STATE_STARTED;
474 break;
475 case VOICE_STATE_STARTED:
476 // Skip a frame
477 Voices[i].state = VOICE_STATE_PLAYING;
478 break;
479 case VOICE_STATE_PLAYING:
480 // Check to see if the voice is finished, if so, stop it
481 if (Voices[i].voice->pb.state == AX_PB_STATE_STOP)
482 bStopFlag = TRUE;
483 break;
484 case VOICE_STATE_STOP:
485 // Force a voice to stop
486 bStopFlag = TRUE;
487 break;
488 }
489
490 // A voice must be stopped
491 if (bStopFlag)
492 {
493 AXSetVoiceState(Voices[i].voice, AX_PB_STATE_STOP);
494 AXFreeVoice(Voices[i].voice);
495 Voices[i].voice = NULL;
496 Voices[i].state = VOICE_STATE_STOPPED;
497 bStopFlag = FALSE;
498 }
499 }
500 }
501
502 #ifndef HOLLYWOOD_REV
503 /*---------------------------------------------------------------------------*
504 Name: AramRequestCallback
505
506 Description: Callback for ARAM DMA completion. Zero's a wait variable
507
508 Arguments: unused
509
510 Returns: none
511 *---------------------------------------------------------------------------*/
AramRequestCallback(u32 task)512 static void AramRequestCallback(u32 task)
513 {
514 #pragma unused(task)
515
516 IsVoiceLoading = FALSE;
517 }
518 #endif
519
520 #ifndef HOLLYWOOD_REV
521 /*---------------------------------------------------------------------------*
522 Name: LoadToARAM
523
524 Description: Loads voice data into ARAM sequentially.
525
526 Arguments: pMRAMStart MRAM Start address
527 pARAMStart ARAM Start address
528 length length of data
529
530 Returns: pointer to the allocated voice
531 *---------------------------------------------------------------------------*/
LoadToARAM(void * pMRAMStart,void * pARAMStart,u32 length)532 static void LoadToARAM(void *pMRAMStart, void* pARAMStart, u32 length)
533 {
534 ARQRequest taskM;
535
536 ARQPostRequest(
537 &taskM,
538 0,
539 ARQ_TYPE_MRAM_TO_ARAM,
540 ARQ_PRIORITY_HIGH,
541 (u32)pMRAMStart,
542 (u32)pARAMStart,
543 length,
544 AramRequestCallback
545 );
546
547 // Callback will release
548 IsVoiceLoading = TRUE;
549 while (IsVoiceLoading)
550 {
551 }
552 }
553 #endif
554
555 /*---------------------------------------------------------------------------*
556 Name: VoiceCallback
557
558 Description: Callback for when a voice is dropped.
559
560 Arguments: unused
561
562 Returns: none
563 *---------------------------------------------------------------------------*/
VoiceCallback(void * voiceIn)564 static void VoiceCallback(void * voiceIn)
565 {
566 AXVPB *voice = (AXVPB*)voiceIn;
567
568 // Note: Voice is auto-magically stopped by AX layer when dropped
569
570 // Application clean-up
571 Voices[voice->index].voice = NULL;
572 Voices[voice->index].state = VOICE_STATE_STOPPED;
573 }
574
575 /*---------------------------------------------------------------------------*
576 Name: AquireVoiceADPCM
577
578 Description: Parses the ADPCM header, sets voice parameters
579
580 Arguments: pDSPADPCMData Pointer to the ADPCM data in MRAM
581 pARAMStart ARAM Start address
582
583 Returns: pointer to the allocated voice or NULL
584 *---------------------------------------------------------------------------*/
585 #ifndef HOLLYWOOD_REV
AquireVoiceADPCM(void * pDSPADPCMData,void * pARAMStart)586 static AXVPB* AquireVoiceADPCM(void *pDSPADPCMData, void* pARAMStart)
587 #else
588 static AXVPB* AquireVoiceADPCM(void *pDSPADPCMData)
589 #endif
590 {
591 DSPADPCM *ps = (DSPADPCM*)pDSPADPCMData;
592 AXPBADDR addr;
593 AXPBADPCM adpcm;
594 AXPBSRC src;
595 AXPBADPCMLOOP adpcmLoop;
596 AXVPB* voice;
597 u32 srcBits;
598 #ifndef HOLLYWOOD_REV
599 u32 aramAddress;
600 #else
601 u32 mramAddress;
602 u32 pMRAMStart;
603 #endif
604
605 // Allocate a voice for use
606 voice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);
607
608 if (voice == NULL)
609 {
610 OSReport("WARNING! Voice Acquisition failed!\n");
611 return NULL;
612 }
613
614 // Fill AXPBADDR structure
615 // All the following addresses are in nibbles
616
617 addr.loopFlag = ps->loop_flag;
618 addr.format = ps->format;
619
620 #ifndef HOLLYWOOD_REV
621 // Support for looping
622 if (addr.loopFlag)
623 {
624 adpcmLoop.loop_pred_scale = ps->lps;
625 adpcmLoop.loop_yn1 = ps->lyn1;
626 adpcmLoop.loop_yn2 = ps->lyn2;
627
628 aramAddress = (ps->sa + Bytes2Nibbles((u32)pARAMStart));
629 }
630 else
631 {
632 // The loop address for one-shot samples should be the zero buffer
633 // The "+ 2" is to avoid the frame header
634 aramAddress = Bytes2Nibbles((u32)ARAMBaseAddress) + 2;
635 }
636 addr.loopAddressHi = (u16)(aramAddress >> 16);
637 addr.loopAddressLo = (u16)(aramAddress & 0xFFFF);
638
639 aramAddress = (ps->ea + Bytes2Nibbles((u32)pARAMStart));
640 addr.endAddressHi = (u16)(aramAddress >> 16);
641 addr.endAddressLo = (u16)(aramAddress & 0xFFFF);
642
643 aramAddress = (ps->ca + Bytes2Nibbles((u32)pARAMStart));
644 addr.currentAddressHi = (u16)(aramAddress >> 16);
645 addr.currentAddressLo = (u16)(aramAddress & 0xFFFF);
646 #else
647 pMRAMStart = OSCachedToPhysical(GetDSPADPCMDataAddress(pDSPADPCMData));
648
649 // Support for looping
650 if (addr.loopFlag)
651 {
652 adpcmLoop.loop_pred_scale = ps->lps;
653 adpcmLoop.loop_yn1 = ps->lyn1;
654 adpcmLoop.loop_yn2 = ps->lyn2;
655
656 mramAddress = (ps->sa + Bytes2Nibbles(pMRAMStart));
657 }
658 else
659 {
660 // The loop address for one-shot samples should be the zero buffer
661 // The "+ 2" is to avoid the frame header
662 mramAddress = Bytes2Nibbles(OSCachedToPhysical(zeroBuffer)) + 2;
663 }
664 addr.loopAddressHi = (u16)(mramAddress >> 16);
665 addr.loopAddressLo = (u16)(mramAddress & 0xFFFF);
666
667 mramAddress = (ps->ea + Bytes2Nibbles(pMRAMStart));
668 addr.endAddressHi = (u16)(mramAddress >> 16);
669 addr.endAddressLo = (u16)(mramAddress & 0xFFFF);
670
671 mramAddress = (ps->ca + Bytes2Nibbles(pMRAMStart));
672 addr.currentAddressHi = (u16)(mramAddress >> 16);
673 addr.currentAddressLo = (u16)(mramAddress & 0xFFFF);
674 #endif
675
676 // Fill AXPBADPCM structure
677 adpcm.a[0][0] = ps->coef[0];
678 adpcm.a[0][1] = ps->coef[1];
679 adpcm.a[1][0] = ps->coef[2];
680 adpcm.a[1][1] = ps->coef[3];
681 adpcm.a[2][0] = ps->coef[4];
682 adpcm.a[2][1] = ps->coef[5];
683 adpcm.a[3][0] = ps->coef[6];
684 adpcm.a[3][1] = ps->coef[7];
685 adpcm.a[4][0] = ps->coef[8];
686 adpcm.a[4][1] = ps->coef[9];
687 adpcm.a[5][0] = ps->coef[10];
688 adpcm.a[5][1] = ps->coef[11];
689 adpcm.a[6][0] = ps->coef[12];
690 adpcm.a[6][1] = ps->coef[13];
691 adpcm.a[7][0] = ps->coef[14];
692 adpcm.a[7][1] = ps->coef[15];
693 adpcm.gain = ps->gain;
694 adpcm.pred_scale = ps->ps;
695 adpcm.yn1 = ps->yn1;
696 adpcm.yn2 = ps->yn2;
697
698 // Fill AXPBSRC structure for proper sample rates
699 srcBits = (u32)(0x00010000 * ((f32)ps->sample_rate / AX_IN_SAMPLES_PER_SEC));
700 src.ratioHi = (u16)(srcBits >> 16);
701 src.ratioLo = (u16)(srcBits & 0xFFFF);
702 src.currentAddressFrac = 0;
703 src.last_samples[0] = 0;
704 src.last_samples[1] = 0;
705 src.last_samples[2] = 0;
706 src.last_samples[3] = 0;
707
708 // Set voice type
709 AXSetVoiceType(voice, AX_PB_TYPE_NORMAL);
710
711 // Set Address and ADPCM information from header
712 AXSetVoiceAddr(voice, &addr);
713 AXSetVoiceAdpcm(voice, &adpcm);
714 AXSetVoiceAdpcmLoop(voice, &adpcmLoop);
715
716 // Set simple volumes
717 AXSetVoiceMix(voice, &g_mix);
718 AXSetVoiceVe(voice, &g_ve);
719
720 // Set sample rate
721 AXSetVoiceSrcType(voice, AX_SRC_TYPE_LINEAR);
722 AXSetVoiceSrc(voice, &src);
723
724 return voice;
725 }
726
727 /*---------------------------------------------------------------------------*
728 Name: LoadFileIntoRam
729
730 Description: Loads a file into memory. Memory is allocated.
731
732 Arguments: path File to load into main memory
733
734 Returns: pointer to file in main memory or NULL if not opened
735 *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)736 static void * LoadFileIntoRam(char *path)
737 {
738 DVDFileInfo handle;
739 u32 round_length;
740 s32 read_length;
741 void *buffer;
742
743 // Open File
744 if (!DVDOpen(path, &handle))
745 {
746 OSReport("WARNING! Failed to open %s\n", path);
747 return NULL;
748 }
749
750 // Make sure file length is not 0
751 if (DVDGetLength(&handle) == 0)
752 {
753 OSReport("WARNING! File length is 0\n");
754 return NULL;
755 }
756
757 round_length = OSRoundUp32B(DVDGetLength(&handle));
758 #ifndef HOLLYWOOD_REV
759 buffer = OSAlloc(round_length);
760 #else
761 buffer = MEMAllocFromExpHeapEx(hExpHeap, round_length, 32);
762 #endif
763
764 // Make sure we got a buffer
765 if (buffer == NULL)
766 {
767 OSReport("WARNING! Unable to allocate buffer\n");
768 return NULL;
769 }
770
771 // Read Files
772 read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
773
774 // Make sure we read the file correctly
775 if (read_length <= 0)
776 {
777 OSReport("WARNING! File lenght is wrong\n");
778 return NULL;
779 }
780
781 return buffer;
782 }
783
784 /*---------------------------------------------------------------------------*
785 Name: PrintIntro
786
787 Description: Prints Intro to debug output
788
789 Arguments: none
790
791 Returns: none
792 *---------------------------------------------------------------------------*/
PrintIntro(void)793 static void PrintIntro(void)
794 {
795 char button[256];
796 u32 i;
797
798 OSReport("\n\n****************************************************\n");
799 OSReport(" AXSimple - Plays DSPADPCM.exe files\n");
800 OSReport("****************************************************\n");
801
802 for (i = 0; i < NUM_BUTTON_MAPS; i++)
803 {
804 switch (ButtonMap[i][0])
805 {
806 case PAD_BUTTON_A:
807 sprintf(button, "A Button");
808 break;
809 case PAD_BUTTON_B:
810 sprintf(button, "B Button");
811 break;
812 case PAD_BUTTON_X:
813 sprintf(button, "X Button");
814 break;
815 case PAD_BUTTON_Y:
816 sprintf(button, "Y Button");
817 break;
818 case PAD_TRIGGER_Z:
819 sprintf(button, "Z Button");
820 break;
821 case PAD_TRIGGER_L:
822 sprintf(button, "L Button");
823 break;
824 case PAD_TRIGGER_R:
825 sprintf(button, "R Button");
826 break;
827 case PAD_BUTTON_DOWN:
828 sprintf(button, "+Control Pad Down");
829 break;
830 case PAD_BUTTON_UP:
831 sprintf(button, "+Control Pad Up");
832 break;
833 case PAD_BUTTON_LEFT:
834 sprintf(button, "+Control Pad Left");
835 break;
836 case PAD_BUTTON_RIGHT:
837 sprintf(button, "+Control Pad Right");
838 break;
839 }
840 OSReport("%s => %s\n", button, SampleFiles[ButtonMap[i][1]]);
841 }
842
843 OSReport("Start/Pause => Stop all sounds\n");
844 OSReport("****************************************************\n");
845 }
846