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.19.2.1  2010/04/02 02:58:32  tojo
15   Fixed a race condition issue to check speaker is off.
16 
17   Revision 1.19  2008/12/24 06:28:38  tojo
18   Modified the error handling of controller data.
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_NONE
393                 ||  info[chan].currStat.cr.err == WPAD_ERR_CORRUPTED)
394                 {
395                     info[chan].button = WPADButtonDown(info[chan].prevStat.cr.button, info[chan].currStat.cr.button);
396                     info[chan].prevStat.cr = info[chan].currStat.cr;
397                 }
398                 else
399                 {
400                     info[chan].button = 0;
401                 }
402                 if (info[chan].Speakers.active > 0)
403                 {
404                     BOOL active = FALSE;
405 
406                     // Stop all sounds when START/PAUSE is pressed
407                     if (info[chan].button & WPAD_BUTTON_HOME)
408                     {
409                         // Stop all voices
410                         for (i = 0; i < AX_MAX_VOICES; i++)
411                         {
412                             Voices[i].state = VOICE_STATE_STOP;
413                         }
414                         continue;
415                     }
416                     if (info[chan].button & WPAD_BUTTON_PLUS)
417                     {
418                         if (info[chan].Speakers.active == 1)
419                         {
420                             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE, MuteOnCallback);
421                         }
422                         info[chan].Speakers.muteReq = TRUE;
423                         continue;
424                     }
425                     if (info[chan].button & WPAD_BUTTON_MINUS)
426                     {
427                         if (info[chan].Speakers.active == 2)
428                         {
429                             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE_OFF, MuteOffCallback);
430                         }
431                         info[chan].Speakers.muteReq = FALSE;
432                         continue;
433                     }
434 
435                     // Use Button map to start sounds
436                     for (i = 0; i < NUM_BUTTON_MAPS; i++)
437                     {
438                         if (info[chan].button & ButtonMap[i][0])
439                         {
440                             PlaySample(chan, &Samples[ButtonMap[i][1]]);
441                         }
442                     }
443 
444                     // Check whether one voice at least is active
445                     for (i = 0; i < AX_MAX_VOICES; i++)
446                     {
447                         if (Voices[i].state != VOICE_STATE_STOPPED && Voices[i].state != VOICE_STATE_STOP)
448                         {
449                             active = TRUE;
450                         }
451                     }
452 
453                     if (!active && info[chan].Speakers.active != 3)
454                     {
455                         // start shutdown speaker.
456                         info[chan].Speakers.active = 3;
457                         WPADControlSpeaker(chan, WPAD_SPEAKER_OFF, SpeakerOffCallback);
458                     }
459                 }
460                 else
461                 {
462                     if (info[chan].button & WPAD_BUTTON_PLUS)
463                     {
464                         info[chan].Speakers.muteReq = TRUE;
465                     }
466                     else if (info[chan].button & WPAD_BUTTON_MINUS)
467                     {
468                         info[chan].Speakers.muteReq = FALSE;
469                     }
470                     else if (!info[chan].Speakers.muteReq && !(info[chan].button & WPAD_BUTTON_HOME) && info[chan].button)
471                     {
472                         WPADControlSpeaker(chan, WPAD_SPEAKER_ON, SpeakerOnCallback);
473                         info[chan].keepBtnMap = info[chan].button;
474                     }
475                 }
476             }
477         }
478 
479         DEMOBeforeRender();
480 
481         DEMOPrintf( 16, 16, 0, "WPAD Demo -- WPAD Axdemo");
482 
483         RenderOperation();
484         RenderControllerStatus();
485 
486         DEMODoneRender();
487 
488     }
489 
490     OSCancelAlarm(&SpeakerAlarm);
491 
492 }
493 
494 /*---------------------------------------------------------------------------*
495  * Name        : UpdateSpeaker
496  * Description :
497  * Arguments   :
498  * Returns     : None.
499  *---------------------------------------------------------------------------*/
UpdateSpeaker(OSAlarm * alarm,OSContext * context)500 static void UpdateSpeaker( OSAlarm *alarm, OSContext *context )
501 {
502 #pragma unused(alarm, context)
503 
504     u8    data[24];
505     u32   flag;
506     s32   chan;
507     BOOL  intr;
508 
509     if (SAMPLES_PER_AUDIO_PACKET <= AXRmtGetSamplesLeft())
510     {
511 
512         for(chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
513         {
514 
515             AXRmtGetSamples(chan, AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET);
516 
517             if (info[chan].Speakers.active)
518             {
519                 intr = OSDisableInterrupts();
520 
521                 if (WPADCanSendStreamData(chan))
522                 {
523                     flag = (info[chan].Speakers.first) ? (u32)WENC_FLAG_FIRST : (u32)WENC_FLAG_CONT;
524                     if (info[chan].Speakers.first)
525                     {
526                         info[chan].Speakers.first = FALSE;
527                     }
528                     WENCGetEncodeData(&info[chan].Speakers.encInfo, flag, (const s16*)AudioBuffer[chan], SAMPLES_PER_AUDIO_PACKET, data);
529 
530                     WPADSendStreamData(chan, data, AUDIO_PACKET_MAX_LEN);
531                 }
532 
533                 OSRestoreInterrupts(intr);
534             }
535         }
536 
537         AXRmtAdvancePtr(SAMPLES_PER_AUDIO_PACKET);
538     }
539 }
540 
541 /*---------------------------------------------------------------------------*
542  * Name        : SpeakerCallback
543  * Description :
544  * Arguments   :
545  * Returns     : None.
546  *---------------------------------------------------------------------------*/
SpeakerCallback(s32 chan,s32 result)547 static void SpeakerCallback( s32 chan, s32 result )
548 {
549     int i;
550 
551     if (result == WPAD_ERR_NONE)
552     {
553         info[chan].Speakers.active = 1;
554         info[chan].Speakers.first = TRUE;
555         info[chan].Speakers.last  = FALSE;
556         memset(&info[chan].Speakers.encInfo, 0, sizeof(WENCInfo));
557 
558         if (info[chan].Speakers.muteReq)
559         {
560             WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE, MuteOnCallback);
561         }
562         else
563         {
564             // Use Button map to start sounds
565             for (i = 0; i < NUM_BUTTON_MAPS; i++)
566             {
567                 if (info[chan].keepBtnMap & ButtonMap[i][0])
568                 {
569                     PlaySample(chan, &Samples[ButtonMap[i][1]]);
570                 }
571             }
572         }
573 
574         // clear btn map.
575         info[chan].keepBtnMap = 0;
576         OSReport("Chan[%d] is ready\n", chan);
577 
578     }
579 }
580 
581 /*---------------------------------------------------------------------------*
582  * Name        : SpeakerOnCallback
583  * Description :
584  * Arguments   :
585  * Returns     : None.
586  *---------------------------------------------------------------------------*/
SpeakerOnCallback(s32 chan,s32 result)587 static void SpeakerOnCallback( s32 chan, s32 result )
588 {
589     if (result == WPAD_ERR_NONE)
590     {
591         WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, SpeakerCallback);
592     }
593 }
594 
595 /*---------------------------------------------------------------------------*
596  * Name        : SpeakerOffCallback
597  * Description :
598  * Arguments   :
599  * Returns     : None.
600  *---------------------------------------------------------------------------*/
SpeakerOffCallback(s32 chan,s32 result)601 static void SpeakerOffCallback( s32 chan, s32 result )
602 {
603 #pragma unused(result)
604 
605     info[chan].Speakers.active = 0;
606 
607     OSReport("Chan[%d] is stopped\n", chan);
608 }
609 
610 /*---------------------------------------------------------------------------*
611  * Name        : MuteOnCallback
612  * Description :
613  * Arguments   :
614  * Returns     : None.
615  *---------------------------------------------------------------------------*/
MuteOnCallback(s32 chan,s32 result)616 static void MuteOnCallback( s32 chan, s32 result )
617 {
618     if (result == WPAD_ERR_NONE)
619     {
620         info[chan].Speakers.active = 2;
621     }
622 }
623 
624 /*---------------------------------------------------------------------------*
625  * Name        : MuteOffCallback
626  * Description :
627  * Arguments   :
628  * Returns     : None.
629  *---------------------------------------------------------------------------*/
MuteOffCallback(s32 chan,s32 result)630 static void MuteOffCallback( s32 chan, s32 result )
631 {
632     if (result == WPAD_ERR_NONE)
633     {
634         info[chan].Speakers.active = 1;
635     }
636 }
637 
638 /*---------------------------------------------------------------------------*
639  * Name        : ExtensionCallback
640  * Description :
641  * Arguments   :
642  * Returns     : None.
643  *---------------------------------------------------------------------------*/
ExtensionCallback(s32 chan,s32 result)644 static void ExtensionCallback( s32 chan, s32 result )
645 {
646     switch(result)
647     {
648         case WPAD_DEV_CORE:
649         case WPAD_DEV_FUTURE:
650         case WPAD_DEV_NOT_SUPPORTED: WPADSetDataFormat(chan, WPAD_FMT_CORE);      break;
651         case WPAD_DEV_FREESTYLE:     WPADSetDataFormat(chan, WPAD_FMT_FREESTYLE); break;
652         case WPAD_DEV_CLASSIC:       WPADSetDataFormat(chan, WPAD_FMT_CLASSIC);   break;
653     }
654 }
655 
656 /*---------------------------------------------------------------------------*
657  * Name        : ConnectCallback
658  * Description :
659  * Arguments   :
660  * Returns     : None.
661  *---------------------------------------------------------------------------*/
ConnectCallback(s32 chan,s32 reason)662 static void ConnectCallback( s32 chan, s32 reason )
663 {
664     OSReport("ConnectCallback(%d) : %s\n", chan, (reason < 0) ? "disconnect" : "connect");
665 
666     info[chan].Speakers.active = 0;
667     if (reason >= 0)
668     {
669         WPADSetDataFormat(chan, WPAD_FMT_CORE);
670     }
671 }
672 
673 
674 /*---------------------------------------------------------------------------*
675  * Name        :
676  * Description :
677  * Arguments   : None.
678  * Returns     : None.
679  *---------------------------------------------------------------------------*/
myAlloc(u32 size)680 void *myAlloc( u32 size )
681 {
682     void *ptr;
683 
684     ptr = MEMAllocFromExpHeap(hExpHeap, size);
685     ASSERTMSG(ptr, "Memory allocation failed\n");
686 
687     return(ptr);
688 }
689 
690 /*---------------------------------------------------------------------------*
691  * Name        :
692  * Description :
693  * Arguments   : None.
694  * Returns     : None.
695  *---------------------------------------------------------------------------*/
myFree(void * ptr)696 u8 myFree( void *ptr )
697 {
698     MEMFreeToExpHeap(hExpHeap, ptr);
699     return(1);
700 }
701 
702 
703 /*---------------------------------------------------------------------------*
704     Name:           LoadSamples
705 
706     Description:    Loads ADPCM files into Main Memory (Header + Data) and
707                     ARAM (Data)
708 
709     Arguments:      none
710 
711     Returns:        none
712  *---------------------------------------------------------------------------*/
LoadSamples(void)713 static void LoadSamples( void )
714 {
715     u32 i;
716 
717     // Load samples
718     for (i = 0; i < NUM_SAMPLES; i++)
719     {
720         // Load ADPCM file into MRAM (96 byte header included)
721         Samples[i].mramAddr = LoadFileIntoRam(SampleFiles[i]);
722 
723         // Sanity Check
724         if (Samples[i].mramAddr == NULL)
725         {
726             OSReport("WARNING! Sample %d not loaded\n", i);
727             continue;
728         }
729     }
730 }
731 
732 /*---------------------------------------------------------------------------*
733     Name:           PlaySample
734 
735     Description:    Utility function that will play a sample
736 
737     Arguments:      sample    Pointer to the sample information
738 
739     Returns:        pointer to the allocated voice
740  *---------------------------------------------------------------------------*/
PlaySample(s32 chan,SampleInfo * sample)741 static void PlaySample( s32 chan, SampleInfo *sample )
742 {
743     AXVPB    *voice;
744 
745     if (sample->mramAddr == NULL)
746     {
747         OSReport("WARNING! Sample not loaded!\n");
748         return;
749     }
750 
751     // Aquire Voice and start
752     voice = AquireVoiceADPCM(chan, sample->mramAddr);
753     if (voice == NULL)
754     {
755         OSReport("WARNING: Ran out of voices!\n");
756         return;
757     }
758     Voices[voice->index].voice = voice;
759     Voices[voice->index].state = VOICE_STATE_START;
760 }
761 
762 /*---------------------------------------------------------------------------*
763     Name:            AudioFrameCallback
764 
765     Description:    Callback that process audio data per 5ms audio frame.
766                     In this case, it stops, resets, and starts a voice.
767 
768     Arguments:      none
769 
770     Returns:        none
771  *---------------------------------------------------------------------------*/
AudioFrameCallback(void)772 static void AudioFrameCallback( void )
773 {
774     u32 i;
775     BOOL bStopFlag = FALSE;
776 
777     // Monitor each voice and process states. This must be done in the
778     // callback
779     for (i = 0; i < AX_MAX_VOICES; i++)
780     {
781 
782         // Skip NULL entries
783         if (Voices[i].voice == NULL) continue;
784 
785         switch (Voices[i].state)
786         {
787             case VOICE_STATE_STOPPED:
788                 break;
789             case VOICE_STATE_START:
790                 // Start the voice
791                 AXSetVoiceState(Voices[i].voice, AX_PB_STATE_RUN);
792                 Voices[i].state = VOICE_STATE_STARTED;
793                 break;
794             case VOICE_STATE_STARTED:
795                 // Skip a frame
796                 Voices[i].state = VOICE_STATE_PLAYING;
797                 break;
798             case VOICE_STATE_PLAYING:
799                 // Check to see if the voice is finished, if so, stop it
800                 if (Voices[i].voice->pb.state == AX_PB_STATE_STOP)
801                     bStopFlag = TRUE;
802                 break;
803             case VOICE_STATE_STOP:
804                 // Force a voice to stop
805                 bStopFlag = TRUE;
806                 break;
807         }
808 
809         // A voice must be stopped
810         if (bStopFlag)
811         {
812             AXSetVoiceState(Voices[i].voice, AX_PB_STATE_STOP);
813             AXFreeVoice(Voices[i].voice);
814             Voices[i].voice = NULL;
815             Voices[i].state = VOICE_STATE_STOPPED;
816             bStopFlag = FALSE;
817         }
818     }
819 
820     // run the sequencer
821     SEQRunAudioFrame();
822 
823     // run the synth
824     SYNRunAudioFrame();
825 
826     // tell the mixer to update settings
827     MIXUpdateSettings();
828 }
829 
830 
831 /*---------------------------------------------------------------------------*
832     Name:           VoiceCallback
833 
834     Description:    Callback for when a voice is dropped.
835 
836     Arguments:      unused
837 
838     Returns:        none
839  *---------------------------------------------------------------------------*/
VoiceCallback(void * voiceIn)840 static void VoiceCallback( void * voiceIn )
841 {
842     AXVPB *voice = (AXVPB*)voiceIn;
843 
844     // Note: Voice is auto-magically stopped by AX layer when dropped
845 
846     // Application clean-up
847     Voices[voice->index].voice = NULL;
848     Voices[voice->index].state = VOICE_STATE_STOPPED;
849 }
850 
851 /*---------------------------------------------------------------------------*
852     Name:           AquireVoiceADPCM
853 
854     Description:    Parses the ADPCM header, sets voice parameters
855 
856     Arguments:      pDSPADPCMData    Pointer to the ADPCM data in MRAM
857                     pARAMStart        ARAM Start address
858 
859     Returns:        pointer to the allocated voice or NULL
860  *---------------------------------------------------------------------------*/
AquireVoiceADPCM(s32 chan,void * pDSPADPCMData)861 static AXVPB* AquireVoiceADPCM( s32 chan, void *pDSPADPCMData )
862 {
863     DSPADPCM            *ps = (DSPADPCM*)pDSPADPCMData;
864     AXPBADDR            addr;
865     AXPBADPCM           adpcm;
866     AXPBSRC             src;
867     AXPBADPCMLOOP       adpcmLoop;
868     AXVPB*              voice;
869     u32                 srcBits;
870     u32                 mramAddress;
871     u32                 pMRAMStart;
872 
873     // Allocate a voice for use
874     voice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);
875 
876     if (voice == NULL)
877     {
878         OSReport("WARNING! Voice Acquisition failed!\n");
879         return NULL;
880     }
881 
882     // Fill AXPBADDR structure
883     // All the folowing addresses are in nibbles
884 
885     addr.loopFlag           = ps->loop_flag;
886     addr.format             = ps->format;
887 
888     pMRAMStart = OSCachedToPhysical(GetDSPADPCMDataAddress(pDSPADPCMData));
889 
890     // Support for looping
891     if (addr.loopFlag)
892     {
893         adpcmLoop.loop_pred_scale = ps->lps;
894         adpcmLoop.loop_yn1        = ps->lyn1;
895         adpcmLoop.loop_yn2        = ps->lyn2;
896     }
897 
898     mramAddress             = (ps->sa + Bytes2Nibbles(pMRAMStart));
899     addr.loopAddressHi      = (u16)(mramAddress >> 16);
900     addr.loopAddressLo      = (u16)(mramAddress & 0xFFFF);
901 
902     mramAddress             = (ps->ea + Bytes2Nibbles(pMRAMStart));
903     addr.endAddressHi       = (u16)(mramAddress >> 16);
904     addr.endAddressLo       = (u16)(mramAddress & 0xFFFF);
905 
906     mramAddress             = (ps->ca + Bytes2Nibbles(pMRAMStart));
907     addr.currentAddressHi   = (u16)(mramAddress >> 16);
908     addr.currentAddressLo   = (u16)(mramAddress & 0xFFFF);
909 
910     // Fill AXPBADPCM structure
911     adpcm.a[0][0]           = ps->coef[0];
912     adpcm.a[0][1]           = ps->coef[1];
913     adpcm.a[1][0]           = ps->coef[2];
914     adpcm.a[1][1]           = ps->coef[3];
915     adpcm.a[2][0]           = ps->coef[4];
916     adpcm.a[2][1]           = ps->coef[5];
917     adpcm.a[3][0]           = ps->coef[6];
918     adpcm.a[3][1]           = ps->coef[7];
919     adpcm.a[4][0]           = ps->coef[8];
920     adpcm.a[4][1]           = ps->coef[9];
921     adpcm.a[5][0]           = ps->coef[10];
922     adpcm.a[5][1]           = ps->coef[11];
923     adpcm.a[6][0]           = ps->coef[12];
924     adpcm.a[6][1]           = ps->coef[13];
925     adpcm.a[7][0]           = ps->coef[14];
926     adpcm.a[7][1]           = ps->coef[15];
927     adpcm.gain              = ps->gain;
928     adpcm.pred_scale        = ps->ps;
929     adpcm.yn1               = ps->yn1;
930     adpcm.yn2               = ps->yn2;
931 
932     // Fill AXPBSRC structure for proper sample rates
933     srcBits = (u32)(0x00010000 * ((f32)ps->sample_rate / AX_IN_SAMPLES_PER_SEC));
934 
935     src.ratioHi = (u16)(srcBits >> 16);
936     src.ratioLo = (u16)(srcBits & 0xFFFF);
937     src.currentAddressFrac = 0;
938     src.last_samples[0] = 0;
939     src.last_samples[1] = 0;
940     src.last_samples[2] = 0;
941     src.last_samples[3] = 0;
942 
943     // Set voice type
944     AXSetVoiceType(voice, AX_PB_TYPE_NORMAL);
945 
946     // Set Address and ADPCM information from header
947     AXSetVoiceAddr(voice, &addr);
948     AXSetVoiceAdpcm(voice, &adpcm);
949     AXSetVoiceAdpcmLoop(voice, &adpcmLoop);
950 
951     // Set simple volumes
952     AXSetVoiceMix(voice, &g_mix);
953     AXSetVoiceVe(voice, &g_ve);
954 
955     // Set controller speaker
956     AXSetVoiceRmtOn(voice, AX_PB_REMOTE_ON);
957     memset(&g_rmix, 0, sizeof(AXPBRMTMIX));
958     switch(chan)
959     {
960         case WPAD_CHAN0:
961             g_rmix.vMain0 = 0x8000;      // chan0 main
962             g_rmix.vAux0  = 0x8000;      // chan0 aux
963             break;
964         case WPAD_CHAN1:
965             g_rmix.vMain1 = 0x8000;      // chan1 main
966             g_rmix.vAux1  = 0x8000;      // chan1 aux
967             break;
968         case WPAD_CHAN2:
969             g_rmix.vMain2 = 0x8000;      // chan2 main
970             g_rmix.vAux2  = 0x8000;      // chan2 aux
971             break;
972         case WPAD_CHAN3:
973             g_rmix.vMain3 = 0x8000;      // chan3 main
974             g_rmix.vAux3  = 0x8000;      // chan3 aux
975             break;
976     }
977     AXSetVoiceRmtMix(voice, &g_rmix);
978 
979     // Set sample rate
980     AXSetVoiceSrcType(voice, AX_SRC_TYPE_LINEAR);
981     AXSetVoiceSrc(voice, &src);
982 
983     return voice;
984 }
985 
986 /*---------------------------------------------------------------------------*
987     Name:            LoadFileIntoRam
988 
989     Description:    Loads a file into memory. Memory is allocated.
990 
991     Arguments:      path    File to load into main memory
992 
993     Returns:        pointer to file in main memory or NULL if not opened
994  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)995 static void * LoadFileIntoRam( char *path )
996 {
997     DVDFileInfo handle;
998     u32         round_length;
999     s32         read_length;
1000     void        *buffer;
1001 
1002     // Open File
1003     if (!DVDOpen(path, &handle))
1004     {
1005         OSReport("WARNING! Failed to open %s\n", path);
1006         return NULL;
1007     }
1008 
1009     // Make sure file length is not 0
1010     if (DVDGetLength(&handle) == 0)
1011     {
1012         OSReport("WARNING! File length is 0\n");
1013         return NULL;
1014     }
1015 
1016     round_length = OSRoundUp32B(DVDGetLength(&handle));
1017     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
1018 
1019     // Make sure we got a buffer
1020     if (buffer == NULL)
1021     {
1022         OSReport("WARNING! Unable to allocate buffer\n");
1023         return NULL;
1024     }
1025 
1026     // Read Files
1027     read_length  = DVDRead(&handle, buffer, (s32)(round_length), 0);
1028 
1029     // Make sure we read the file correctly
1030     if (read_length <= 0)
1031     {
1032         OSReport("WARNING! File lenght is wrong\n");
1033         return NULL;
1034     }
1035 
1036     return buffer;
1037 }
1038 
1039 static const s16 HEIGHT = 10;
1040 
1041 /*---------------------------------------------------------------------------*
1042  * Name        : RenderOperation
1043  * Description :
1044  * Arguments   :
1045  * Returns     : None.
1046  *---------------------------------------------------------------------------*/
RenderOperation(void)1047 static void RenderOperation( void )
1048 {
1049     s16 y = 96;
1050     char button[256];
1051     u32 i;
1052 
1053     for (i = 0; i < NUM_BUTTON_MAPS; i++)
1054     {
1055         switch (ButtonMap[i][0])
1056         {
1057             case WPAD_BUTTON_A: sprintf(button, "A    "); break;
1058             case WPAD_BUTTON_B: sprintf(button, "B    "); break;
1059             case WPAD_BUTTON_1: sprintf(button, "1    "); break;
1060             case WPAD_BUTTON_2: sprintf(button, "2    "); break;
1061             case WPAD_BUTTON_DOWN:  sprintf(button, "Down "); break;
1062             case WPAD_BUTTON_UP:    sprintf(button, "Up   "); break;
1063             case WPAD_BUTTON_LEFT:  sprintf(button, "Left "); break;
1064             case WPAD_BUTTON_RIGHT: sprintf(button, "Right"); break;
1065         }
1066         DEMOPrintf(  16, y+=HEIGHT, 0, "%s    : %s", button, SampleFiles[ButtonMap[i][1]]);
1067     }
1068 
1069     DEMOPrintf(  16, y+=HEIGHT, 0, "Home     : Stop all sounds");
1070     DEMOPrintf(  16, y+=HEIGHT, 0, "Plus     : Mute On");
1071     DEMOPrintf(  16, y+=HEIGHT, 0, "Minus    : Mute Off");
1072 }
1073 
1074 /*---------------------------------------------------------------------------*
1075  * Name        : RenderControllerStatus
1076  * Description :
1077  * Arguments   :
1078  * Returns     : None.
1079  *---------------------------------------------------------------------------*/
RenderControllerStatus(void)1080 static void RenderControllerStatus( void )
1081 {
1082     s16 y = 32;
1083     int chan;
1084 
1085     DEMOPrintf( 150, y, 0, "speaker");
1086     DEMOPrintf( 250, y, 0, "volume");
1087     for(chan=0; chan<WPAD_MAX_CONTROLLERS; chan++)
1088     {
1089         y += HEIGHT;
1090         DEMOPrintf(  16, y, 0, "CHAN_%d [%s]",
1091             chan,
1092             (info[chan].status == WPAD_ERR_NO_CONTROLLER) ? "--" :
1093             (info[chan].type == 0) ? "CORE"     :
1094             (info[chan].type == 1) ? "NUNCHAKU" :
1095             (info[chan].type == 2) ? "CLASSIC"  :
1096                                      "UNKNOWN"
1097         );
1098         DEMOPrintf( 150, y, 0, "%s", (info[chan].Speakers.active == 0) ? "OFF"  :
1099                                      (info[chan].Speakers.active == 2) ? "MUTE" :
1100                                                                          "ON");
1101         DEMOPrintf( 250, y, 0, "%d", WPADGetSpeakerVolume());
1102     }
1103 }
1104 
1105 /*---------------------------------------------------------------------------*
1106  * Name        : initialize
1107  * Description :
1108  * Arguments   :
1109  * Returns     : None.
1110  *---------------------------------------------------------------------------*/
initialize(void)1111 static void initialize( void )
1112 {
1113     const GXColor DARKBLUE = { 0, 0, 64, 255 };
1114     const int SCREEN_WIDTH  = 320;
1115     const int SCREEN_HEIGHT = 240;
1116 
1117     DEMOInit( &GXNtsc480IntDf );
1118     GXSetCopyClear( DARKBLUE, GX_MAX_Z24 );
1119     GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
1120     DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
1121     GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE );                       // Set pixel processing mode
1122     GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );    // Translucent mode
1123 
1124     DEMOPadInit();
1125 
1126 } /* end initialize() */
1127