1 /*---------------------------------------------------------------------------*
2   Project:  Revolution WPAD AX demo
3   File:     wpad_axdemo.c
4 
5   Copyright (C)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: wpad_axdemo.c,v $
14   Revision 1.18.2.2  2007/12/11 01:36:56  tojo
15   (none)
16 
17   Revision 1.18.2.1  2007/12/11 01:17:50  tojo
18   Modified to handle the error code of WPADStatus.
19 
20   Revision 1.18  2007/07/10 12:14:46  tojo
21   (none)
22 
23   Revision 1.17  2007/05/10 04:17:34  aka
24   Revised to use AXRmtGetSamplesLeft().
25 
26   Revision 1.16  2007/04/23 09:16:08  tojo
27   (none)
28 
29   Revision 1.15  2007/02/13 04:35:17  tojo
30   Changed the button assignment of MUTE/MUTE OFF.
31 
32   Revision 1.14  2007/02/09 07:22:07  tojo
33   Modifed to follow the guideline.
34 
35   Revision 1.13  2006/11/21 08:38:15  aka
36   Removed the zero buffer.
37 
38   Revision 1.12  2006/10/23 02:16:23  aka
39   Changed from AXInit() to AXInitSpecifyMem().
40   Changed from MIXInit() to MIXInitSpecifyMem().
41   Changed from SYNInit() to SYNInitSpecifyMem().
42 
43   Revision 1.11  2006/10/23 01:17:30  tojo
44   Called WPADSetConnectCallback before initialization complete.
45 
46   Revision 1.10  2006/10/11 03:03:50  aka
47   Revised AXInit(), MIXInit() and SYNInit().
48 
49   Revision 1.9  2006/09/19 06:35:07  tojo
50   (none)
51 
52   Revision 1.8  2006/09/18 12:13:54  tojo
53   (none)
54 
55   Revision 1.7  2006/08/15 08:46:04  tojo
56   (none)
57 
58   Revision 1.6  2006/08/11 09:33:13  tojo
59   (none)
60 
61   Revision 1.5  2006/08/10 00:41:21  aka
62   Changed comments.
63 
64   Revision 1.4  2006/08/03 13:32:55  tojo
65   Removed old apis.
66 
67   Revision 1.3  2006/07/24 02:01:07  aka
68   Changed in relation to modification of AX.
69 
70   Revision 1.2  2006/07/21 03:00:11  tojo
71   Implemented gui.
72 
73   Revision 1.1  2006/07/19 09:31:24  tojo
74   Initial check in.
75 
76   $NoKeywords: $
77  *---------------------------------------------------------------------------*/
78 
79 /*---------------------------------------------------------------------------*
80     This program plays audio streaming on Wii remote controller using AX.
81     The audio streaming is encoded by WENC in runtime.
82  *---------------------------------------------------------------------------*/
83 
84 #include <demo.h>
85 #include <revolution/mix.h>
86 #include <revolution/seq.h>
87 #include <revolution/syn.h>
88 #include <string.h>
89 #include <revolution/mem.h>
90 
91 #include <revolution/wenc.h>
92 #include <revolution/wpad.h>
93 
94 // User defines
95 #define NUM_SAMPLES     8
96 #define NUM_BUTTON_MAPS 8
97 // Filenames for samples to be played
98 char SampleFiles [NUM_SAMPLES][256] =
99 {
100     "axdemo/simple/snare.dsp",
101     "axdemo/simple/tom.dsp",
102     "axdemo/simple/cymbal.dsp",
103     "axdemo/simple/ride.dsp",
104     "axdemo/simple/bongo1.dsp",
105     "axdemo/simple/bongo2.dsp",
106     "axdemo/simple/bongo3.dsp",
107     "axdemo/simple/bongo4.dsp",
108 };
109 // Button mappings for samples {Button, index in file table}
110 u32 ButtonMap [NUM_BUTTON_MAPS][2] =
111 {
112     {WPAD_BUTTON_A,      0},
113     {WPAD_BUTTON_B,      1},
114     {WPAD_BUTTON_1,      2},
115     {WPAD_BUTTON_2,      3},
116     {WPAD_BUTTON_DOWN,   4},
117     {WPAD_BUTTON_UP,     5},
118     {WPAD_BUTTON_LEFT,   6},
119     {WPAD_BUTTON_RIGHT,  7}
120 };
121 
122 // This demo uses a very simple mixing paradigm. All sounds are played at
123 // a volume of 1.0 (0x8000). Please see the MIX library for a more
124 // comprehensive mixing library
125 AXPBMIX g_mix = {
126     0x0000,       // volume left
127     0x0000,       // volume ramp left
128     0x0000,       // volume right
129     0x0000,       // volume ramp right
130 
131     0x0000,       // volume AUX A left
132     0x0000,       // volume ramp AUX A left
133     0x0000,       // volume AUX A right
134     0x0000,       // volume ramp AUX A right
135 
136     0x0000,       // volume AUX B left
137     0x0000,       // volume ramp AUX B left
138     0x0000,       // volume AUX B right
139     0x0000,       // volume ramp AUX B right
140 
141     0x0000,       // volume AUX C left
142     0x0000,       // volume ramp AUX C left
143     0x0000,       // volume AUX C right
144     0x0000,       // volume ramp AUX C right
145 
146     0x0000,       // volume surround
147     0x0000,       // volume ramp surround
148     0x0000,       // volume AUX A surround
149     0x0000,       // volume ramp AUX A surround
150     0x0000,       // volume AUX B surround
151     0x0000,       // volume ramp AUX B surround
152     0x0000,       // volume AUX C surround
153     0x0000,       // volume ramp AUX C surround
154 };
155 
156 AXPBVE g_ve = {
157     0x8000,     // volume at start of frame, 0x8000 = 1.0
158     0           // signed per sample delta (160 samples per frame)
159 };
160 
161 AXPBRMTMIX g_rmix = {
162     0x0000,       // volume main0
163     0x0000,       // volume ramp main0
164     0x0000,       // volume aux0
165     0x0000,       // volume ramp aux0
166 
167     0x0000,       // volume main1
168     0x0000,       // volume ramp main1
169     0x0000,       // volume aux1
170     0x0000,       // volume ramp aux1
171 
172     0x0000,       // volume main2
173     0x0000,       // volume ramp main2
174     0x0000,       // volume aux2
175     0x0000,       // volume ramp aux2
176 
177     0x0000,       // volume main3
178     0x0000,       // volume ramp main3
179     0x0000,       // volume aux3
180     0x0000        // volume ramp aux3
181 };
182 
183 // User Structures to keep track of data
184 typedef struct
185 {
186     void        *mramAddr;
187 
188 } SampleInfo;
189 
190 typedef struct
191 {
192     AXVPB           *voice;
193     u32             state;
194 } VoiceInfo;
195 
196 // Voice  Defines
197 #define VOICE_PRIO_HIGH 31
198 #define VOICE_PRIO_MED  15
199 #define VOICE_PRIO_LOW  1
200 
201 #define VOICE_STATE_STOPPED        0
202 #define VOICE_STATE_START          1
203 #define VOICE_STATE_STARTED        2
204 #define VOICE_STATE_PLAYING        3
205 #define VOICE_STATE_STOP           4
206 
207 // Exp Heap
208 static MEMHeapHandle hExpHeap;
209 
210 // Utility Macro Functions
211 #define RoundUp64(x)                (((u32)(x) + 64 - 1) & ~(64 - 1))
212 #define Bytes2Nibbles(n)            (n << 1)
213 #define Nibbles2Bytes(n)            (n >> 1)
214 #define GetDSPADPCMDataAddress(a)   ((void*)((u32)a + sizeof(DSPADPCM)))
215 #define GetDSPADPCMDataSize32B(a)   (RoundUp64(((DSPADPCM*)a)->num_adpcm_nibbles) >> 1)
216 #define GetVoiceCurrentAddr32(v)    (*(u32 *)(&((v)->pb.addr.currentAddressHi)))
217 #define GetVoiceLoopAddr32(v)       (*(u32 *)(&((v)->pb.addr.loopAddressHi)))
218 #define GetVoiceEndAddr32(v)        (*(u32 *)(&((v)->pb.addr.endAddressHi)))
219 
220 // Sample Info
221 static SampleInfo   Samples[NUM_SAMPLES];
222 // AX Voice info
223 static VoiceInfo    Voices[AX_MAX_VOICES];
224 
225 // function Prototypes
226 static void * LoadFileIntoRam       ( char *path );
227 static void AudioFrameCallback      ( void );
228 static AXVPB* AquireVoiceADPCM      ( s32 chan, void *pDSPADPCMData );
229 static void LoadSamples             ( void );
230 static void PlaySample              ( s32 chan, SampleInfo *sample );
231 static void VoiceCallback           ( void * voiceIn );
232 
233 #define SAMPLES_PER_AUDIO_FRAME     96
234 #define BYTES_PER_AUDIO_FRAME       384
235 static s16          SoundBuffer[2][SAMPLES_PER_AUDIO_FRAME * 2] ATTRIBUTE_ALIGN(32);
236 static s32          SoundBufferIndex = 0;
237 static AIDCallback  OldAIDCallback   = NULL;
238 static s16*         LastAudioBuffer  = NULL;
239 static s16*         CurAudioBuffer   = NULL;
240 
241 #define GM_WT       "/axdemo/synth/gm16adpcm.wt"
242 #define GM_PCM      "/axdemo/synth/gm16adpcm.pcm"
243 #define MIDI_FILE   "/axdemo/midi/2nd_time.mid"
244 
245 // allocator functions for WPAD
246 void* myAlloc                       ( u32 size );
247 u8    myFree                        ( void *ptr );
248 
249 static void ConnectCallback         ( s32 chan, s32 reason );
250 static void ExtensionCallback       ( s32 chan, s32 result );
251 static void SpeakerCallback         ( s32 chan, s32 result );
252 static void SpeakerOnCallback       ( s32 chna, s32 result );
253 static void SpeakerOffCallback      ( s32 chan, s32 result );
254 static void MuteOnCallback          ( s32 chan, s32 result );
255 static void MuteOffCallback         ( s32 chan, s32 result );
256 static void UpdateSpeaker           ( OSAlarm *alarm, OSContext *context );
257 
258 #define SAMPLES_PER_AUDIO_PACKET    40
259 #define AUDIO_PACKET_MAX_LEN        20
260 
261 // Speaker Status
262 typedef struct SpeakerInfo
263 {
264     u8          active;
265     BOOL        muteReq;
266     WENCInfo    encInfo;
267     BOOL        first;
268     BOOL        last;
269 } SpeakerInfo;
270 
271 // Periodic Alarms for audio streaming
272 static OSAlarm  SpeakerAlarm;
273 // Audio buffers
274 static s16      AudioBuffer[WPAD_MAX_CONTROLLERS][SAMPLES_PER_AUDIO_PACKET];
275 
276 static void initialize              ( void );
277 static void RenderOperation         ( void );
278 static void RenderControllerStatus  ( void );
279 
280 typedef union Status
281 {
282     WPADStatus      cr;
283     WPADFSStatus    fs;
284     WPADCLStatus    cl;
285 } Status;
286 
287 typedef struct ContInfo
288 {
289     u32         type;
290     s32         status;
291     u16         keepBtnMap;
292     u16         button;
293     Status      currStat;
294     Status      prevStat;
295     SpeakerInfo Speakers;
296 } ContInfo;
297 
298 static ContInfo info[WPAD_MAX_CONTROLLERS];
299 
300 /*---------------------------------------------------------------------------*
301  * Name        : main
302  * Description : main
303  * Arguments   : None.
304  * Returns     : None.
305  *---------------------------------------------------------------------------*/
main(void)306 void main( void )
307 {
308     s32        i;
309     s32        chan;
310 
311     void       *arenaMem2Lo;
312     void       *arenaMem2Hi;
313 
314     SEQSEQUENCE Sequence;
315     u8          *Wavetable;
316     u8          *Pcm;
317     u8          *MidiFile;
318     void        *axBuffer;
319     void        *mixBuffer;
320     void        *synBuffer;
321 
322     // Initialize DEMO
323     initialize();
324 
325     // initialize Exp Heap on MEM2
326     arenaMem2Lo = OSGetMEM2ArenaLo();
327     arenaMem2Hi = OSGetMEM2ArenaHi();
328     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
329     ASSERT(hExpHeap != NULL);
330 
331     // Initialize Audio
332     axBuffer  = OSAlloc(AXGetMemorySize(AX_MAX_VOICES));
333     mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES));
334     synBuffer = MEMAllocFromExpHeap(hExpHeap, SYNGetMemorySize(AX_MAX_VOICES));
335 
336     AIInit(NULL);
337     AXInitSpecifyMem(AX_MAX_VOICES, axBuffer);
338     MIXInitSpecifyMem(mixBuffer);
339     SYNInitSpecifyMem(synBuffer);
340     SEQInit();
341 
342     // Load Voice data into MRAM
343     LoadSamples();
344 
345     Wavetable = LoadFileIntoRam(GM_WT);
346     Pcm       = LoadFileIntoRam(GM_PCM);
347     MidiFile  = LoadFileIntoRam(MIDI_FILE);
348 
349     // Register Callback with AX for audio processing
350     AXRegisterCallback(&AudioFrameCallback);
351 
352     SEQAddSequence( &Sequence,
353                     MidiFile,
354                     Wavetable,
355                     Pcm,
356                     NULL,
357                     16,
358                     15,
359                     1
360                     );
361     SEQSetState(&Sequence, SEQ_STATE_RUNLOOPED);
362 
363     // Initialize WPAD
364     WPADRegisterAllocator(myAlloc, myFree);
365 
366     WPADInit();
367 
368     for(i=0;i<WPAD_MAX_CONTROLLERS; i++)
369     {
370         WPADSetConnectCallback((s32)i, ConnectCallback);
371     }
372 
373     while(WPADGetStatus() != WPAD_STATE_SETUP)
374     {
375         ;
376     }
377 
378     OSCreateAlarm(&SpeakerAlarm);
379     OSSetPeriodicAlarm(&SpeakerAlarm, OSGetTime(), WPAD_STRM_INTERVAL, UpdateSpeaker);
380 
381     // Spin
382     while (1)
383     {
384         for(chan=0; chan<WPAD_MAX_CONTROLLERS; chan++)
385         {
386             info[chan].status = WPADProbe(chan, &info[chan].type);
387 
388             if (info[chan].status != WPAD_ERR_NO_CONTROLLER)
389             {
390                 WPADRead(chan, &info[chan].currStat.cr);
391 
392                 if (info[chan].currStat.cr.err != WPAD_ERR_INVALID)
393                 {
394                     info[chan].button   = WPADButtonDown(info[chan].prevStat.cr.button, info[chan].currStat.cr.button);
395                     info[chan].prevStat.cr = info[chan].currStat.cr;
396                 }
397                 if (WPADIsSpeakerEnabled(chan))
398                 {
399                     BOOL active = FALSE;
400 
401                     // Stop all sounds when START/PAUSE is pressed
402                     if (info[chan].currStat.cr.button & WPAD_BUTTON_HOME)
403                     {
404                         // Stop all voices
405                         for (i = 0; i < AX_MAX_VOICES; i++)
406                         {
407                             Voices[i].state = VOICE_STATE_STOP;
408                         }
409                         continue;
410                     }
411                     if (info[chan].button & WPAD_BUTTON_PLUS)
412                     {
413                         if (info[chan].Speakers.active == 1)
414                         {
415                             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE, MuteOnCallback);
416                         }
417                         info[chan].Speakers.muteReq = TRUE;
418                         continue;
419                     }
420                     if (info[chan].button & WPAD_BUTTON_MINUS)
421                     {
422                         if (info[chan].Speakers.active == 2)
423                         {
424                             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE_OFF, MuteOffCallback);
425                         }
426                         info[chan].Speakers.muteReq = FALSE;
427                         continue;
428                     }
429 
430                     // Use Button map to start sounds
431                     for (i = 0; i < NUM_BUTTON_MAPS; i++)
432                     {
433                         if (info[chan].button & ButtonMap[i][0])
434                         {
435                             PlaySample(chan, &Samples[ButtonMap[i][1]]);
436                         }
437                     }
438 
439                     // Check whether one voice at least is active
440                     for (i = 0; i < AX_MAX_VOICES; i++)
441                     {
442                         if (Voices[i].state != VOICE_STATE_STOPPED && Voices[i].state != VOICE_STATE_STOP)
443                         {
444                             active = TRUE;
445                         }
446                     }
447 
448                     if (!active && info[chan].Speakers.active != 3)
449                     {
450                         // start shutdown speaker.
451                         info[chan].Speakers.active = 3;
452                         WPADControlSpeaker(chan, WPAD_SPEAKER_OFF, SpeakerOffCallback);
453                     }
454                 }
455                 else
456                 {
457                     if (info[chan].button & WPAD_BUTTON_PLUS)
458                     {
459                         info[chan].Speakers.muteReq = TRUE;
460                     }
461                     else if (info[chan].button & WPAD_BUTTON_MINUS)
462                     {
463                         info[chan].Speakers.muteReq = FALSE;
464                     }
465                     else if (!info[chan].Speakers.muteReq && !(info[chan].button & WPAD_BUTTON_HOME) && info[chan].button)
466                     {
467                         WPADControlSpeaker(chan, WPAD_SPEAKER_ON, SpeakerOnCallback);
468                         info[chan].keepBtnMap = info[chan].button;
469                     }
470                 }
471             }
472         }
473 
474         DEMOBeforeRender();
475 
476         DEMOPrintf( 16, 16, 0, "WPAD Demo -- WPAD Axdemo");
477 
478         RenderOperation();
479         RenderControllerStatus();
480 
481         DEMODoneRender();
482 
483     }
484 
485     OSCancelAlarm(&SpeakerAlarm);
486 
487 }
488 
489 /*---------------------------------------------------------------------------*
490  * Name        : UpdateSpeaker
491  * Description :
492  * Arguments   :
493  * Returns     : None.
494  *---------------------------------------------------------------------------*/
UpdateSpeaker(OSAlarm * alarm,OSContext * context)495 static void UpdateSpeaker( OSAlarm *alarm, OSContext *context )
496 {
497 #pragma unused(alarm, context)
498 
499     u8    data[24];
500     u32   flag;
501     s32   chan;
502     BOOL  intr;
503 
504     if (SAMPLES_PER_AUDIO_PACKET <= AXRmtGetSamplesLeft())
505     {
506 
507         for(chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
508         {
509 
510             AXRmtGetSamples(chan, AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET);
511 
512             if (info[chan].Speakers.active)
513             {
514                 intr = OSDisableInterrupts();
515 
516                 if (WPADCanSendStreamData(chan))
517                 {
518                     flag = (info[chan].Speakers.first) ? (u32)WENC_FLAG_FIRST : (u32)WENC_FLAG_CONT;
519                     if (info[chan].Speakers.first)
520                     {
521                         info[chan].Speakers.first = FALSE;
522                     }
523                     WENCGetEncodeData(&info[chan].Speakers.encInfo, flag, (const s16*)AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET, data);
524 
525                     WPADSendStreamData(chan, data, AUDIO_PACKET_MAX_LEN);
526                 }
527 
528                 OSRestoreInterrupts(intr);
529             }
530         }
531 
532         AXRmtAdvancePtr(SAMPLES_PER_AUDIO_PACKET);
533     }
534 }
535 
536 /*---------------------------------------------------------------------------*
537  * Name        : SpeakerCallback
538  * Description :
539  * Arguments   :
540  * Returns     : None.
541  *---------------------------------------------------------------------------*/
SpeakerCallback(s32 chan,s32 result)542 static void SpeakerCallback( s32 chan, s32 result )
543 {
544     int i;
545 
546     if (result == WPAD_ERR_NONE)
547     {
548         info[chan].Speakers.active = 1;
549         info[chan].Speakers.first = TRUE;
550         info[chan].Speakers.last  = FALSE;
551         memset(&info[chan].Speakers.encInfo, 0, sizeof(WENCInfo));
552 
553         if (info[chan].Speakers.muteReq)
554         {
555             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE, MuteOnCallback);
556         }
557         else
558         {
559             // Use Button map to start sounds
560             for (i = 0; i < NUM_BUTTON_MAPS; i++)
561             {
562                 if (info[chan].keepBtnMap & ButtonMap[i][0])
563                 {
564                     PlaySample(chan, &Samples[ButtonMap[i][1]]);
565                 }
566             }
567         }
568 
569         // clear btn map.
570         info[chan].keepBtnMap = 0;
571         OSReport("Chan[%d] is ready\n", chan);
572 
573     }
574 }
575 
576 /*---------------------------------------------------------------------------*
577  * Name        : SpeakerOnCallback
578  * Description :
579  * Arguments   :
580  * Returns     : None.
581  *---------------------------------------------------------------------------*/
SpeakerOnCallback(s32 chan,s32 result)582 static void SpeakerOnCallback( s32 chan, s32 result )
583 {
584     if (result == WPAD_ERR_NONE)
585     {
586         WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, SpeakerCallback);
587     }
588 }
589 
590 /*---------------------------------------------------------------------------*
591  * Name        : SpeakerOffCallback
592  * Description :
593  * Arguments   :
594  * Returns     : None.
595  *---------------------------------------------------------------------------*/
SpeakerOffCallback(s32 chan,s32 result)596 static void SpeakerOffCallback( s32 chan, s32 result )
597 {
598 #pragma unused(result)
599 
600     info[chan].Speakers.active = 0;
601 
602     OSReport("Chan[%d] is stopped\n", chan);
603 }
604 
605 /*---------------------------------------------------------------------------*
606  * Name        : MuteOnCallback
607  * Description :
608  * Arguments   :
609  * Returns     : None.
610  *---------------------------------------------------------------------------*/
MuteOnCallback(s32 chan,s32 result)611 static void MuteOnCallback( s32 chan, s32 result )
612 {
613     if (result == WPAD_ERR_NONE)
614     {
615         info[chan].Speakers.active = 2;
616     }
617 }
618 
619 /*---------------------------------------------------------------------------*
620  * Name        : MuteOffCallback
621  * Description :
622  * Arguments   :
623  * Returns     : None.
624  *---------------------------------------------------------------------------*/
MuteOffCallback(s32 chan,s32 result)625 static void MuteOffCallback( s32 chan, s32 result )
626 {
627     if (result == WPAD_ERR_NONE)
628     {
629         info[chan].Speakers.active = 1;
630     }
631 }
632 
633 /*---------------------------------------------------------------------------*
634  * Name        : ExtensionCallback
635  * Description :
636  * Arguments   :
637  * Returns     : None.
638  *---------------------------------------------------------------------------*/
ExtensionCallback(s32 chan,s32 result)639 static void ExtensionCallback( s32 chan, s32 result )
640 {
641     switch(result)
642     {
643         case WPAD_DEV_CORE:
644         case WPAD_DEV_FUTURE:
645         case WPAD_DEV_NOT_SUPPORTED: WPADSetDataFormat(chan, WPAD_FMT_CORE);      break;
646         case WPAD_DEV_FREESTYLE:     WPADSetDataFormat(chan, WPAD_FMT_FREESTYLE); break;
647         case WPAD_DEV_CLASSIC:       WPADSetDataFormat(chan, WPAD_FMT_CLASSIC);   break;
648     }
649 }
650 
651 /*---------------------------------------------------------------------------*
652  * Name        : ConnectCallback
653  * Description :
654  * Arguments   :
655  * Returns     : None.
656  *---------------------------------------------------------------------------*/
ConnectCallback(s32 chan,s32 reason)657 static void ConnectCallback( s32 chan, s32 reason )
658 {
659     OSReport("ConnectCallback(%d) : %s\n", chan, (reason < 0) ? "disconnect" : "connect");
660 
661     info[chan].Speakers.active = 0;
662     if (reason >= 0)
663     {
664         WPADSetDataFormat(chan, WPAD_FMT_CORE);
665     }
666 }
667 
668 
669 /*---------------------------------------------------------------------------*
670  * Name        :
671  * Description :
672  * Arguments   : None.
673  * Returns     : None.
674  *---------------------------------------------------------------------------*/
myAlloc(u32 size)675 void *myAlloc( u32 size )
676 {
677     void *ptr;
678 
679     ptr = MEMAllocFromExpHeap(hExpHeap, size);
680     ASSERTMSG(ptr, "Memory allocation failed\n");
681 
682     return(ptr);
683 }
684 
685 /*---------------------------------------------------------------------------*
686  * Name        :
687  * Description :
688  * Arguments   : None.
689  * Returns     : None.
690  *---------------------------------------------------------------------------*/
myFree(void * ptr)691 u8 myFree( void *ptr )
692 {
693     MEMFreeToExpHeap(hExpHeap, ptr);
694     return(1);
695 }
696 
697 
698 /*---------------------------------------------------------------------------*
699     Name:           LoadSamples
700 
701     Description:    Loads ADPCM files into Main Memory (Header + Data) and
702                     ARAM (Data)
703 
704     Arguments:      none
705 
706     Returns:        none
707  *---------------------------------------------------------------------------*/
LoadSamples(void)708 static void LoadSamples( void )
709 {
710     u32 i;
711 
712     // Load samples
713     for (i = 0; i < NUM_SAMPLES; i++)
714     {
715         // Load ADPCM file into MRAM (96 byte header included)
716         Samples[i].mramAddr = LoadFileIntoRam(SampleFiles[i]);
717 
718         // Sanity Check
719         if (Samples[i].mramAddr == NULL)
720         {
721             OSReport("WARNING! Sample %d not loaded\n", i);
722             continue;
723         }
724     }
725 }
726 
727 /*---------------------------------------------------------------------------*
728     Name:           PlaySample
729 
730     Description:    Utility function that will play a sample
731 
732     Arguments:      sample    Pointer to the sample information
733 
734     Returns:        pointer to the allocated voice
735  *---------------------------------------------------------------------------*/
PlaySample(s32 chan,SampleInfo * sample)736 static void PlaySample( s32 chan, SampleInfo *sample )
737 {
738     AXVPB    *voice;
739 
740     if (sample->mramAddr == NULL)
741     {
742         OSReport("WARNING! Sample not loaded!\n");
743         return;
744     }
745 
746     // Aquire Voice and start
747     voice = AquireVoiceADPCM(chan, sample->mramAddr);
748     if (voice == NULL)
749     {
750         OSReport("WARNING: Ran out of voices!\n");
751         return;
752     }
753     Voices[voice->index].voice = voice;
754     Voices[voice->index].state = VOICE_STATE_START;
755 }
756 
757 /*---------------------------------------------------------------------------*
758     Name:            AudioFrameCallback
759 
760     Description:    Callback that process audio data per 5ms audio frame.
761                     In this case, it stops, resets, and starts a voice.
762 
763     Arguments:      none
764 
765     Returns:        none
766  *---------------------------------------------------------------------------*/
AudioFrameCallback(void)767 static void AudioFrameCallback( void )
768 {
769     u32 i;
770     BOOL bStopFlag = FALSE;
771 
772     // Monitor each voice and process states. This must be done in the
773     // callback
774     for (i = 0; i < AX_MAX_VOICES; i++)
775     {
776 
777         // Skip NULL entries
778         if (Voices[i].voice == NULL) continue;
779 
780         switch (Voices[i].state)
781         {
782             case VOICE_STATE_STOPPED:
783                 break;
784             case VOICE_STATE_START:
785                 // Start the voice
786                 AXSetVoiceState(Voices[i].voice, AX_PB_STATE_RUN);
787                 Voices[i].state = VOICE_STATE_STARTED;
788                 break;
789             case VOICE_STATE_STARTED:
790                 // Skip a frame
791                 Voices[i].state = VOICE_STATE_PLAYING;
792                 break;
793             case VOICE_STATE_PLAYING:
794                 // Check to see if the voice is finished, if so, stop it
795                 if (Voices[i].voice->pb.state == AX_PB_STATE_STOP)
796                     bStopFlag = TRUE;
797                 break;
798             case VOICE_STATE_STOP:
799                 // Force a voice to stop
800                 bStopFlag = TRUE;
801                 break;
802         }
803 
804         // A voice must be stopped
805         if (bStopFlag)
806         {
807             AXSetVoiceState(Voices[i].voice, AX_PB_STATE_STOP);
808             AXFreeVoice(Voices[i].voice);
809             Voices[i].voice = NULL;
810             Voices[i].state = VOICE_STATE_STOPPED;
811             bStopFlag = FALSE;
812         }
813     }
814 
815     // run the sequencer
816     SEQRunAudioFrame();
817 
818     // run the synth
819     SYNRunAudioFrame();
820 
821     // tell the mixer to update settings
822     MIXUpdateSettings();
823 }
824 
825 
826 /*---------------------------------------------------------------------------*
827     Name:           VoiceCallback
828 
829     Description:    Callback for when a voice is dropped.
830 
831     Arguments:      unused
832 
833     Returns:        none
834  *---------------------------------------------------------------------------*/
VoiceCallback(void * voiceIn)835 static void VoiceCallback( void * voiceIn )
836 {
837     AXVPB *voice = (AXVPB*)voiceIn;
838 
839     // Note: Voice is auto-magically stopped by AX layer when dropped
840 
841     // Application clean-up
842     Voices[voice->index].voice = NULL;
843     Voices[voice->index].state = VOICE_STATE_STOPPED;
844 }
845 
846 /*---------------------------------------------------------------------------*
847     Name:           AquireVoiceADPCM
848 
849     Description:    Parses the ADPCM header, sets voice parameters
850 
851     Arguments:      pDSPADPCMData    Pointer to the ADPCM data in MRAM
852                     pARAMStart        ARAM Start address
853 
854     Returns:        pointer to the allocated voice or NULL
855  *---------------------------------------------------------------------------*/
AquireVoiceADPCM(s32 chan,void * pDSPADPCMData)856 static AXVPB* AquireVoiceADPCM( s32 chan, void *pDSPADPCMData )
857 {
858     DSPADPCM            *ps = (DSPADPCM*)pDSPADPCMData;
859     AXPBADDR            addr;
860     AXPBADPCM           adpcm;
861     AXPBSRC             src;
862     AXPBADPCMLOOP       adpcmLoop;
863     AXVPB*              voice;
864     u32                 srcBits;
865     u32                 mramAddress;
866     u32                 pMRAMStart;
867 
868     // Allocate a voice for use
869     voice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);
870 
871     if (voice == NULL)
872     {
873         OSReport("WARNING! Voice Acquisition failed!\n");
874         return NULL;
875     }
876 
877     // Fill AXPBADDR structure
878     // All the folowing addresses are in nibbles
879 
880     addr.loopFlag           = ps->loop_flag;
881     addr.format             = ps->format;
882 
883     pMRAMStart = OSCachedToPhysical(GetDSPADPCMDataAddress(pDSPADPCMData));
884 
885     // Support for looping
886     if (addr.loopFlag)
887     {
888         adpcmLoop.loop_pred_scale = ps->lps;
889         adpcmLoop.loop_yn1        = ps->lyn1;
890         adpcmLoop.loop_yn2        = ps->lyn2;
891     }
892 
893     mramAddress             = (ps->sa + Bytes2Nibbles(pMRAMStart));
894     addr.loopAddressHi      = (u16)(mramAddress >> 16);
895     addr.loopAddressLo      = (u16)(mramAddress & 0xFFFF);
896 
897     mramAddress             = (ps->ea + Bytes2Nibbles(pMRAMStart));
898     addr.endAddressHi       = (u16)(mramAddress >> 16);
899     addr.endAddressLo       = (u16)(mramAddress & 0xFFFF);
900 
901     mramAddress             = (ps->ca + Bytes2Nibbles(pMRAMStart));
902     addr.currentAddressHi   = (u16)(mramAddress >> 16);
903     addr.currentAddressLo   = (u16)(mramAddress & 0xFFFF);
904 
905     // Fill AXPBADPCM structure
906     adpcm.a[0][0]           = ps->coef[0];
907     adpcm.a[0][1]           = ps->coef[1];
908     adpcm.a[1][0]           = ps->coef[2];
909     adpcm.a[1][1]           = ps->coef[3];
910     adpcm.a[2][0]           = ps->coef[4];
911     adpcm.a[2][1]           = ps->coef[5];
912     adpcm.a[3][0]           = ps->coef[6];
913     adpcm.a[3][1]           = ps->coef[7];
914     adpcm.a[4][0]           = ps->coef[8];
915     adpcm.a[4][1]           = ps->coef[9];
916     adpcm.a[5][0]           = ps->coef[10];
917     adpcm.a[5][1]           = ps->coef[11];
918     adpcm.a[6][0]           = ps->coef[12];
919     adpcm.a[6][1]           = ps->coef[13];
920     adpcm.a[7][0]           = ps->coef[14];
921     adpcm.a[7][1]           = ps->coef[15];
922     adpcm.gain              = ps->gain;
923     adpcm.pred_scale        = ps->ps;
924     adpcm.yn1               = ps->yn1;
925     adpcm.yn2               = ps->yn2;
926 
927     // Fill AXPBSRC structure for proper sample rates
928     srcBits = (u32)(0x00010000 * ((f32)ps->sample_rate / AX_IN_SAMPLES_PER_SEC));
929 
930     src.ratioHi = (u16)(srcBits >> 16);
931     src.ratioLo = (u16)(srcBits & 0xFFFF);
932     src.currentAddressFrac = 0;
933     src.last_samples[0] = 0;
934     src.last_samples[1] = 0;
935     src.last_samples[2] = 0;
936     src.last_samples[3] = 0;
937 
938     // Set voice type
939     AXSetVoiceType(voice, AX_PB_TYPE_NORMAL);
940 
941     // Set Address and ADPCM information from header
942     AXSetVoiceAddr(voice, &addr);
943     AXSetVoiceAdpcm(voice, &adpcm);
944     AXSetVoiceAdpcmLoop(voice, &adpcmLoop);
945 
946     // Set simple volumes
947     AXSetVoiceMix(voice, &g_mix);
948     AXSetVoiceVe(voice, &g_ve);
949 
950     // Set controller speaker
951     AXSetVoiceRmtOn(voice, AX_PB_REMOTE_ON);
952     memset(&g_rmix, 0, sizeof(AXPBRMTMIX));
953     switch(chan)
954     {
955         case WPAD_CHAN0:
956             g_rmix.vMain0 = 0x8000;      // chan0 main
957             g_rmix.vAux0  = 0x8000;      // chan0 aux
958             break;
959         case WPAD_CHAN1:
960             g_rmix.vMain1 = 0x8000;      // chan1 main
961             g_rmix.vAux1  = 0x8000;      // chan1 aux
962             break;
963         case WPAD_CHAN2:
964             g_rmix.vMain2 = 0x8000;      // chan2 main
965             g_rmix.vAux2  = 0x8000;      // chan2 aux
966             break;
967         case WPAD_CHAN3:
968             g_rmix.vMain3 = 0x8000;      // chan3 main
969             g_rmix.vAux3  = 0x8000;      // chan3 aux
970             break;
971     }
972     AXSetVoiceRmtMix(voice, &g_rmix);
973 
974     // Set sample rate
975     AXSetVoiceSrcType(voice, AX_SRC_TYPE_LINEAR);
976     AXSetVoiceSrc(voice, &src);
977 
978     return voice;
979 }
980 
981 /*---------------------------------------------------------------------------*
982     Name:            LoadFileIntoRam
983 
984     Description:    Loads a file into memory. Memory is allocated.
985 
986     Arguments:      path    File to load into main memory
987 
988     Returns:        pointer to file in main memory or NULL if not opened
989  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)990 static void * LoadFileIntoRam( char *path )
991 {
992     DVDFileInfo handle;
993     u32         round_length;
994     s32         read_length;
995     void        *buffer;
996 
997     // Open File
998     if (!DVDOpen(path, &handle))
999     {
1000         OSReport("WARNING! Failed to open %s\n", path);
1001         return NULL;
1002     }
1003 
1004     // Make sure file length is not 0
1005     if (DVDGetLength(&handle) == 0)
1006     {
1007         OSReport("WARNING! File length is 0\n");
1008         return NULL;
1009     }
1010 
1011     round_length = OSRoundUp32B(DVDGetLength(&handle));
1012     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
1013 
1014     // Make sure we got a buffer
1015     if (buffer == NULL)
1016     {
1017         OSReport("WARNING! Unable to allocate buffer\n");
1018         return NULL;
1019     }
1020 
1021     // Read Files
1022     read_length  = DVDRead(&handle, buffer, (s32)(round_length), 0);
1023 
1024     // Make sure we read the file correctly
1025     if (read_length <= 0)
1026     {
1027         OSReport("WARNING! File lenght is wrong\n");
1028         return NULL;
1029     }
1030 
1031     return buffer;
1032 }
1033 
1034 static const s16 HEIGHT = 10;
1035 
1036 /*---------------------------------------------------------------------------*
1037  * Name        : RenderOperation
1038  * Description :
1039  * Arguments   :
1040  * Returns     : None.
1041  *---------------------------------------------------------------------------*/
RenderOperation(void)1042 static void RenderOperation( void )
1043 {
1044     s16 y = 96;
1045     char button[256];
1046     u32 i;
1047 
1048     for (i = 0; i < NUM_BUTTON_MAPS; i++)
1049     {
1050         switch (ButtonMap[i][0])
1051         {
1052             case WPAD_BUTTON_A: sprintf(button, "A    "); break;
1053             case WPAD_BUTTON_B: sprintf(button, "B    "); break;
1054             case WPAD_BUTTON_1: sprintf(button, "1    "); break;
1055             case WPAD_BUTTON_2: sprintf(button, "2    "); break;
1056             case WPAD_BUTTON_DOWN:  sprintf(button, "Down "); break;
1057             case WPAD_BUTTON_UP:    sprintf(button, "Up   "); break;
1058             case WPAD_BUTTON_LEFT:  sprintf(button, "Left "); break;
1059             case WPAD_BUTTON_RIGHT: sprintf(button, "Right"); break;
1060         }
1061         DEMOPrintf(  16, y+=HEIGHT, 0, "%s    : %s", button, SampleFiles[ButtonMap[i][1]]);
1062     }
1063 
1064     DEMOPrintf(  16, y+=HEIGHT, 0, "Home     : Stop all sounds");
1065     DEMOPrintf(  16, y+=HEIGHT, 0, "Plus     : Mute On");
1066     DEMOPrintf(  16, y+=HEIGHT, 0, "Minus    : Mute Off");
1067 }
1068 
1069 /*---------------------------------------------------------------------------*
1070  * Name        : RenderControllerStatus
1071  * Description :
1072  * Arguments   :
1073  * Returns     : None.
1074  *---------------------------------------------------------------------------*/
RenderControllerStatus(void)1075 static void RenderControllerStatus( void )
1076 {
1077     s16 y = 32;
1078     int chan;
1079 
1080     DEMOPrintf( 150, y, 0, "speaker");
1081     DEMOPrintf( 250, y, 0, "volume");
1082     for(chan=0; chan<WPAD_MAX_CONTROLLERS; chan++)
1083     {
1084         y += HEIGHT;
1085         DEMOPrintf(  16, y, 0, "CHAN_%d [%s]",
1086             chan,
1087             (info[chan].status == WPAD_ERR_NO_CONTROLLER) ? "--" :
1088             (info[chan].type == 0) ? "CORE"     :
1089             (info[chan].type == 1) ? "NUNCHAKU" :
1090             (info[chan].type == 2) ? "CLASSIC"  :
1091                                      "UNKNOWN"
1092         );
1093         DEMOPrintf( 150, y, 0, "%s", (info[chan].Speakers.active == 0) ? "OFF"  :
1094                                      (info[chan].Speakers.active == 2) ? "MUTE" :
1095                                                                          "ON");
1096         DEMOPrintf( 250, y, 0, "%d", WPADGetSpeakerVolume());
1097     }
1098 }
1099 
1100 /*---------------------------------------------------------------------------*
1101  * Name        : initialize
1102  * Description :
1103  * Arguments   :
1104  * Returns     : None.
1105  *---------------------------------------------------------------------------*/
initialize(void)1106 static void initialize( void )
1107 {
1108     const GXColor DARKBLUE = { 0, 0, 64, 255 };
1109     const int SCREEN_WIDTH  = 320;
1110     const int SCREEN_HEIGHT = 240;
1111 
1112     DEMOInit( &GXNtsc480IntDf );
1113     GXSetCopyClear( DARKBLUE, GX_MAX_Z24 );
1114     GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
1115     DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
1116     GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE );                       // Set pixel processing mode
1117     GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );    // Translucent mode
1118 
1119     DEMOPadInit();
1120 
1121 } /* end initialize() */
1122