1 /*---------------------------------------------------------------------------*
2 Project: AX low-pass filter demo application
3 File: axfilter.c
4
5 Copyright (C)1998-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: axfilter.c,v $
14 Revision 1.10 06/08/2006 06:06:07 aka
15 Removed setting of tempDisableFX for new AXFX.
16
17 Revision 1.9 02/21/2006 01:04:15 mitu
18 modified am.h path.
19
20 Revision 1.8 02/20/2006 04:13:07 mitu
21 changed include path from dolphin/ to revolution/.
22
23 Revision 1.7 02/02/2006 08:33:48 aka
24 Added AXFXSetHooks() to alloc from MEM2 in AXFX.
25
26 Revision 1.6 02/02/2006 07:35:27 aka
27 Modified using MEM functions instead of OSAlloc()/OSFree().
28
29 Revision 1.5 02/01/2006 08:22:51 aka
30 Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif.
31
32 Revision 1.4 2006/01/31 08:07:05 aka
33 Added cast from u32 to u8* in relation to changing API around ARAM.
34
35 Revision 1.3 2006/01/27 04:54:10 ekwon
36 Corrected "\%" escape sequence warning (replaced with "%%").
37
38 Revision 1.2 11/08/2005 02:55:02 aka
39 Changed suiting to Revolution's audio spec.
40
41 Revision 1.1 11/04/2005 05:01:39 aka
42 Imported from dolphin tree.
43
44 3 03/04/24 8:42 Dante
45 Removed reverbDPL2.crosstalk
46
47 2 03/02/02 5:05p Akagi
48 Added 3 casts to remove warning messages.
49
50 1 03/01/22 12:52 Ntd1
51 Added axfilter.c
52
53 $NoKeywords: $
54 *---------------------------------------------------------------------------*/
55
56 /*---------------------------------------------------------------------------*
57 * Includes
58 *---------------------------------------------------------------------------*/
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stddef.h>
63
64 #include <revolution.h>
65 #include <demo.h>
66 #include <demo/DEMOWin.h>
67 #include <revolution/mix.h>
68 #include <revolution/sp.h>
69 #include <revolution/axfx.h>
70 #ifndef HOLLYWOOD_REV
71 #include <dolphin/am.h>
72 #else
73 #include <revolution/mem.h>
74 #endif
75
76 #include "lpfdemo.h"
77
78 /*---------------------------------------------------------------------------*
79 * SP data
80 *---------------------------------------------------------------------------*/
81
82 #define SPT_FILE "/axdemo/filter/lpfdemo.spt"
83 #define SPD_FILE "/axdemo/filter/lpfdemo.spd"
84
85 // use only a single SP sound table
86 static SPSoundTable *sp_table;
87 #ifdef HOLLYWOOD_REV
88 static u8 *sp_data;
89 #endif
90
91 #ifndef HOLLYWOOD_REV
92 /*---------------------------------------------------------------------------*
93 * ARAM initialization
94 *---------------------------------------------------------------------------*/
95
96 #define MAX_ARAM_BLOCKS 3 // Use AR allocator to divide ARAM into 3 blocks
97 #define AUDIO_BLOCK_SIZE_BYTES (8*1024*1024) // Give a whopping 8MB of ARAM to audio!
98 #define XFER_BUFFER_SIZE_BYTES (16*1024) // transfer buffer for ARAM audio manager (AM)
99
100 static u8 xfer_buffer[XFER_BUFFER_SIZE_BYTES] ATTRIBUTE_ALIGN(32);
101
102 static u32 aramZeroBase;
103 static u32 aramUserBase;
104 static u32 aramMemArray[MAX_ARAM_BLOCKS];
105
106 #else
107 /*---------------------------------------------------------------------------*
108 * Exp Heap
109 *---------------------------------------------------------------------------*/
110
111 static MEMHeapHandle hExpHeap;
112
113 /*---------------------------------------------------------------------------*
114 * Zero Buffer
115 *---------------------------------------------------------------------------*/
116
117 #define ZEROBUFFER_BYTES 256
118 #endif
119
120 /*---------------------------------------------------------------------------*
121 * AX data
122 *---------------------------------------------------------------------------*/
123
124 // Constructs for Aux-bus effects
125 static AXFX_REVERBSTD reverbStd;
126 static AXFX_REVERBHI reverbHi;
127 static AXFX_CHORUS chorus;
128 static AXFX_DELAY delay;
129 static AXFX_REVERBHI_DPL2 reverbDPL2;
130
131 // AX profiling structures
132
133 // store up to 8 frames, just to be safe
134 #define NUM_AX_PROFILE_FRAMES 8
135
136 static AXPROFILE ax_profile[NUM_AX_PROFILE_FRAMES];
137
138 /*---------------------------------------------------------------------------*
139 * Voice and sound layer abstractions
140 *---------------------------------------------------------------------------*/
141
142
143 // --------------------------------------------------------------------------
144 // Sound layer abstraction (for cheesy support of multi-channel sounds)
145 // --------------------------------------------------------------------------
146 // For the purposes of this demo, a sound can be composed of multiple samples
147 // mapped into multiple channels. In this way, we can hack out some quick-and-
148 // dirty stereo or multi-channel sound effects.
149 //
150 // Note that samples are referenced by their SoundPipeline entry index.
151 //
152
153 #define MAX_NUM_CHANNELS_PER_SOUND 4 // multi-channel sound support for up to four channels
154 #define NUM_DEMO_SOUNDS 10
155
156 typedef struct
157 {
158 char *name; // handy string for debugging. No sane application would use strings of any sort in a non-debug runtime.
159 u32 index; // abstraction layer index.
160 u32 num_channels; // number of channels associated with this sound.
161
162 u32 sfx [MAX_NUM_CHANNELS_PER_SOUND]; // SP sound effect IDs.
163 u32 pan [MAX_NUM_CHANNELS_PER_SOUND]; // initial pan values for each channel.
164 u32 span [MAX_NUM_CHANNELS_PER_SOUND]; // initial pan values for each channel.
165
166 } DEMO_SOUND;
167
168
169
170 static DEMO_SOUND demo_sound[] =
171 {
172 // Name index NumChans SP sample indices Initial Pan Initial SPan
173 // ------------- ----- -------- --------------------------------------- -------------- -----------------
174 { "GuitarScape", 0, 2, {MSX_GS_LEFT, MSX_GS_RIGHT, 0, 0 }, {0, 127, 0, 0}, {127, 127, 0, 0} },
175 { "Splash", 1, 2, {MSX_SPL_LEFT, MSX_SPL_RIGHT, 0, 0 }, {0, 127, 0, 0}, {127, 127, 0, 0} },
176 { "CarDemo", 2, 2, {MSX_CAR_LEFT, MSX_CAR_RIGHT, 0, 0 }, {0, 127, 0, 0}, {127, 127, 0, 0} },
177 { "Gunshot", 3, 1, {SFX_GUNSHOT, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
178 { "PinkNoise", 4, 1, {SFX_PINK, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
179 { "WhiteNoise", 5, 1, {SFX_WHITE, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
180 { "MachineGun", 6, 1, {SFX_MACHINE_GUN, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
181 { "Explosion", 7, 1, {SFX_EXPLOSION, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
182 { "Footsteps", 8, 1, {SFX_FOOTSTEPS, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} },
183 { "Voice", 9, 1, {SFX_NGC_MAN, 0, 0, 0 }, {63, 0, 0, 0}, {127, 0, 0, 0} }
184
185 };
186
187 // --------------------------------------------------------------------------
188 // Voice layer abstraction
189 // --------------------------------------------------------------------------
190 //
191
192 #define MAX_DEMO_VOICES 64 // Max number of voices we will support in the abstraction layer
193
194 #define mISLOOPED(x) ((x->type)&0x1) // Checks SP entry 'type' to see if the voice is looped or not
195
196 typedef struct _DEMOVOICE
197 {
198 AXVPB *ax_voice;
199 SPSoundEntry *sp_entry;
200 struct _DEMOVOICE *link;
201
202 } DEMO_VOICE;
203
204
205 static DEMO_VOICE demo_voices[MAX_DEMO_VOICES];
206
207
208
209 /*---------------------------------------------------------------------------*
210 * Prototypes
211 *---------------------------------------------------------------------------*/
212
213 // for AX and voice abstraction layer
214 static void ax_demo_callback (void);
215 static void ax_drop_voice_callback (void *p);
216 static void stop_all_voices (void);
217 static void init_effects (void);
218 static void play_sound (u32 sound, u32 loop_flag);
219
220 // for UI menus
221 static void MNU_sound (DEMOWinMenuInfo *menu, u32 item, u32 *result);
222 static void MNU_play (DEMOWinMenuInfo *menu, u32 item, u32 *result);
223 static void MNU_play_looped (DEMOWinMenuInfo *menu, u32 item, u32 *result);
224 static void MNU_stop (DEMOWinMenuInfo *menu, u32 item, u32 *result);
225 static void MNU_auxa (DEMOWinMenuInfo *menu, u32 item, u32 *result);
226 static void MNU_auxa_settings (DEMOWinMenuInfo *menu, u32 item, u32 *result);
227 static void MNU_compressor (DEMOWinMenuInfo *menu, u32 item, u32 *result);
228 static void MNU_filter (DEMOWinMenuInfo *menu, u32 item, u32 *result);
229
230 /*---------------------------------------------------------------------------*
231 * User Interface stuff
232 *---------------------------------------------------------------------------*/
233
234 volatile static u32 soundIndex = 0; // current sound effect to play
235 volatile static u32 auxaIndex = 0; // current effect to apply to AuxA bus
236 volatile static u32 compressFlag = 0; // current compressor state
237 volatile static u32 filterFlag = 1; // current state of filter
238 volatile static u32 old_filterFlag = 1;
239 volatile static u32 filterCutoff = 0; // current LPF cut-off frequency
240
241 DEMOWinInfo *DebugWin;
242 DEMOWinInfo *StatusWin;
243
244 DEMOWinMenuItem MenuItem[] =
245 {
246
247 { "Sound : Guitarscape", DEMOWIN_ITM_NONE, MNU_sound, NULL },
248 { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL },
249 { "Play ", DEMOWIN_ITM_NONE, MNU_play, NULL },
250 { "Play Looped", DEMOWIN_ITM_NONE, MNU_play_looped, NULL },
251 { "Stop", DEMOWIN_ITM_NONE, MNU_stop, NULL },
252 { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL },
253 { "Filter : ON ", DEMOWIN_ITM_NONE, MNU_filter, NULL },
254 { "Compressor: OFF", DEMOWIN_ITM_NONE, MNU_compressor, NULL },
255 { "AuxA : (none)", DEMOWIN_ITM_NONE, MNU_auxa, NULL },
256 { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL },
257 { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL },
258 { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL }
259 };
260
261
262 DEMOWinMenuInfo Menu =
263 {
264 "AX Low-pass filter test", // title
265 NULL, // window handle
266 MenuItem, // list of menu items
267 14, // max num of items to display at a time
268 DEMOWIN_MNU_NONE, // attribute flags
269
270 // user callbacks
271 NULL, // callback for menu open event
272 NULL, // callback for cursor move event
273 NULL, // callback for item select event
274 NULL, // callback for cancel event
275
276 // private members
277 0, 0, 0, 0, 0
278 };
279
280 DEMOWinMenuInfo *MenuPtr;
281
282 /*===========================================================================*
283 * F U N C T I O N D E F I N I T I O N S
284 *===========================================================================*/
285
286
287 /*---------------------------------------------------------------------------*
288 * VOICE ABSTRACTION LAYER STUFF
289 /*---------------------------------------------------------------------------*
290
291
292 /*---------------------------------------------------------------------------*
293 * Name :
294 * Description :
295 * Arguments :
296 * Returns :
297 *---------------------------------------------------------------------------*/
298
stop_all_voices(void)299 static void stop_all_voices(void)
300 {
301
302 u32 i;
303 BOOL old;
304
305 old = OSDisableInterrupts();
306
307 for (i=0; i<MAX_DEMO_VOICES; i++)
308 {
309 if (demo_voices[i].ax_voice)
310 {
311 // hard stop!
312 AXSetVoiceState(demo_voices[i].ax_voice, AX_PB_STATE_STOP);
313
314 }
315
316 }
317
318 OSRestoreInterrupts(old);
319
320
321 } // end stop_voice()
322
323 /*---------------------------------------------------------------------------*
324 * Name :
325 * Description :
326 * Arguments :
327 * Returns :
328 *---------------------------------------------------------------------------*/
329
play_sound(u32 sound,u32 loop_flag)330 static void play_sound(u32 sound, u32 loop_flag)
331 {
332
333 u32 i;
334 AXPBLPF lpf;
335
336 AXVPB *ax_v;
337 DEMO_VOICE *demo_v;
338 DEMO_VOICE *prev_demo_v;
339 DEMO_VOICE *first_demo_v;
340 DEMO_VOICE *curr_demo_v;
341 DEMO_VOICE *tmp_demo_v;
342
343 BOOL old;
344
345
346 ASSERTMSG( (sound < NUM_DEMO_SOUNDS), "ERROR: Sound reference out of range.\n");
347 ASSERTMSG( (demo_sound[sound].num_channels <= MAX_NUM_CHANNELS_PER_SOUND), "ERROR: Channel quantity out of range.\n");
348
349 old = OSDisableInterrupts();
350
351 prev_demo_v = NULL;
352
353 for (i=0; i<demo_sound[sound].num_channels; i++)
354 {
355 ax_v = AXAcquireVoice(15, ax_drop_voice_callback, 0);
356 if (ax_v)
357 {
358 demo_v = &demo_voices[ax_v->index];
359 if (0==i)
360 {
361 first_demo_v = demo_v; // save reference to first voice
362 }
363
364 demo_v->ax_voice = ax_v;
365 demo_v->sp_entry = SPGetSoundEntry(sp_table, demo_sound[sound].sfx[i]);
366 demo_v->link = prev_demo_v;
367 prev_demo_v = demo_v;
368
369 MIXInitChannel(ax_v, 0, 0, 0, -960, -960, (s32)demo_sound[sound].pan[i], (s32)demo_sound[sound].span[i], -120);
370 SPPrepareSound(demo_v->sp_entry, ax_v, (demo_v->sp_entry)->sampleRate);
371
372 // initialize filter!
373 lpf.on = (u16)filterFlag; // filter state is determined by filterFlag
374 lpf.yn1 = 0; // when activated, the history sample must be reset
375 lpf.a0 = __coefs[filterCutoff].a0; // set coefficients to current, user-selected cutoff
376 lpf.b0 = __coefs[filterCutoff].b0;
377 AXSetVoiceLpf(ax_v, &lpf); // Tell AX to update the voice's LPF parameters!
378
379 AXSetVoiceState(ax_v, AX_PB_STATE_RUN); // activate the voice!
380 if (FALSE == loop_flag)
381 {
382 // user has requested one-shot playback of the sound.
383 ax_v->pb.addr.loopFlag = AXPBADDR_LOOP_OFF;
384 ax_v->pb.addr.endAddressHi = (u16)(demo_v->sp_entry->endAddr >> 16);
385 ax_v->pb.addr.endAddressLo = (u16)(demo_v->sp_entry->endAddr & 0xFFFF);
386 }
387
388 }
389 else
390 {
391
392 // AX voice allocation failed. So, we must not FREE any AX voices we may have
393 // acquired for other channels.
394
395 DEMOWinLogPrintf(DebugWin, "ERROR: Voice Allocation failed!\n");
396 curr_demo_v = prev_demo_v;
397 while(NULL == curr_demo_v)
398 {
399 AXFreeVoice(curr_demo_v->ax_voice); // release any AX voices currently allocated for this sound
400 curr_demo_v->ax_voice = NULL; // clear AX voice pointer from DEMO_VOICE
401 curr_demo_v->sp_entry = NULL; // clear SP entry pointer from DEMO_VOICE
402 tmp_demo_v = curr_demo_v; // save current DEMO_VOICE
403 curr_demo_v=curr_demo_v->link; // advance to next DEMO_VOICE
404 tmp_demo_v->link = NULL; // clear link of old DEMO_VOICE
405 }
406 OSRestoreInterrupts(old);
407 return;
408
409 }
410 }
411 first_demo_v->link = demo_v; // first link references last link - it's a circle!
412 OSRestoreInterrupts(old);
413
414 } // end play_sound()
415
416 /*---------------------------------------------------------------------------*
417 * Name :
418 * Description :
419 * Arguments : None.
420 * Returns : None.
421 *---------------------------------------------------------------------------*/
ax_demo_callback(void)422 static void ax_demo_callback(void)
423 {
424 AXPBLPF lpf;
425 u32 i;
426
427
428 // This is the user callback invoked by AX every audio frame.
429 // This callback is responsible for culling any stopped voices
430 // from our DEMO_VOICE abstraction layer, and for updating the
431 // voice parameters of any active voices.
432 //
433 // For the purposes of this demo, we are only updated the
434 // voice parameters associated with the low-pass filter feature
435 // of the DSP.
436 //
437
438 // check for voices which have stopped
439 for (i=0; i<MAX_DEMO_VOICES; i++)
440 {
441 if (demo_voices[i].ax_voice)
442 {
443 // Is the voice stopped?
444 if ( AX_PB_STATE_STOP == ((demo_voices[i].ax_voice)->pb.state))
445 {
446 // If the voice has stopped, clear it from the abstraction layer
447 MIXReleaseChannel(demo_voices[i].ax_voice);
448 AXFreeVoice(demo_voices[i].ax_voice);
449 demo_voices[i].ax_voice = NULL;
450 demo_voices[i].sp_entry = NULL;
451 demo_voices[i].link = NULL;
452 }
453 else
454 {
455 // Otherwise, update any AX voice parameters. For this demo, we only care about
456 // the low-pass filter parameters.
457
458 // has filter ON/OFF state changed?
459 if (old_filterFlag != filterFlag)
460 {
461 if (filterFlag)
462 {
463 // Yes. The filter has been turned on. So initialize the parameters!
464 lpf.on = 1;
465 lpf.yn1 = 0;
466 lpf.a0 = __coefs[filterCutoff].a0;
467 lpf.b0 = __coefs[filterCutoff].b0;
468 AXSetVoiceLpf(demo_voices[i].ax_voice, &lpf);
469 }
470 else
471 {
472 // Yes. The filter has been turned off. So clear the filter "ON" bit.
473 lpf.on = 0;
474 AXSetVoiceLpf(demo_voices[i].ax_voice, &lpf);
475 }
476 }
477 else
478 {
479 // ON/OFF state has not changed.
480 // However, if the filter is on, then the coefs may have changed, so update those.
481 if (filterFlag)
482 {
483 AXSetVoiceLpfCoefs(demo_voices[i].ax_voice, __coefs[filterCutoff].a0, __coefs[filterCutoff].b0);
484 }
485
486 }
487 }
488 }
489 }
490 old_filterFlag = filterFlag;
491
492 } // end ax_demo_callback()
493
494 /*---------------------------------------------------------------------------*
495 * Name : ax_drop_voice_callback()
496 * Description : Invoked by AX when a voice has been forciby dropped.
497 * Must delete references to the voice from our abstraction layer
498 * and release the associated MIXer channel.
499 * Arguments : None.
500 * Returns : None.
501 *---------------------------------------------------------------------------*/
ax_drop_voice_callback(void * p)502 static void ax_drop_voice_callback(void *p)
503 {
504
505 AXVPB *ax_v;
506 DEMO_VOICE *d_v;
507 DEMO_VOICE *tmp_d_v;
508
509 ax_v = (AXVPB *)p; // AX gives us a pointer to the AXVPB of the dropped voice
510 d_v = &demo_voices[ax_v->index]; // Its index corresponds uniquely to a DEMO_VOICE in our abstraction layer.
511
512 MIXReleaseChannel(ax_v); // Release the mixer channel for this AX voice.
513
514 d_v->ax_voice = NULL; // Delete the reference to the AX voice from the DEMO_VOICE.
515 d_v->sp_entry = NULL; // Delete the reference to the SP entry from the DEMO_VOICE.
516
517 // Now, if a multi-channel sound drops a voice, then all other voices (each of which are associated
518 // with a specific channel) must be STOPPED as well. So, traverse the links and STOP every voice.
519 while(d_v->link)
520 {
521 if (d_v->ax_voice)
522 {
523 // The associated AX voice exists. So stop it. Note that we only need to stop
524 // the voice; the user callback (ax_demo_callback) will reset the pointers and
525 // perform a cleanup
526 AXSetVoiceState(d_v->ax_voice, AX_PB_STATE_STOP);
527 }
528 tmp_d_v = d_v; // save current DEMO_VOICE reference
529 d_v = d_v->link; // advance through the links
530 tmp_d_v->link = NULL; // clear saved DEMO_VOICE link.
531 }
532
533 } // end ax_demo_callback()
534
535 /*---------------------------------------------------------------------------*
536 * MENU FUNCTIONS
537 /*---------------------------------------------------------------------------*
538
539
540 /*---------------------------------------------------------------------------*
541 * Name :
542 * Description :
543 * Arguments :
544 * Returns :
545 *---------------------------------------------------------------------------*/
MNU_play(DEMOWinMenuInfo * menu,u32 item,u32 * result)546 static void MNU_play(DEMOWinMenuInfo *menu, u32 item, u32 *result)
547 {
548 #pragma unused(menu, item, result)
549
550 play_sound(soundIndex, FALSE);
551
552 } // end MNU_play()
553
554
555 /*---------------------------------------------------------------------------*
556 * Name :
557 * Description :
558 * Arguments :
559 * Returns :
560 *---------------------------------------------------------------------------*/
MNU_play_looped(DEMOWinMenuInfo * menu,u32 item,u32 * result)561 static void MNU_play_looped(DEMOWinMenuInfo *menu, u32 item, u32 *result)
562 {
563 #pragma unused(menu, item, result)
564
565 play_sound(soundIndex, TRUE);
566
567 } // end MNU_play_looped()
568
569
570 /*---------------------------------------------------------------------------*
571 * Name :
572 * Description :
573 * Arguments :
574 * Returns :
575 *---------------------------------------------------------------------------*/
MNU_stop(DEMOWinMenuInfo * menu,u32 item,u32 * result)576 static void MNU_stop(DEMOWinMenuInfo *menu, u32 item, u32 *result)
577 {
578 #pragma unused(menu, item, result)
579
580 stop_all_voices();
581
582 } // end MNU_stop()
583
584
585 /*---------------------------------------------------------------------------*
586 * Name :
587 * Description :
588 * Arguments :
589 * Returns :
590 *---------------------------------------------------------------------------*/
591
MNU_compressor(DEMOWinMenuInfo * menu,u32 item,u32 * result)592 static void MNU_compressor(DEMOWinMenuInfo *menu, u32 item, u32 *result)
593 {
594 #pragma unused(menu, item, result)
595
596 BOOL old;
597
598 old = OSDisableInterrupts();
599
600 compressFlag ^= 1;
601 AXSetCompressor(compressFlag);
602
603 OSRestoreInterrupts(old);
604
605 if (compressFlag)
606 {
607 menu->items[item].name = "Compressor: ON ";
608 }
609 else
610 {
611 menu->items[item].name = "Compressor: OFF";
612 }
613
614
615 } // end MNU_compressor()
616
617
618 /*---------------------------------------------------------------------------*
619 * Name :
620 * Description :
621 * Arguments :
622 * Returns :
623 *---------------------------------------------------------------------------*/
624
MNU_filter(DEMOWinMenuInfo * menu,u32 item,u32 * result)625 static void MNU_filter(DEMOWinMenuInfo *menu, u32 item, u32 *result)
626 {
627 #pragma unused(menu, item, result)
628
629 BOOL old;
630
631 old = OSDisableInterrupts();
632
633 filterFlag ^= 1;
634
635 OSRestoreInterrupts(old);
636
637 if (filterFlag)
638 {
639 menu->items[item].name = "Filter : ON ";
640 }
641 else
642 {
643 menu->items[item].name = "Filter : OFF";
644 }
645
646
647 } // end MNU_filter()
648
649
650 /*---------------------------------------------------------------------------*
651 * Name :
652 * Description :
653 * Arguments :
654 * Returns :
655 *---------------------------------------------------------------------------*/
656
MNU_auxa(DEMOWinMenuInfo * menu,u32 item,u32 * result)657 static void MNU_auxa(DEMOWinMenuInfo *menu, u32 item, u32 *result)
658 {
659 #pragma unused(menu, item, result)
660
661 auxaIndex++;
662
663 auxaIndex %= 6;
664
665 switch (auxaIndex)
666 {
667 case 0:
668 AXRegisterAuxACallback(NULL, NULL);
669 menu->items[item].name = "AuxA : (none)";
670 break;
671 case 1:
672 AXRegisterAuxACallback((void*)&AXFXReverbStdCallback, (void*)&reverbStd);
673 menu->items[item].name = "AuxA : ReverbStd";
674 break;
675 case 2:
676 AXRegisterAuxACallback((void*)&AXFXReverbHiCallback, (void*)&reverbHi);
677 menu->items[item].name = "AuxA : ReverbHi";
678 break;
679
680 case 3:
681 AXRegisterAuxACallback((void*)&AXFXReverbHiCallbackDpl2, (void*)&reverbDPL2);
682 menu->items[item].name = "AuxA : ReverbDPL2";
683 break;
684
685
686 case 4:
687 AXRegisterAuxACallback((void*)&AXFXChorusCallback, (void*)&chorus);
688 menu->items[item].name = "AuxA : Chorus";
689 break;
690
691 case 5:
692 AXRegisterAuxACallback((void*)&AXFXDelayCallback, (void*)&delay);
693 menu->items[item].name = "AuxA : Delay";
694 break;
695
696 }
697
698
699 } // end MNU_auxa()
700
701
702 /*---------------------------------------------------------------------------*
703 * Name :
704 * Description :
705 * Arguments :
706 * Returns :
707 *---------------------------------------------------------------------------*/
708
MNU_auxa_settings(DEMOWinMenuInfo * menu,u32 item,u32 * result)709 static void MNU_auxa_settings(DEMOWinMenuInfo *menu, u32 item, u32 *result)
710 {
711 #pragma unused(menu, item, result)
712
713 } // end MNU_auxa_settings()
714
715 /*---------------------------------------------------------------------------*
716 * Name :
717 * Description :
718 * Arguments :
719 * Returns :
720 *---------------------------------------------------------------------------*/
721
MNU_sound(DEMOWinMenuInfo * menu,u32 item,u32 * result)722 static void MNU_sound(DEMOWinMenuInfo *menu, u32 item, u32 *result)
723 {
724 #pragma unused(result)
725
726 static char dummy[80];
727
728 soundIndex++;
729 soundIndex %= NUM_DEMO_SOUNDS;
730
731 sprintf(dummy, "Sound : %s", demo_sound[soundIndex].name);
732 menu->items[item].name = dummy;
733
734 } // end MNU_sound
735
736 /*---------------------------------------------------------------------------*
737 * Name : status_win_update()
738 * Description : refresh callback for status window
739 * Arguments :
740 * Returns :
741 *---------------------------------------------------------------------------*/
742
743 #define MAX_TICK_RANGE 100
744
status_win_update(DEMOWinInfo * window)745 static void status_win_update(DEMOWinInfo *window)
746 {
747
748 int substickY;
749
750 static int tick;
751
752 BOOL old;
753
754 u32 i;
755
756 u32 cpuCycles;
757 u32 userCycles;
758 u32 axCycles;
759 u32 voices;
760
761 u32 maxCpuCycles =0;
762 u32 maxUserCycles=0;
763 u32 maxAxCycles =0;
764 u32 maxVoices =0;
765
766 // retrieve stick position as sampled by the DEMOWin windowing system.
767 substickY = (MenuPtr->handle)->pad.pads[0].substickY;
768
769 // If filtering is active, then allow substick (y-axis) to change filter cut-off frequency
770 if (filterFlag)
771 {
772 // if filtering is active, then the Y-axis of the substick controls the
773 // cut-off frequency.
774
775 if (substickY > 63)
776 {
777 tick--;
778 if (tick < 0)
779 {
780 tick = 0;
781 }
782 }
783 else if (substickY < -63)
784 {
785 tick++;
786 if (tick > MAX_TICK_RANGE)
787 {
788 tick = MAX_TICK_RANGE;
789 }
790 }
791
792 filterCutoff = (u32)( ((f32)(tick) / (f32)(MAX_TICK_RANGE)) * (f32)(NUM_FREQ_CUTOFF - 1));
793 }
794 DEMOWinPrintfXY(window, 0, 1, "Cutoff Freq : %s ", __coefs[filterCutoff].text);
795
796 old = OSDisableInterrupts();
797
798 i = AXGetProfile();
799
800 if (i)
801 {
802 // up to 4 audio frames can complete within a 60Hz video frame
803 // so spin thru the accumulated audio frame profiles and find the peak values
804 while (i)
805 {
806 i--;
807
808 cpuCycles = (u32)(ax_profile[i].axFrameEnd - ax_profile[i].axFrameStart);
809 userCycles = (u32)(ax_profile[i].userCallbackEnd - ax_profile[i].userCallbackStart);
810 axCycles = cpuCycles - userCycles;
811 voices = ax_profile[i].axNumVoices;
812
813 // find peak values over the last i audio frames
814 if (cpuCycles > maxCpuCycles) maxCpuCycles = cpuCycles;
815 if (userCycles > maxUserCycles) maxUserCycles = userCycles;
816 if (axCycles > maxAxCycles) maxAxCycles = axCycles;
817 if (voices > maxVoices) maxVoices = voices;
818
819 }
820 OSRestoreInterrupts(old);
821
822 DEMOWinPrintfXY(window, 0, 4, "Total CPU : %5.2f%%", (f32)OSTicksToNanoseconds(maxCpuCycles) / 50000);
823 DEMOWinPrintfXY(window, 0, 6, "User : %5.2f%%", (f32)OSTicksToNanoseconds(maxUserCycles) / 50000);
824 DEMOWinPrintfXY(window, 0, 7, "AX : %5.2f%%", (f32)OSTicksToNanoseconds(maxAxCycles) / 50000);
825 DEMOWinPrintfXY(window, 0, 9, "Voices : %5d", maxVoices);
826
827 }
828
829 OSRestoreInterrupts(old);
830
831 }
832
833 /*---------------------------------------------------------------------------*
834 * Name :
835 * Description :
836 * Arguments :
837 * Returns :
838 *---------------------------------------------------------------------------*/
839
init_effects(void)840 void init_effects(void)
841 {
842
843 reverbStd.time = 3.0f;
844 reverbStd.preDelay = 0.1f;
845 reverbStd.damping = 0.5f;
846 reverbStd.coloration = 0.5f;
847 reverbStd.mix = 0.5f;
848
849 reverbHi.time = 3.0f;
850 reverbHi.preDelay = 0.1f;
851 reverbHi.damping = 0.5f;
852 reverbHi.coloration = 0.5f;
853 reverbHi.crosstalk = 0.3f;
854 reverbHi.mix = 0.5f;
855
856 reverbDPL2.time = 3.0f;
857 reverbDPL2.preDelay = 0.1f;
858 reverbDPL2.damping = 0.5f;
859 reverbDPL2.coloration = 0.5f;
860 reverbDPL2.mix = 0.5f;
861
862 chorus.baseDelay = 15;
863 chorus.variation = 0;
864 chorus.period = 500;
865
866 delay.delay[0] = 500;
867 delay.delay[1] = 500;
868 delay.delay[2] = 500;
869 delay.feedback[0] = 50;
870 delay.feedback[1] = 50;
871 delay.feedback[2] = 50;
872 delay.output[0] = 100;
873 delay.output[1] = 100;
874 delay.output[2] = 100;
875
876 AXFXReverbStdInit(&reverbStd); // initialize reverb
877 AXFXReverbHiInit(&reverbHi); // initialize reverb
878 AXFXReverbHiInitDpl2(&reverbDPL2); // initialize DPL2-compatible reverb
879 AXFXChorusInit(&chorus); // initialize chorus
880 AXFXDelayInit(&delay); // initialize delay
881
882
883 } // end init_effects()
884
885 #ifdef HOLLYWOOD_REV
886 /*---------------------------------------------------------------------------*
887 *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)888 static void* LoadFileIntoRam(char *path)
889 {
890 DVDFileInfo handle;
891 u32 round_length;
892 s32 read_length;
893 void *buffer;
894
895 // Open File
896 if (!DVDOpen(path, &handle))
897 {
898 OSReport("WARNING! Failed to open %s\n", path);
899 return NULL;
900 }
901
902 // Make sure file length is not 0
903 if (DVDGetLength(&handle) == 0)
904 {
905 OSReport("WARNING! File length is 0\n");
906 return NULL;
907 }
908
909 round_length = OSRoundUp32B(DVDGetLength(&handle));
910 buffer = MEMAllocFromExpHeapEx(hExpHeap, round_length, 32);
911
912 // Make sure we got a buffer
913 if (buffer == NULL)
914 {
915 OSReport("WARNING! Unable to allocate buffer\n");
916 return NULL;
917 }
918
919 // Read Files
920 read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
921
922 // Make sure we read the file correctly
923 if (read_length <= 0)
924 {
925 OSReport("WARNING! File lenght is wrong\n");
926 return NULL;
927 }
928
929 return buffer;
930 }
931
932 /*---------------------------------------------------------------------------*
933 *---------------------------------------------------------------------------*/
PrivateAlloc(u32 size)934 static void* PrivateAlloc(u32 size)
935 {
936 return MEMAllocFromExpHeapEx(hExpHeap, size, 32);
937 }
938
939 /*---------------------------------------------------------------------------*
940 *---------------------------------------------------------------------------*/
PrivateFree(void * addr)941 static void PrivateFree(void* addr)
942 {
943 MEMFreeToExpHeap(hExpHeap, addr);
944 }
945 #endif
946
947 /*---------------------------------------------------------------------------*
948 * Name : main()
949 * Description : Hold on to your seatbelts!
950 * Arguments : None.
951 * Returns : None.
952 *---------------------------------------------------------------------------*/
main(void)953 void main(void)
954 {
955 #ifdef HOLLYWOOD_REV
956 void *arenaMem2Lo;
957 void *arenaMem2Hi;
958 u8 *zeroBuffer;
959 #endif
960
961 // initialize system
962 DEMOInit(NULL);
963 DEMOWinInit();
964
965 SISetSamplingRate(5);
966
967 #ifndef HOLLYWOOD_REV
968 // initialize ARAM w/ stack allocator
969 ARInit(aramMemArray, MAX_ARAM_BLOCKS);
970 ARQInit();
971 #else
972 // initialize Exp Heap on MEM2
973 arenaMem2Lo = OSGetMEM2ArenaLo();
974 arenaMem2Hi = OSGetMEM2ArenaHi();
975 hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
976 #endif
977
978 // initialize AI subsystem
979 AIInit(NULL);
980
981 // initialize AX audio system and MIXer application
982 AXInit();
983 MIXInit();
984
985 AXSetMode(AX_MODE_DPL2);
986 MIXSetSoundMode(MIX_SOUND_MODE_DPL2);
987
988 #ifndef HOLLYWOOD_REV
989 // -----------------------------------------------------------
990 // Initialize ARAM audio manager (AM)
991 // -----------------------------------------------------------
992
993 // get a block from the AR ARAM allocator
994 aramUserBase = ARAlloc(AUDIO_BLOCK_SIZE_BYTES);
995
996 // initialize AM with the block
997 AMInit(aramUserBase, AUDIO_BLOCK_SIZE_BYTES);
998
999 // retrieve start of zero buffer, as created by AM
1000 aramZeroBase = AMGetZeroBuffer();
1001 #endif
1002
1003 // -----------------------------------------------------------
1004 // Load SP data!
1005 // -----------------------------------------------------------
1006 #ifndef HOLLYWOOD_REV
1007 // Retrieve sound table
1008 sp_table = (SPSoundTable *)AMLoadFile(SPT_FILE, NULL);
1009
1010 // Load sound effects into ARAM
1011 aramUserBase = AMPushBuffered(SPD_FILE, (void *)xfer_buffer, XFER_BUFFER_SIZE_BYTES);
1012 #else
1013 // Load sound table
1014 sp_table = LoadFileIntoRam(SPT_FILE);
1015
1016 // Load sound effects
1017 sp_data = LoadFileIntoRam(SPD_FILE);
1018 #endif
1019
1020 #ifdef HOLLYWOOD_REV
1021 // -----------------------------------------------------------
1022 // Prepare Zero Buffer
1023 // -----------------------------------------------------------
1024 zeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8);
1025 memset(zeroBuffer, 0, ZEROBUFFER_BYTES);
1026 DCFlushRange(zeroBuffer, ZEROBUFFER_BYTES);
1027 #endif
1028
1029 // -----------------------------------------------------------
1030 // initialize sound table!
1031 // -----------------------------------------------------------
1032 #ifndef HOLLYWOOD_REV
1033 SPInitSoundTable(sp_table, (u8*)aramUserBase, (u8*)aramZeroBase);
1034 #else
1035 SPInitSoundTable(sp_table, sp_data, zeroBuffer);
1036 #endif
1037
1038 // -----------------------------------------------------------
1039 // Initialize demo voice abstraction layer
1040 // -----------------------------------------------------------
1041 AXRegisterCallback(ax_demo_callback);
1042
1043 // -----------------------------------------------------------
1044 // Initialize AUX-bus effects
1045 // -----------------------------------------------------------
1046 #ifdef HOLLYWOOD_REV
1047 AXFXSetHooks((AXFXAlloc)PrivateAlloc, (AXFXFree)PrivateFree);
1048 #endif
1049 init_effects();
1050
1051 // -----------------------------------------------------------
1052 // initialize profiling for AX
1053 // -----------------------------------------------------------
1054 AXInitProfile(ax_profile, NUM_AX_PROFILE_FRAMES);
1055
1056 // -----------------------------------------------------------
1057 // Invoke menu system!
1058 // -----------------------------------------------------------
1059 MenuPtr = DEMOWinCreateMenuWindow(
1060 &Menu,
1061 20,
1062 100
1063 );
1064
1065 DebugWin = DEMOWinCreateWindow(
1066 (u16)(MenuPtr->handle->x2+10),
1067 20,
1068 620,
1069 440,
1070 "Debug",
1071 1024,
1072 NULL
1073 );
1074
1075 StatusWin = DEMOWinCreateWindow(
1076 (u16)(MenuPtr->handle->x1),
1077 (u16)(MenuPtr->handle->y2+10),
1078 (u16)(MenuPtr->handle->x2),
1079 (u16)(MenuPtr->handle->y2+120),
1080 "Status",
1081 0,
1082 status_win_update
1083 );
1084
1085 DEMOWinOpenWindow(DebugWin);
1086 DEMOWinOpenWindow(StatusWin);
1087
1088 DEMOWinLogPrintf(DebugWin, "-------------------------------\n");
1089 DEMOWinLogPrintf(DebugWin, "AX Low-pass filter test\n");
1090 DEMOWinLogPrintf(DebugWin, "-------------------------------\n");
1091
1092 DEMOWinLogPrintf(DebugWin, "\n");
1093
1094 DEMOWinLogPrintf(DebugWin, "Mode is AX_MODE_DPL2.\n\n");
1095 DEMOWinLogPrintf(DebugWin, "- Use sub-stick up/down to change\n");
1096 DEMOWinLogPrintf(DebugWin, " filter cut-off frequency.\n");
1097
1098 while (1)
1099 {
1100
1101 DEMOWinMenu(MenuPtr);
1102
1103 }
1104
1105 } // end main()
1106