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