1 /*---------------------------------------------------------------------------*
2   Project: Delay (expanded version) Test
3   File:    expdelay.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: expdelay.c,v $
14   Revision 1.1  06/08/2006 08:16:15  aka
15   Imported new demos for new AXFX made by Kawamura-san (EAD).
16 
17   $NoKeywords: $
18  *---------------------------------------------------------------------------*/
19 
20 
21 /*---------------------------------------------------------------------------*
22  * Includes
23  *---------------------------------------------------------------------------*/
24 
25 #include <demo.h>
26 #include <demo/DEMOWin.h>
27 #include <revolution.h>
28 #include <revolution/mix.h>
29 #include <revolution/sp.h>
30 #include <revolution/axfx.h>
31 #include <revolution/axfx_presets.h>
32 #include <revolution/mem.h>
33 #include <string.h>
34 
35 #include "dpl2reverb.h"
36 
37 /*---------------------------------------------------------------------------*
38  * SP data
39  *---------------------------------------------------------------------------*/
40 
41 #define SPT_FILE "/axdemo/dpl2/dpl2reverb.spt"
42 #define SPD_FILE "/axdemo/dpl2/dpl2reverb.spd"
43 
44 // use only a single SP sound table
45 static SPSoundTable *sp_table;
46 static u8           *sp_data;
47 
48 /*---------------------------------------------------------------------------*
49  * Exp Heap
50  *---------------------------------------------------------------------------*/
51 static MEMHeapHandle hExpHeap;
52 
53 /*---------------------------------------------------------------------------*
54  * Zero Buffer
55  *---------------------------------------------------------------------------*/
56 
57 #define ZEROBUFFER_BYTES 256
58 
59 /*---------------------------------------------------------------------------*
60  * AX and Application-layer voice abstraction
61  *---------------------------------------------------------------------------*/
62 
63 // Max number of voices we will support in the abstraction layer
64 #define MAX_DEMO_VOICES 64
65 
66 // Checks SP entry 'type' to see if the voice is looped or not
67 #define mISLOOPED(x) ((x->type)&0x1)
68 
69 int panX;   // pan value for left/right
70 int panY;   // pan value for front/back
71 
72 // Each voice has an associated AX parameter block and an SP entry
73 typedef struct
74 {
75     AXVPB *ax_voice;
76     SPSoundEntry *sp_entry;
77 } DEMO_VOICE;
78 
79 DEMO_VOICE demo_voices[MAX_DEMO_VOICES];
80 
81 // Constructs for Aux-bus effects
82 static AXFX_DELAY_EXP       delay;
83 
84 // AX profiling structures
85 
86 // store up to 8 frames, just to be safe
87 #define NUM_AX_PROFILE_FRAMES 8
88 
89 static AXPROFILE        ax_profile[NUM_AX_PROFILE_FRAMES];
90 
91 /*---------------------------------------------------------------------------*
92  * Prototypes
93  *---------------------------------------------------------------------------*/
94 
95 // for AX and voice abstraction layer
96 static void         ax_demo_callback        (void);
97 static void         ax_drop_voice_callback  (void *p);
98 static void         stop_all_voices         (void);
99 static void         stop_voice              (DEMO_VOICE *v);
100 static DEMO_VOICE  *play_sfx                (u32 sfx);
101 
102 // for UI menus
103 static void         MNU_sound               (DEMOWinMenuInfo *menu, u32 item, u32 *result);
104 static void         MNU_position            (DEMOWinMenuInfo *menu, u32 item, u32 *result);
105 static void         MNU_stop_sfx            (DEMOWinMenuInfo *menu, u32 item, u32 *result);
106 static void         MNU_auxa                (DEMOWinMenuInfo *menu, u32 item, u32 *result);
107 static void         MNU_compressor          (DEMOWinMenuInfo *menu, u32 item, u32 *result);
108 static void         MNU_kill_all            (DEMOWinMenuInfo *menu, u32 item, u32 *result);
109 
110 /*---------------------------------------------------------------------------*
111  * User Interface stuff
112  *---------------------------------------------------------------------------*/
113 
114 static u32 soundIndex    = 0;   // current sound effect to play
115 static u32 positionIndex = 0;   // current panning
116 static u32 auxaIndex     = 0;   // current effect to apply to AuxA bus
117 static u32 compressFlag  = 0;   // current compressor state
118 
119 DEMOWinInfo *DebugWin;
120 DEMOWinInfo *PositionWin;
121 
122 DEMOWinMenuItem MenuItem[] =
123 {
124     { "Sound   : (none)",            DEMOWIN_ITM_NONE,       MNU_sound,        NULL },
125     { "AuxA    : (none)",            DEMOWIN_ITM_NONE,       MNU_auxa,         NULL },
126     { "",                            DEMOWIN_ITM_SEPARATOR,  NULL,             NULL },
127     { "Position: C Stick",           DEMOWIN_ITM_NONE,       MNU_position,     NULL },
128     { "",                            DEMOWIN_ITM_SEPARATOR,  NULL,             NULL },
129     { "Compress: No",                DEMOWIN_ITM_NONE,       MNU_compressor,   NULL },
130     { "",                            DEMOWIN_ITM_SEPARATOR,  NULL,             NULL },
131     { "Kill All Voices",             DEMOWIN_ITM_NONE,       MNU_kill_all,     NULL },
132     { "",                            DEMOWIN_ITM_TERMINATOR, NULL,             NULL }
133 
134 };
135 
136 DEMOWinMenuInfo Menu =
137 {
138     "AX DelayExp Test",         // title
139     NULL,                       // window handle
140     MenuItem,                   // list of menu items
141      9,                         // max num of items to display at a time
142     DEMOWIN_MNU_NONE,           // attribute flags
143 
144     // user callbacks
145     NULL,                       // callback for menu open event
146     NULL,                       // callback for cursor move event
147     NULL,                       // callback for item select event
148     NULL,                       // callback for cancel event
149 
150     // private members
151     0, 0, 0, 0, 0
152 };
153 
154 DEMOWinMenuInfo *MenuPtr;
155 
156 /*===========================================================================*
157  *                   F U N C T I O N    D E F I N I T I O N S
158  *===========================================================================*/
159 
160 
161 /*---------------------------------------------------------------------------*
162  * VOICE ABSTRACTION LAYER STUFF
163 /*---------------------------------------------------------------------------*
164 
165 
166 /*---------------------------------------------------------------------------*
167  * Name        :
168  * Description :
169  * Arguments   :
170  * Returns     :
171  *---------------------------------------------------------------------------*/
172 
173 
stop_voice(DEMO_VOICE * v)174 static void stop_voice(DEMO_VOICE *v)
175 {
176 
177     u32  i;
178     BOOL old;
179 
180         old = OSDisableInterrupts();
181 
182         for (i=0; i<MAX_DEMO_VOICES; i++)
183         {
184             if (v == &demo_voices[i])
185             {
186                 if (demo_voices[i].ax_voice)
187                 {
188                     if (mISLOOPED(demo_voices[i].sp_entry))
189                     {
190                         SPPrepareEnd(demo_voices[i].sp_entry, demo_voices[i].ax_voice);
191                     }
192                     else
193                     {
194                         AXSetVoiceState(demo_voices[i].ax_voice, AX_PB_STATE_STOP);
195                     }
196 
197                     break;
198                 }
199 
200             }
201         }
202 
203         (void)OSRestoreInterrupts(old);
204 
205 
206 } // end stop_voice()
207 
208 /*---------------------------------------------------------------------------*
209  * Name        :
210  * Description :
211  * Arguments   :
212  * Returns     :
213  *---------------------------------------------------------------------------*/
214 
stop_all_voices(void)215 static void stop_all_voices(void)
216 {
217 
218     u32  i;
219     BOOL old;
220 
221 
222 
223         old = OSDisableInterrupts();
224 
225         for (i=0; i<MAX_DEMO_VOICES; i++)
226         {
227             if (demo_voices[i].ax_voice)
228             {
229                 if (mISLOOPED(demo_voices[i].sp_entry))
230                 {
231                     SPPrepareEnd(demo_voices[i].sp_entry, demo_voices[i].ax_voice);
232                 }
233                 else
234                 {
235                     AXSetVoiceState(demo_voices[i].ax_voice, AX_PB_STATE_STOP);
236                 }
237 
238             }
239 
240         }
241 
242         (void)OSRestoreInterrupts(old);
243 
244 
245 } // end stop_voice()
246 
247 /*---------------------------------------------------------------------------*
248  * Name        :
249  * Description :
250  * Arguments   :
251  * Returns     :
252  *---------------------------------------------------------------------------*/
253 
254 
play_sfx(u32 sfx)255 static DEMO_VOICE *play_sfx(u32 sfx)
256 {
257 
258     AXVPB      *ax_v;
259     DEMO_VOICE *v;
260 
261     BOOL        old;
262 
263 
264         old = OSDisableInterrupts();
265 
266         ax_v = AXAcquireVoice(15, ax_drop_voice_callback, 0);
267 
268         if (ax_v)
269         {
270             // use AX voice index to reference a voice in the demo abstraction layer
271             demo_voices[ax_v->index].ax_voice = ax_v;
272 
273             // assign a pointer for convenience
274             v = &demo_voices[ax_v->index];
275 
276             // grab the requested sound from the SP table
277             v->sp_entry = SPGetSoundEntry(sp_table, sfx);
278 
279             SPPrepareSound(v->sp_entry, v->ax_voice, (v->sp_entry)->sampleRate);
280 
281 
282             MIXInitChannel(v->ax_voice, 0, 0, 0, -960, -960, panX, 127-panY, 0);
283             AXSetVoiceState(v->ax_voice, AX_PB_STATE_RUN);
284 
285             (void)OSRestoreInterrupts(old);
286         }
287         else
288         {
289             v = NULL;
290             (void)OSRestoreInterrupts(old);
291             DEMOWinLogPrintf(DebugWin, "ERROR: AX voice allocation failed.\n");
292 
293         }
294 
295         return(v);
296 
297 } // end play_sfx()
298 
299 
300 /*---------------------------------------------------------------------------*
301  * Name        :
302  * Description :
303  * Arguments   : None.
304  * Returns     : None.
305  *---------------------------------------------------------------------------*/
ax_demo_callback(void)306 static void ax_demo_callback(void)
307 {
308 
309     u32 i;
310 
311         // check for voices which have stopped and remove them from the
312         // abstraction layer
313         for (i=0; i<MAX_DEMO_VOICES; i++)
314         {
315             if (demo_voices[i].ax_voice)
316             {
317                 if ( AX_PB_STATE_STOP == ((demo_voices[i].ax_voice)->pb.state))
318                 {
319                     // if the voice has stopped, clear it from the abstraction layer
320                     MIXReleaseChannel(demo_voices[i].ax_voice);
321                     AXFreeVoice(demo_voices[i].ax_voice);
322                     demo_voices[i].ax_voice = NULL;
323                 }
324                 else
325                 {
326                     // otherwise, update the panning
327                     MIXSetPan(demo_voices[i].ax_voice, panX);
328                     MIXSetSPan(demo_voices[i].ax_voice, 127 - panY);
329                     MIXUpdateSettings();
330                 }
331             }
332         }
333 
334 } // end ax_demo_callback()
335 
336 
337 /*---------------------------------------------------------------------------*
338  * Name        : ax_drop_voice_callback()
339  * Description : Invoked by AX when a voice has been forciby dropped.
340  *               Must delete references to the voice from our abstraction layer
341  *               and release the associated MIXer channel.
342  * Arguments   : None.
343  * Returns     : None.
344  *---------------------------------------------------------------------------*/
ax_drop_voice_callback(void * p)345 static void ax_drop_voice_callback(void *p)
346 {
347 
348     AXVPB *v;
349 
350         v = (AXVPB *)p;
351 
352         MIXReleaseChannel(demo_voices[v->index].ax_voice);
353         demo_voices[v->index].ax_voice = NULL;
354         demo_voices[v->index].sp_entry = NULL;
355 
356 } // end ax_demo_callback()
357 
358 
359 
360 /*---------------------------------------------------------------------------*
361  * MENU FUNCTIONS
362 /*---------------------------------------------------------------------------*
363 
364 /*---------------------------------------------------------------------------*
365  * Name        :
366  * Description :
367  * Arguments   :
368  * Returns     :
369  *---------------------------------------------------------------------------*/
370 
MNU_compressor(DEMOWinMenuInfo * menu,u32 item,u32 * result)371 static void MNU_compressor(DEMOWinMenuInfo *menu, u32 item, u32 *result)
372 {
373 #pragma unused(menu, item, result)
374 
375     BOOL old;
376 
377         old = OSDisableInterrupts();
378 
379         compressFlag ^= 1;
380         AXSetCompressor(compressFlag);
381 
382         (void)OSRestoreInterrupts(old);
383 
384         if (compressFlag)
385         {
386             menu->items[item].name = "Compress: YES";
387         }
388         else
389         {
390             menu->items[item].name = "Compress: NO ";
391         }
392 
393 
394 } // end MNU_compressor()
395 
396 /*---------------------------------------------------------------------------*
397  * Name        :
398  * Description :
399  * Arguments   :
400  * Returns     :
401  *---------------------------------------------------------------------------*/
402 
MNU_kill_all(DEMOWinMenuInfo * menu,u32 item,u32 * result)403 static void MNU_kill_all(DEMOWinMenuInfo *menu, u32 item, u32 *result)
404 {
405 #pragma unused(menu, item, result)
406 
407 
408     u32  i;
409     BOOL old;
410 
411         old = OSDisableInterrupts();
412 
413         for (i=0; i<MAX_DEMO_VOICES; i++)
414         {
415             if (demo_voices[i].ax_voice)
416             {
417                 AXSetVoiceState(demo_voices[i].ax_voice, AX_PB_STATE_STOP);
418             }
419         }
420 
421         (void)OSRestoreInterrupts(old);
422 
423 
424 } // end MNU_kill_all()
425 
426 
427 
428 /*---------------------------------------------------------------------------*
429  * Name        :
430  * Description :
431  * Arguments   :
432  * Returns     :
433  *---------------------------------------------------------------------------*/
434 
MNU_auxa(DEMOWinMenuInfo * menu,u32 item,u32 * result)435 static void MNU_auxa(DEMOWinMenuInfo *menu, u32 item, u32 *result)
436 {
437 #pragma unused(menu, item, result)
438 
439     auxaIndex++;
440 
441     auxaIndex %= 5;
442 
443     switch (auxaIndex)
444     {
445         case 0:
446             AXFXDelayExpShutdown(&delay);
447             AXRegisterAuxACallback(NULL, NULL);
448             menu->items[item].name = "Delay : (none)";
449             break;
450         case 1:
451             AXFX_PRESET_DELAY_EXP_TYPE1(&delay);
452             AXFXDelayExpSettings(&delay);
453             AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay);
454             menu->items[item].name = "Delay : Type 1";
455             break;
456 
457 
458         case 2:
459             AXFX_PRESET_DELAY_EXP_TYPE2(&delay);
460             AXFXDelayExpSettings(&delay);
461             AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay);
462             menu->items[item].name = "Delay : Type 2";
463             break;
464 
465         case 3:
466             AXFX_PRESET_DELAY_EXP_FLANGE1(&delay);
467             AXFXDelayExpSettings(&delay);
468             AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay);
469             menu->items[item].name = "Delay : Flange 1";
470             break;
471 
472         case 4:
473             AXFX_PRESET_DELAY_EXP_FLANGE2(&delay);
474             AXFXDelayExpSettings(&delay);
475             AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay);
476             menu->items[item].name = "Delay : Flange 2";
477             break;
478 
479 
480     }
481 
482 
483 } // end MNU_auxa()
484 
485 
486 /*---------------------------------------------------------------------------*
487  * Name        :
488  * Description :
489  * Arguments   :
490  * Returns     :
491  *---------------------------------------------------------------------------*/
492 
MNU_sound(DEMOWinMenuInfo * menu,u32 item,u32 * result)493 static void MNU_sound(DEMOWinMenuInfo *menu, u32 item, u32 *result)
494 {
495 #pragma unused(result)
496 
497         soundIndex++;
498         soundIndex %= 5;
499 
500 
501         stop_all_voices();
502 
503         switch (soundIndex)
504         {
505             case 0: // None
506 
507                 menu->items[item].name = "Sound   : None";
508                 break;
509 
510             case 1:
511 
512                 play_sfx(SFX_TICK);
513                 menu->items[item].name = "Sound   : TICK";
514 
515                 break;
516 
517             case 2:
518 
519                 play_sfx(SFX_EXPLODE);
520                 menu->items[item].name = "Sound   : EXPLOSION";
521 
522                 break;
523 
524             case 3:
525 
526                 play_sfx(SFX_MACHINEGUN);
527                 menu->items[item].name = "Sound   : MACHINEGUN";
528 
529                 break;
530 
531             case 4:
532 
533                 play_sfx(SFX_SYNTH);
534                 menu->items[item].name = "Sound   : SYNTH";
535 
536                 break;
537 
538         } // end switch()
539 
540 } // end MNU_sound
541 
542 
543 
544 
545 
546 /*---------------------------------------------------------------------------*
547  * Name        :
548  * Description :
549  * Arguments   :
550  * Returns     :
551  *---------------------------------------------------------------------------*/
552 
MNU_position(DEMOWinMenuInfo * menu,u32 item,u32 * result)553 static void MNU_position(DEMOWinMenuInfo *menu, u32 item, u32 *result)
554 {
555 #pragma unused(result)
556 
557         positionIndex++;
558         positionIndex %= 7;
559 
560         switch (positionIndex)
561         {
562             case 0:
563 
564                 menu->items[item].name = "Position: C Stick";
565 
566                 break;
567 
568             case 1:
569 
570                 panX = 0;
571                 panY = 0;
572                 menu->items[item].name = "Position: L";
573 
574                 break;
575 
576             case 2:
577 
578                 panX = 63;
579                 panY = 0;
580                 menu->items[item].name = "Position: C";
581 
582                 break;
583 
584             case 3:
585 
586                 panX = 127;
587                 panY = 0;
588                 menu->items[item].name = "Position: R";
589 
590                 break;
591 
592             case 4:
593 
594                 panX = 0;
595                 panY = 127;
596                 menu->items[item].name = "Position: Ls";
597 
598                 break;
599 
600             case 5:
601 
602                 panX = 127;
603                 panY = 127;
604                 menu->items[item].name = "Position: Rs";
605 
606                 break;
607 
608             case 6:
609 
610                 panX = 63;
611                 panY = 127;
612                 menu->items[item].name = "Position: Bs";
613 
614                 break;
615 
616             }
617 
618 } // end MNU_position()
619 
620 
621 /*---------------------------------------------------------------------------*
622  * Name        : position_win_update()
623  * Description : refresh callback for position window
624  * Arguments   :
625  * Returns     :
626  *---------------------------------------------------------------------------*/
627 
position_win_update(DEMOWinInfo * window)628 static void position_win_update(DEMOWinInfo *window)
629 {
630 
631 
632     int substickX;
633     int substickY;
634 
635     BOOL old;
636 
637     u32 i;
638 
639     u32 cpuCycles;
640     u32 userCycles;
641     u32 axCycles;
642     u32 voices;
643 
644     u32 maxCpuCycles =0;
645     u32 maxUserCycles=0;
646     u32 maxAxCycles  =0;
647     u32 maxVoices    =0;
648 
649 
650         substickX = (MenuPtr->handle)->pad.pads[0].substickX;
651         substickY = (MenuPtr->handle)->pad.pads[0].substickY;
652 
653         // Update panning position
654         if (positionIndex == 0)
655         {
656 
657             // if positionIndex is zero, then get panning information from
658             // the C-stick
659             panX = substickX + 63;
660             panY = (substickY - 63) * -1;
661 
662         }
663 
664         DEMOWinPrintfXY(window, 0, 1, "Pan       : %1.2f ", (f32)panX/127);
665         DEMOWinPrintfXY(window, 0, 2, "SPan      : %1.2f ", (f32)panY/127);
666 
667         old = OSDisableInterrupts();
668 
669         i = AXGetProfile();
670 
671         if (i)
672         {
673             // up to 4 audio frames can complete within a 60Hz video frame
674             // so spin thru the accumulated audio frame profiles and find the peak values
675             while (i)
676             {
677                 i--;
678 
679                 cpuCycles   = (u32)(ax_profile[i].axFrameEnd      - ax_profile[i].axFrameStart);
680                 userCycles  = (u32)(ax_profile[i].userCallbackEnd - ax_profile[i].userCallbackStart);
681                 axCycles    = cpuCycles - userCycles;
682                 voices      = ax_profile[i].axNumVoices;
683 
684                 // find peak values over the last i audio frames
685                 if (cpuCycles > maxCpuCycles)     maxCpuCycles    = cpuCycles;
686                 if (userCycles > maxUserCycles)   maxUserCycles   = userCycles;
687                 if (axCycles > maxAxCycles)       maxAxCycles     = axCycles;
688                 if (voices > maxVoices)           maxVoices       = voices;
689 
690             }
691             (void)OSRestoreInterrupts(old);
692 
693             DEMOWinPrintfXY(window, 0, 4, "Total CPU : %5.2f\n", (f32)OSTicksToNanoseconds(maxCpuCycles) / 50000);
694             DEMOWinPrintfXY(window, 0, 6, "User      : %5.2f\n", (f32)OSTicksToNanoseconds(maxUserCycles) / 50000);
695             DEMOWinPrintfXY(window, 0, 7, "AX        : %5.2f\n", (f32)OSTicksToNanoseconds(maxAxCycles) / 50000);
696             DEMOWinPrintfXY(window, 0, 9, "Voices    : %5d",    maxVoices);
697 
698         }
699 
700         (void)OSRestoreInterrupts(old);
701 
702 }
703 
704 /*---------------------------------------------------------------------------*
705  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)706 static void* LoadFileIntoRam(char *path)
707 {
708     DVDFileInfo handle;
709     u32         round_length;
710     s32         read_length;
711     void        *buffer;
712 
713     // Open File
714     if (!DVDOpen(path, &handle))
715     {
716         OSReport("WARNING! Failed to open %s\n", path);
717         return NULL;
718     }
719 
720     // Make sure file length is not 0
721     if (DVDGetLength(&handle) == 0)
722     {
723         OSReport("WARNING! File length is 0\n");
724         return NULL;
725     }
726 
727     round_length = OSRoundUp32B(DVDGetLength(&handle));
728     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
729 
730     // Make sure we got a buffer
731     if (buffer == NULL)
732     {
733         OSReport("WARNING! Unable to allocate buffer\n");
734         return NULL;
735     }
736 
737     // Read Files
738     read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
739 
740     // Make sure we read the file correctly
741     if (read_length <= 0)
742     {
743         OSReport("WARNING! File lenght is wrong\n");
744         return NULL;
745     }
746 
747     return buffer;
748 }
749 
750 /*---------------------------------------------------------------------------*
751  *---------------------------------------------------------------------------*/
PrivateAlloc(u32 size)752 static void* PrivateAlloc(u32 size)
753 {
754     return MEMAllocFromExpHeapEx(hExpHeap, size, 32);
755 }
756 
757 /*---------------------------------------------------------------------------*
758  *---------------------------------------------------------------------------*/
PrivateFree(void * addr)759 static void PrivateFree(void* addr)
760 {
761     MEMFreeToExpHeap(hExpHeap, addr);
762 }
763 
764 /*---------------------------------------------------------------------------*
765  * Name        : main()
766  * Description : Hold on to your seatbelts!
767  * Arguments   : None.
768  * Returns     : None.
769  *---------------------------------------------------------------------------*/
main(void)770 void main(void)
771 {
772     void       *arenaMem2Lo;
773     void       *arenaMem2Hi;
774     u8         *zeroBuffer;
775 
776     // initialize system
777     DEMOInit(NULL);
778     DEMOWinInit();
779 
780     SISetSamplingRate(5);
781 
782     arenaMem2Lo = OSGetMEM2ArenaLo();
783     arenaMem2Hi = OSGetMEM2ArenaHi();
784     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
785 
786     // initialize AI subsystem
787     AIInit(NULL);
788 
789     // initialize AX audio system and MIXer application
790     AXInit();
791     MIXInit();
792 
793     AXSetMode(AX_MODE_SURROUND);
794     MIXSetSoundMode(MIX_SOUND_MODE_SURROUND);
795 
796     // -----------------------------------------------------------
797     // Load SP data!
798     // -----------------------------------------------------------
799 
800     // Load sound table
801     sp_table = LoadFileIntoRam(SPT_FILE);
802 
803     // Load sound effects
804     sp_data  = LoadFileIntoRam(SPD_FILE);
805 
806     // -----------------------------------------------------------
807     // Prepare Zero Buffer
808     // -----------------------------------------------------------
809     zeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8);
810     memset(zeroBuffer, 0, ZEROBUFFER_BYTES);
811     DCFlushRange(zeroBuffer, ZEROBUFFER_BYTES);
812 
813     // -----------------------------------------------------------
814     // initialize sound table!
815     // -----------------------------------------------------------
816     SPInitSoundTable(sp_table, sp_data, zeroBuffer);
817 
818     // -----------------------------------------------------------
819     // Initialize demo voice abstraction layer
820     // -----------------------------------------------------------
821     AXRegisterCallback(ax_demo_callback);
822 
823     // -----------------------------------------------------------
824     // Initialize AUX-bus effects
825     // -----------------------------------------------------------
826     AXFXSetHooks((AXFXAlloc)PrivateAlloc, (AXFXFree)PrivateFree);
827     AXFX_PRESET_DELAY_EXP_TYPE1(&delay);
828     AXFXDelayExpInit(&delay);
829 
830     // -----------------------------------------------------------
831     // initialize profiling for AX
832     // -----------------------------------------------------------
833     AXInitProfile(ax_profile, NUM_AX_PROFILE_FRAMES);
834 
835     // -----------------------------------------------------------
836     // Invoke menu system!
837     // -----------------------------------------------------------
838     MenuPtr     = DEMOWinCreateMenuWindow(
839         &Menu,
840         20,
841         120
842         );
843 
844     DebugWin    = DEMOWinCreateWindow(
845         (u16)(MenuPtr->handle->x2+10),
846         20,
847         620,
848         440,
849         "Debug",
850         1024,
851         NULL
852         );
853 
854     PositionWin = DEMOWinCreateWindow(
855         (u16)(MenuPtr->handle->x1),
856         (u16)(MenuPtr->handle->y2+10),
857         (u16)(MenuPtr->handle->x2),
858         (u16)(MenuPtr->handle->y2+120),
859         "Position",
860         0,
861         position_win_update
862         );
863 
864     DEMOWinOpenWindow(DebugWin);
865     DEMOWinOpenWindow(PositionWin);
866 
867     DEMOWinLogPrintf(DebugWin, "-----------------------------\n");
868     DEMOWinLogPrintf(DebugWin, "Delay (expanded version) Test\n");
869     DEMOWinLogPrintf(DebugWin, "-----------------------------\n");
870 
871     DEMOWinLogPrintf(DebugWin, "\n");
872 
873     DEMOWinLogPrintf(DebugWin, "Mode is AX_MODE_SURROUND.\n");
874 
875     while (1)
876     {
877 
878         DEMOWinMenu(MenuPtr);
879 
880     }
881 
882 } // end main()
883