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