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