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