1 /*---------------------------------------------------------------------------*
2 Project: Revolution WPAD AX demo
3 File: wpad_seqdemo.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_seqdemo.c,v $
14 Revision 1.2 08/03/2006 13:32:55 tojo
15 Removed old APIs.
16
17 Revision 1.1 07/26/2006 07:47:32 aka
18 Initial check-in.
19
20
21 $NoKeywords: $
22 *---------------------------------------------------------------------------*/
23
24 #include <string.h>
25
26 #include <demo.h>
27 #include <revolution/mem.h>
28 #include <revolution/mix.h>
29 #include <revolution/syn.h>
30 #include <revolution/seq.h>
31 #include <revolution/wenc.h>
32 #include <revolution/wpad.h>
33
34 /*---------------------------------------------------------------------------*
35 SEQ
36 *---------------------------------------------------------------------------*/
37
38 // zero buffer
39 #define ZEROBUFFER_BYTES 512
40
41 // data
42 #define GM_WT "/axdemo/synth/gm16adpcm.wt"
43 #define GM_PCM "/axdemo/synth/gm16adpcm.pcm"
44 #define MIDI_FILE_MAIN "/axdemo/midi/2nd_time.mid"
45 #define MIDI_FILE_REMOTE "/axdemo/midi/autumnal.mid"
46
47 // function prototypes
48 static void *LoadFileIntoRam ( char *path );
49 static void AudioFrameCallback ( void );
50 static void VoiceInitCallback ( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel );
51 static void VoiceUpdateCallback ( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel );
52
53 /*---------------------------------------------------------------------------*
54 WPAD
55 *---------------------------------------------------------------------------*/
56
57 // allocator functions for WPAD
58 static void *myAlloc ( u32 size );
59 static u8 myFree ( void *ptr );
60
61 // function prototypes
62 static void UpdateSpeaker ( OSAlarm *alarm, OSContext *context );
63 static void SpeakerCallback ( s32 chan, s32 result );
64 static void SpeakerOnCallback ( s32 chan, s32 result );
65 static void ConnectCallback ( s32 chan, s32 reason );
66
67 // Speaker Status
68 typedef struct SpeakerInfo
69 {
70 u8 active;
71 WENCInfo encInfo;
72 BOOL first;
73 BOOL last;
74
75 } SpeakerInfo;
76
77 // Controller Status
78 typedef struct ContInfo
79 {
80 u32 type;
81 s32 status;
82 WPADStatus currStat;
83 WPADStatus prevStat;
84 SpeakerInfo Speakers;
85
86 SEQSEQUENCE Sequence;
87 u8 play;
88
89 } ContInfo;
90
91 static ContInfo info[WPAD_MAX_CONTROLLERS];
92
93 // Periodic Alarms for audio streaming
94 static OSAlarm SpeakerAlarm;
95
96 // Audio buffers
97 #define SAMPLES_PER_AUDIO_PACKET 40
98 #define AUDIO_PACKET_LEN 20 // SAMPLES_PER_AUDIO_PACKET / 2
99
100 /*---------------------------------------------------------------------------*
101 etc.
102 *---------------------------------------------------------------------------*/
103
104 // Exp Heap
105 static MEMHeapHandle hExpHeap;
106
107 // function prototypes
108 static void initialize();
109 static void RenderOperation();
110 static void RenderControllerStatus();
111
112 /*---------------------------------------------------------------------------*
113 * Name : main
114 * Description : main
115 * Arguments : None.
116 * Returns : None.
117 *---------------------------------------------------------------------------*/
main(void)118 void main (void)
119 {
120 s32 i;
121 s32 chan;
122 u16 button;
123
124 void *arenaMem2Lo;
125 void *arenaMem2Hi;
126
127 SEQSEQUENCE SequenceMain;
128 u8 *MidiFileMain;
129 u8 *MidiFileRemote;
130 u8 *Wavetable;
131 u8 *Pcm;
132 u8 *ZeroBuffer;
133
134 // Initialize DEMO
135 initialize();
136
137 // initialize Exp Heap on MEM2
138 arenaMem2Lo = OSGetMEM2ArenaLo();
139 arenaMem2Hi = OSGetMEM2ArenaHi();
140 hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
141 ASSERT(hExpHeap != NULL);
142
143 //
144 // Initialize Audio
145 //
146
147 AIInit(NULL);
148 AXInit();
149 MIXInit();
150 SYNInit();
151 SEQInit();
152
153 // Load Audio Data
154 Wavetable = LoadFileIntoRam(GM_WT);
155 Pcm = LoadFileIntoRam(GM_PCM);
156 MidiFileMain = LoadFileIntoRam(MIDI_FILE_MAIN);
157 MidiFileRemote = LoadFileIntoRam(MIDI_FILE_REMOTE);
158
159 // Alloc Zero Buffer
160 ZeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8);
161 memset(ZeroBuffer, 0, ZEROBUFFER_BYTES);
162 DCFlushRange(ZeroBuffer, ZEROBUFFER_BYTES);
163
164 // Register Callback with AX for audio processing
165 AXRegisterCallback(&AudioFrameCallback);
166
167 // Prepare Sequence for Main
168 SEQAddSequence(&SequenceMain,
169 MidiFileMain,
170 Wavetable,
171 Pcm,
172 ZeroBuffer,
173 16,
174 15,
175 1
176 );
177
178 // Play Sequence for Main
179 SEQSetState(&SequenceMain, SEQ_STATE_RUNLOOPED);
180
181 // Prepare Sequence for Remotes
182 for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
183 {
184 SEQAddSequence(&info[i].Sequence,
185 MidiFileRemote,
186 Wavetable,
187 Pcm,
188 ZeroBuffer,
189 16,
190 15,
191 1
192 );
193 SYNSetMasterVolume( &info[i].Sequence.synth, -960);
194 SYNSetInitCallback( &info[i].Sequence.synth, VoiceInitCallback);
195 SYNSetUpdateCallback(&info[i].Sequence.synth, VoiceUpdateCallback);
196 }
197
198 //
199 // Initialize WPAD
200 //
201
202 WPADRegisterAllocator(myAlloc, myFree);
203
204 WPADInit();
205
206 while (WPADGetStatus() != WPAD_STATE_SETUP)
207 {
208 ;
209 }
210
211 for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
212 {
213 WPADSetConnectCallback((s32)i, ConnectCallback);
214 }
215
216 OSCreateAlarm(&SpeakerAlarm);
217 OSSetPeriodicAlarm(&SpeakerAlarm, OSGetTime(), WPAD_STRM_INTERVAL, UpdateSpeaker);
218
219
220 // Spin
221 while (1)
222 {
223 for (chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
224 {
225 info[chan].status = WPADProbe(chan, &info[chan].type);
226
227 if (info[chan].status == WPAD_ERR_NONE)
228 {
229 WPADRead(chan, &info[chan].currStat);
230
231 button = WPADButtonDown(info[chan].prevStat.button, info[chan].currStat.button);
232 info[chan].prevStat = info[chan].currStat;
233
234 if (button & WPAD_BUTTON_A)
235 {
236 if (!info[chan].play)
237 {
238 SEQSetState(&info[chan].Sequence, SEQ_STATE_RUN);
239 }
240 else
241 {
242 SEQSetState(&info[chan].Sequence, SEQ_STATE_STOP);
243 }
244 }
245
246 if (SEQGetState(&info[chan].Sequence) == SEQ_STATE_RUN)
247 {
248 info[chan].play = 1;
249 }
250 else
251 {
252 info[chan].play = 0;
253 }
254 }
255 }
256
257 DEMOBeforeRender();
258 RenderOperation();
259 RenderControllerStatus();
260 DEMODoneRender();
261 }
262
263 OSCancelAlarm(&SpeakerAlarm);
264 }
265
266 /*---------------------------------------------------------------------------*
267 * Name : UpdateSpeaker
268 * Description :
269 * Arguments :
270 * Returns : None.
271 *---------------------------------------------------------------------------*/
UpdateSpeaker(OSAlarm * alarm,OSContext * context)272 static void UpdateSpeaker(OSAlarm *alarm, OSContext *context)
273 {
274 #pragma unused(alarm, context)
275
276 s16 pcmData[SAMPLES_PER_AUDIO_PACKET];
277 u8 encData[AUDIO_PACKET_LEN];
278 u32 flag;
279 s32 chan;
280 BOOL adv = FALSE;
281
282 for (chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
283 {
284 if (SAMPLES_PER_AUDIO_PACKET == AXRmtGetSamples(chan, pcmData, SAMPLES_PER_AUDIO_PACKET))
285 {
286 adv = TRUE;
287
288 if (info[chan].Speakers.active)
289 {
290 flag = (info[chan].Speakers.first) ? (u32)WENC_FLAG_FIRST : (u32)WENC_FLAG_CONT;
291 if (info[chan].Speakers.first)
292 {
293 info[chan].Speakers.first = FALSE;
294 }
295
296 WENCGetEncodeData(&info[chan].Speakers.encInfo,
297 flag,
298 pcmData,
299 SAMPLES_PER_AUDIO_PACKET,
300 encData);
301
302 WPADSendStreamData(chan, encData, AUDIO_PACKET_LEN);
303 }
304 }
305 }
306
307 if (adv)
308 {
309 AXRmtAdvancePtr(SAMPLES_PER_AUDIO_PACKET);
310 }
311 }
312
313 /*---------------------------------------------------------------------------*
314 * Name : SpeakerCallback
315 * Description :
316 * Arguments :
317 * Returns : None.
318 *---------------------------------------------------------------------------*/
SpeakerCallback(s32 chan,s32 result)319 static void SpeakerCallback( s32 chan, s32 result )
320 {
321 if (result == WPAD_ERR_NONE)
322 {
323 info[chan].Speakers.active = 1;
324 info[chan].Speakers.first = TRUE;
325 info[chan].Speakers.last = FALSE;
326 memset(&info[chan].Speakers.encInfo, 0, sizeof(WENCInfo));
327
328 OSReport("Chan[%d] is ready\n", chan);
329 }
330 }
331
332 /*---------------------------------------------------------------------------*
333 * Name : SpeakerOnCallback
334 * Description :
335 * Arguments :
336 * Returns : None.
337 *---------------------------------------------------------------------------*/
SpeakerOnCallback(s32 chan,s32 result)338 static void SpeakerOnCallback( s32 chan, s32 result )
339 {
340 if (result == WPAD_ERR_NONE)
341 {
342 WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, SpeakerCallback);
343 }
344 }
345
346 /*---------------------------------------------------------------------------*
347 * Name : ConnectCallback
348 * Description :
349 * Arguments :
350 * Returns : None.
351 *---------------------------------------------------------------------------*/
ConnectCallback(s32 chan,s32 reason)352 static void ConnectCallback( s32 chan, s32 reason )
353 {
354 OSReport("ConnectCallback(%d) : %s\n", chan, (reason < 0) ? "disconnect" : "connect");
355
356 info[chan].Speakers.active = 0;
357 if (reason >= 0)
358 {
359 WPADSetDataFormat(chan, WPAD_FMT_CORE);
360 WPADControlSpeaker(chan, WPAD_SPEAKER_ON, SpeakerOnCallback);
361 }
362 else
363 {
364 SEQSetState(&info[chan].Sequence, SEQ_STATE_STOP);
365 info[chan].play = 0;
366 }
367 }
368
369 /*---------------------------------------------------------------------------*
370 * Name : myAlloc
371 * Description :
372 * Arguments : None.
373 * Returns : None.
374 *---------------------------------------------------------------------------*/
myAlloc(u32 size)375 static void *myAlloc(u32 size)
376 {
377 void *ptr;
378
379 ptr = MEMAllocFromExpHeap(hExpHeap, size);
380 ASSERTMSG(ptr, "Memory allocation failed\n");
381
382 return(ptr);
383 }
384
385 /*---------------------------------------------------------------------------*
386 * Name : myFree
387 * Description :
388 * Arguments : None.
389 * Returns : None.
390 *---------------------------------------------------------------------------*/
myFree(void * ptr)391 static u8 myFree(void *ptr)
392 {
393 MEMFreeToExpHeap(hExpHeap, ptr);
394 return(1);
395 }
396
397 /*---------------------------------------------------------------------------*
398 * Name : AudioFrameCallback
399 * Description : Callback that process audio data per 3ms audio frame.
400 * Arguments : None.
401 * Returns : : None.
402 *---------------------------------------------------------------------------*/
AudioFrameCallback(void)403 static void AudioFrameCallback(void)
404 {
405 // run the sequencer
406 SEQRunAudioFrame();
407
408 // run the synth
409 SYNRunAudioFrame();
410
411 // tell the mixer to update settings
412 MIXUpdateSettings();
413 }
414
415 /*---------------------------------------------------------------------------*
416 * Name : LoadFileIntoRam
417 * Description : Loads a file into memory. Memory is allocated.
418 * Arguments : path File to load into main memory
419 * Returns : : pointer to file in main memory or NULL if not opened
420 *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)421 static void *LoadFileIntoRam(char *path)
422 {
423 DVDFileInfo handle;
424 u32 round_length;
425 s32 read_length;
426 void *buffer;
427
428 // Open File
429 if (!DVDOpen(path, &handle))
430 {
431 OSReport("WARNING! Failed to open %s\n", path);
432 return NULL;
433 }
434
435 // Make sure file length is not 0
436 if (DVDGetLength(&handle) == 0)
437 {
438 OSReport("WARNING! File length is 0\n");
439 return NULL;
440 }
441
442 round_length = OSRoundUp32B(DVDGetLength(&handle));
443 buffer = MEMAllocFromExpHeapEx(hExpHeap, round_length, 32);
444
445 // Make sure we got a buffer
446 if (buffer == NULL)
447 {
448 OSReport("WARNING! Unable to allocate buffer\n");
449 return NULL;
450 }
451
452 // Read Files
453 read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
454
455 // Make sure we read the file correctly
456 if (read_length <= 0)
457 {
458 OSReport("WARNING! File lenght is wrong\n");
459 return NULL;
460 }
461
462 return buffer;
463 }
464
465 /*---------------------------------------------------------------------------*
466 * Name : RenderOperation
467 * Description :
468 * Arguments : None.
469 * Returns : : None.
470 *---------------------------------------------------------------------------*/
471 static const s16 HEIGHT = 10;
RenderOperation(void)472 static void RenderOperation(void)
473 {
474 s16 y = 64;
475
476 DEMOPrintf( 16, y += HEIGHT, 0, "button A : Start/Stop Sequence");
477 }
478
479 /*---------------------------------------------------------------------------*
480 * Name : RenderControllerStatus
481 * Description :
482 * Arguments : None.
483 * Returns : : None.
484 *---------------------------------------------------------------------------*/
RenderControllerStatus(void)485 static void RenderControllerStatus(void)
486 {
487 s16 y = 16;
488 int chan;
489
490 DEMOPrintf( 150, y, 0, "speaker");
491 DEMOPrintf( 220, y, 0, "sequence");
492 for( chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
493 {
494 y += HEIGHT;
495 DEMOPrintf( 16, y, 0, "CHAN_%d [%s]",
496 chan,
497 (info[chan].status == WPAD_ERR_NO_CONTROLLER) ? "--" :
498 (info[chan].type == 0) ? "CORE" :
499 (info[chan].type == 1) ? "NUNCHAKU" :
500 (info[chan].type == 2) ? "CLASSIC" :
501 "UNKNOWN"
502 );
503 DEMOPrintf( 150, y, 0, "%s", (info[chan].Speakers.active == 1) ? "ON" :
504 (info[chan].Speakers.active == 2) ? "MUTE" :
505 "OFF");
506 DEMOPrintf( 220, y, 0, "%s", (info[chan].play == 0) ? "STOP" :
507 "PLAY");
508 }
509 }
510
511 /*---------------------------------------------------------------------------*
512 * Name : initialize
513 * Description : Initialize GX.
514 * Arguments : None.
515 * Returns : : None.
516 *---------------------------------------------------------------------------*/
initialize(void)517 static void initialize(void)
518 {
519 const GXColor DARKBLUE = { 0, 0, 64, 255 };
520 const int SCREEN_WIDTH = 320;
521 const int SCREEN_HEIGHT = 240;
522
523 DEMOInit( &GXNtsc480IntDf );
524 GXSetCopyClear( DARKBLUE, GX_MAX_Z24 );
525 GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
526 DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
527 GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE ); // Set pixel processing mode
528 GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR ); // Translucent mode
529
530 DEMOPadInit();
531 }
532
533 /*---------------------------------------------------------------------------*
534 * Name : VoiceInitCallback
535 * Description :
536 * Arguments :
537 * Returns : : None.
538 *---------------------------------------------------------------------------*/
VoiceInitCallback(AXVPB * axvpb,SYNSYNTH * synth,u8 midiChannel)539 static void VoiceInitCallback(AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel)
540 {
541 #pragma unused(midiChannel)
542
543 s32 i;
544
545 for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
546 {
547 if (synth == &info[i].Sequence.synth)
548 {
549 break;
550 }
551 }
552
553 switch(i)
554 {
555 case 0:
556 MIXRmtSetVolumes(axvpb, 0, 0, -960, -960, -960, -960, -960, -960, -960);
557 break;
558 case 1:
559 MIXRmtSetVolumes(axvpb, 0, -960, 0, -960, -960, -960, -960, -960, -960);
560 break;
561 case 2:
562 MIXRmtSetVolumes(axvpb, 0, -960, -960, 0, -960, -960, -960, -960, -960);
563 break;
564 default:
565 MIXRmtSetVolumes(axvpb, 0, -960, -960, -960, 0, -960, -960, -960, -960);
566 break;
567 }
568
569 AXSetVoiceRmtOn(axvpb, AX_PB_REMOTE_ON);
570 }
571
572 /*---------------------------------------------------------------------------*
573 * Name : VoiceUpdateCallback
574 * Description :
575 * Arguments :
576 * Returns : : None.
577 *---------------------------------------------------------------------------*/
VoiceUpdateCallback(AXVPB * axvpb,SYNSYNTH * synth,u8 midiChannel)578 static void VoiceUpdateCallback(AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel)
579 {
580 #pragma unused(axvpb)
581 #pragma unused(synth)
582 #pragma unused(midiChannel)
583 }
584