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