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