1 /*---------------------------------------------------------------------------*
2   Project:  AX Compressor Demo
3   File:     compressor.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: compressor.c,v $
14   Revision 1.13  2006/11/21 08:21:38  aka
15   Removed the zero buffer.
16 
17   Revision 1.12  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.11  2006/10/10 08:30:06  aka
23   Revised AXInit(), MIXInit() and SYNInit().
24 
25   Revision 1.10  2006/09/18 04:28:22  aka
26   Modified using AX_MAX_VOICES instead of MAX_DEMO_VOICES.
27 
28   Revision 1.9  2006/03/06 09:59:03  kawaset
29   Eliminated warnings.
30 
31   Revision 1.8  2006/02/21 01:04:15  mitu
32   modified am.h path.
33 
34   Revision 1.7  2006/02/20 04:13:07  mitu
35   changed include path from dolphin/ to revolution/.
36 
37   Revision 1.6  2006/02/02 07:30:11  aka
38   Modified using MEM functions instead of OSAlloc()/OSFree().
39 
40   Revision 1.5  2006/02/01 07:47:40  aka
41   Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif.
42 
43   Revision 1.4  2006/01/31 08:07:05  aka
44   Added cast from u32 to u8* in relation to changing API around ARAM.
45 
46   Revision 1.3  2006/01/27 04:54:59  ekwon
47   Corrected "\%" escape sequence warning (replaced with "%%").
48 
49   Revision 1.2  2005/11/08 02:55:02  aka
50   Changed suiting to Revolution's audio spec.
51 
52   Revision 1.1  2005/11/04 05:01:39  aka
53   Imported from dolphin tree.
54 
55     1     1/11/02 3:43p Eugene
56     Demonstration of AX compressor.
57 
58 
59   $NoKeywords: $
60  *---------------------------------------------------------------------------*/
61 
62 /*---------------------------------------------------------------------------*
63  * Includes
64  *---------------------------------------------------------------------------*/
65 
66 #include <string.h>
67 #include <demo.h>
68 #include <demo/DEMOWin.h>
69 #include <demo/DEMOAVX.h>
70 #include <revolution.h>
71 #include <revolution/mix.h>
72 #include <revolution/sp.h>
73 #include <revolution/mem.h>
74 
75 #include "comp_sp.h"
76 
77 /*---------------------------------------------------------------------------*
78  * SP data
79  *---------------------------------------------------------------------------*/
80 
81 #define SPT_FILE "/AXDEMO/compressor/comp_sp.spt"
82 #define SPD_FILE "/AXDEMO/compressor/comp_sp.spd"
83 
84 static SPSoundTable *sp_table;
85 static u8           *sp_data;
86 
87 /*---------------------------------------------------------------------------*
88  * Exp Heap
89  *---------------------------------------------------------------------------*/
90 static MEMHeapHandle hExpHeap;
91 
92 /*---------------------------------------------------------------------------*
93  * AX Profiling
94  *---------------------------------------------------------------------------*/
95 
96 // store up to 8 frames, just to be safe
97 #define NUM_AX_PROFILE_FRAMES 8
98 
99 static AXPROFILE        ax_profile[NUM_AX_PROFILE_FRAMES];
100 
101 /*---------------------------------------------------------------------------*
102  * Application-layer voice abstraction
103  *---------------------------------------------------------------------------*/
104 
105 typedef struct
106 {
107     AXVPB *ax_voice;
108     SPSoundEntry *sp_entry;
109 
110 } DEMO_VOICE;
111 
112 DEMO_VOICE demo_voice[AX_MAX_VOICES];
113 
114 // Checks SP entry 'type' to see if the voice is looped or not
115 #define mISLOOPED(x) ((x->type)&0x1)
116 
117 // flag to track state of compressor!
118 static u32 compressor_mode = AX_COMPRESSOR_ON;
119 
120 
121 /*---------------------------------------------------------------------------*
122  * DEMO-AVX: for snooping output of DSP for clipping
123  *---------------------------------------------------------------------------*/
124 
125 #define AVX_BUFFER_SIZE_WORDS 160
126 
127 s16 __left_channel  [AVX_BUFFER_SIZE_WORDS] ATTRIBUTE_ALIGN(32);
128 s16 __right_channel [AVX_BUFFER_SIZE_WORDS] ATTRIBUTE_ALIGN(32);
129 
130 static u32 clip_tick_left;      // for animating the clip detector
131 static u32 clip_tick_right;     // for animating the clip detector
132 static u32 clip_left;           // for counting number of clips, just for fun
133 static u32 clip_right;          // for counting number of clips, just for fun
134 
135 
136 /*---------------------------------------------------------------------------*
137  * Alarms and such for test processes
138  *---------------------------------------------------------------------------*/
139 
140 #define PING_PERIOD     100   // in milliseconds
141 
142 static OSAlarm PingAlarm;
143 static u32 ping_counter;
144 
145 
146 /*---------------------------------------------------------------------------*
147  * Prototypes
148  *---------------------------------------------------------------------------*/
149 
150 
151 // for user interface
152 static void         MNU_play_click          (DEMOWinMenuInfo *menu, u32 item);
153 static void         MNU_play_hum            (DEMOWinMenuInfo *menu, u32 item, u32 *result);
154 static void         MNU_play_ping           (DEMOWinMenuInfo *menu, u32 item, u32 *result);
155 static void         MNU_play_voice          (DEMOWinMenuInfo *menu, u32 item, u32 *result);
156 static void         MNU_stop_sfx            (DEMOWinMenuInfo *menu, u32 item, u32 *result);
157 static void         MNU_toggle_comp         (DEMOWinMenuInfo *menu, u32 item, u32 *result);
158 static void         MNU_start_ping_test     (DEMOWinMenuInfo *menu, u32 item, u32 *result);
159 static void         MNU_start_voice_test    (DEMOWinMenuInfo *menu, u32 item, u32 *result);
160 
161 
162 // for voice abstraction layer
163 static DEMO_VOICE  *get_demo_voice          (void);
164 static void         init_demo_voices        (void);
165 static void         ax_demo_callback        (void);
166 static void         ax_drop_voice_callback  (void *p);
167 static void         play_sfx                (u32 sfx);
168 static void         stop_all_sfx            (void);
169 static void         ax_profile_update       (DEMOWinInfo *window);
170 
171 // test infrastructure
172 static void         ping_test_refresh       (DEMOWinInfo *handle);
173 static void         ping_alarm_handler      (OSAlarm *alarm, OSContext *context);
174 static void         voice_alarm_handler     (OSAlarm *alarm, OSContext *context);
175 static void         do_test                 (u32 sfx);
176 
177 
178 /*---------------------------------------------------------------------------*
179  * UI Stuff
180  *---------------------------------------------------------------------------*/
181 
182 DEMOWinInfo *DebugWin;      // debug messages
183 DEMOWinInfo *ProfileWin;    // AX state information
184 
185 DEMOWinMenuItem MenuItem[] =
186 {
187     { "Tests",                  DEMOWIN_ITM_SEPARATOR,  NULL,                 NULL },
188     { "  Ping test",            DEMOWIN_ITM_NONE,       MNU_start_ping_test,  NULL },
189     { "  Voice test",           DEMOWIN_ITM_NONE,       MNU_start_voice_test, NULL },
190     { " ",                      DEMOWIN_ITM_SEPARATOR,  NULL,                 NULL },
191     { "Manual AX Controls",     DEMOWIN_ITM_SEPARATOR,  NULL,                 NULL },
192     { "  Toggle Compressor",    DEMOWIN_ITM_NONE,       MNU_toggle_comp,      NULL },
193     { "  Play Looping Hum",     DEMOWIN_ITM_NONE,       MNU_play_hum,         NULL },
194     { "  Play Ping",            DEMOWIN_ITM_NONE,       MNU_play_ping,        NULL },
195     { "  Play Voice",           DEMOWIN_ITM_NONE,       MNU_play_voice,       NULL },
196     { "  Stop All Voices",      DEMOWIN_ITM_NONE,       MNU_stop_sfx,         NULL },
197     { " ",                      DEMOWIN_ITM_SEPARATOR,  NULL,                 NULL },
198     { "",                       DEMOWIN_ITM_TERMINATOR, NULL,                 NULL }
199 };
200 
201 DEMOWinMenuInfo Menu =
202 {
203     "AX Compressor Demo",       // title
204     NULL,                       // window handle
205     MenuItem,                   // list of menu items
206     12,                         // max num of items to display at a time
207     DEMOWIN_MNU_NONE,           // attribute flags
208 
209     // user callbacks
210     NULL,                       // callback for menu open event
211     MNU_play_click,             // callback for cursor move event
212     NULL,                       // callback for item select event
213     NULL,                       // callback for cancel event
214 
215     // private members
216     0, 0, 0, 0, 0
217 };
218 
219 DEMOWinMenuInfo *MenuPtr;
220 
221 /*===========================================================================*
222  *                   F U N C T I O N    D E F I N I T I O N S
223  *===========================================================================*/
224 
225 /*---------------------------------------------------------------------------*
226  * Name        : ax_profile_updatek()
227  * Description : refresh callback for AX profile window
228  * Arguments   :
229  * Returns     :
230  *---------------------------------------------------------------------------*/
231 
ax_profile_update(DEMOWinInfo * window)232 static void ax_profile_update(DEMOWinInfo *window)
233 {
234 
235     BOOL old;
236 
237     u32 i;
238 
239     u32 cpuCycles;
240     u32 userCycles;
241     u32 axCycles;
242     u32 voices;
243 
244     u32 maxCpuCycles =0;
245     u32 maxUserCycles=0;
246     u32 maxAxCycles  =0;
247     u32 maxVoices    =0;
248 
249         old = OSDisableInterrupts();
250 
251         i = AXGetProfile();
252 
253         if (i)
254         {
255             // up to 4 audio frames can complete within a 60Hz video frame
256             // so spin thru the accumulated audio frame profiles and find the peak values
257             while (i)
258             {
259                 i--;
260 
261                 cpuCycles   = (u32)(ax_profile[i].axFrameEnd      - ax_profile[i].axFrameStart);
262                 userCycles  = (u32)(ax_profile[i].userCallbackEnd - ax_profile[i].userCallbackStart);
263                 axCycles    = cpuCycles - userCycles;
264                 voices      = ax_profile[i].axNumVoices;
265 
266                 // find peak values over the last i audio frames
267                 if (cpuCycles > maxCpuCycles)     maxCpuCycles    = cpuCycles;
268                 if (userCycles > maxUserCycles)   maxUserCycles   = userCycles;
269                 if (axCycles > maxAxCycles)       maxAxCycles     = axCycles;
270                 if (voices > maxVoices)           maxVoices       = voices;
271 
272             }
273             OSRestoreInterrupts(old);
274 
275             DEMOWinPrintfXY(window, 0, 2, "Total CPU : %5.2f%%", (f32)OSTicksToNanoseconds(maxCpuCycles) / 50000);
276             DEMOWinPrintfXY(window, 0, 4, "User      : %5.2f%%", (f32)OSTicksToNanoseconds(maxUserCycles) / 50000);
277             DEMOWinPrintfXY(window, 0, 5, "AX        : %5.2f%%", (f32)OSTicksToNanoseconds(maxAxCycles) / 50000);
278             DEMOWinPrintfXY(window, 0, 7, "Voices    : %5d",    maxVoices);
279             DEMOWinPrintfXY(window, 0, 9, "Compressor: %s", (compressor_mode ? "ON " : "OFF"));
280 
281         }
282 
283         OSRestoreInterrupts(old);
284 
285 } // end profile_update()
286 
287 
288 /*---------------------------------------------------------------------------*
289  * Name        : MNU_play_click()
290  * Description : Callback for menu system, plays 'click' for cursor movement
291  * Arguments   :
292  * Returns     :
293  *---------------------------------------------------------------------------*/
294 
MNU_play_click(DEMOWinMenuInfo * menu,u32 item)295 static void MNU_play_click(DEMOWinMenuInfo *menu, u32 item)
296 {
297 
298 #pragma unused(menu)
299 #pragma unused(item)
300 
301     play_sfx(SFX_MENU);
302 
303 
304 } // end MNU_play_click()
305 
306 
307 /*---------------------------------------------------------------------------*
308  * Name        :
309  * Description :
310  * Arguments   :
311  * Returns     :
312  *---------------------------------------------------------------------------*/
313 
MNU_play_hum(DEMOWinMenuInfo * menu,u32 item,u32 * result)314 static void MNU_play_hum(DEMOWinMenuInfo *menu, u32 item, u32 *result)
315 {
316 
317 #pragma unused(menu, item, result)
318 
319     play_sfx(SFX_HUM_LOOPED);
320 
321 } // end MNU_play_sfx()
322 
323 
324 /*---------------------------------------------------------------------------*
325  * Name        :
326  * Description :
327  * Arguments   :
328  * Returns     :
329  *---------------------------------------------------------------------------*/
330 
MNU_play_ping(DEMOWinMenuInfo * menu,u32 item,u32 * result)331 static void MNU_play_ping(DEMOWinMenuInfo *menu, u32 item, u32 *result)
332 {
333 
334 #pragma unused(menu, item, result)
335 
336     play_sfx(SFX_PING);
337 
338 } // end MNU_play_sfx()
339 
340 
341 /*---------------------------------------------------------------------------*
342  * Name        :
343  * Description :
344  * Arguments   :
345  * Returns     :
346  *---------------------------------------------------------------------------*/
347 
MNU_play_voice(DEMOWinMenuInfo * menu,u32 item,u32 * result)348 static void MNU_play_voice(DEMOWinMenuInfo *menu, u32 item, u32 *result)
349 {
350 
351 #pragma unused(menu, item, result)
352 
353     play_sfx(SFX_VOICE_NGC_MAN);
354 
355 } // end MNU_play_sfx()
356 
357 
358 /*---------------------------------------------------------------------------*
359  * Name        : MNU_stop_sfx()
360  * Description : Stops all voices. Note that voices are freed by the AX user
361  *               callback on the next frame.
362  * Arguments   :
363  * Returns     :
364  *---------------------------------------------------------------------------*/
365 
MNU_stop_sfx(DEMOWinMenuInfo * menu,u32 item,u32 * result)366 static void MNU_stop_sfx(DEMOWinMenuInfo *menu, u32 item, u32 *result)
367 {
368 #pragma unused(menu)
369 #pragma unused(item)
370 #pragma unused(result)
371 
372 
373     stop_all_sfx();
374 
375 
376 } // end MNU_stop_sfx()
377 
378 
379 /*---------------------------------------------------------------------------*
380  * Name        : MNU_toggle_comp()
381  * Description : Toggles the AX compressor.
382  * Arguments   :
383  * Returns     :
384  *---------------------------------------------------------------------------*/
385 
MNU_toggle_comp(DEMOWinMenuInfo * menu,u32 item,u32 * result)386 static void MNU_toggle_comp(DEMOWinMenuInfo *menu, u32 item, u32 *result)
387 {
388 #pragma unused(menu)
389 #pragma unused(item)
390 #pragma unused(result)
391 
392     BOOL old;
393 
394         old = OSDisableInterrupts();
395 
396         compressor_mode ^= 1;
397         AXSetCompressor(compressor_mode);
398 
399         OSRestoreInterrupts(old);
400 
401 } // end MNU_stop_sfx()
402 
403 
404 /*---------------------------------------------------------------------------*
405  * Name        :
406  * Description :
407  * Arguments   : None.
408  * Returns     : None.
409  *---------------------------------------------------------------------------*/
410 
init_demo_voices()411 static void init_demo_voices()
412 {
413 
414     u32 i;
415 
416         for (i=0; i<AX_MAX_VOICES; i++)
417         {
418             demo_voice[i].ax_voice = NULL;
419             demo_voice[i].sp_entry = NULL;
420         }
421 
422 } // end init_demo_voices()
423 
424 
425 /*---------------------------------------------------------------------------*
426  * Name        :
427  * Description :
428  * Arguments   : None.
429  * Returns     : None.
430  *---------------------------------------------------------------------------*/
get_demo_voice()431 static DEMO_VOICE *get_demo_voice()
432 {
433 
434     u32 i;
435 
436         i=0;
437         while (i < AX_MAX_VOICES)
438         {
439 
440             if (NULL == demo_voice[i].ax_voice)
441             {
442                 return(&demo_voice[i]);
443             }
444             i++;
445         }
446 
447         return(NULL);
448 
449 }  // end get_demo_voice()
450 
451 
452 /*---------------------------------------------------------------------------*
453  * Name        :
454  * Description :
455  * Arguments   : None.
456  * Returns     : None.
457  *---------------------------------------------------------------------------*/
458 
ax_demo_callback(void)459 static void ax_demo_callback(void)
460 {
461 
462     u32 i;
463 
464         for (i=0; i<AX_MAX_VOICES; i++)
465         {
466             if (demo_voice[i].ax_voice)
467             {
468                 if ( AX_PB_STATE_STOP == ((demo_voice[i].ax_voice)->pb.state))
469                 {
470                     MIXReleaseChannel(demo_voice[i].ax_voice);
471                     AXFreeVoice(demo_voice[i].ax_voice);
472                     demo_voice[i].ax_voice = NULL;
473                 }
474             }
475         }
476 
477 } // end ax_demo_callback()
478 
479 
480 /*---------------------------------------------------------------------------*
481  * Name        : ax_drop_voice_callback()
482  * Description : Invoked by AX when a voice has been forciby dropped.
483  *               Must delete references to the voice from our abstraction layer
484  *               and release the associated MIXer channel.
485  * Arguments   : None.
486  * Returns     : None.
487  *---------------------------------------------------------------------------*/
488 
ax_drop_voice_callback(void * p)489 static void ax_drop_voice_callback(void *p)
490 {
491 
492     u32 i;
493 
494         OSReport("Voice dropped!\n");
495 
496 
497         // search for abstracted voice associated with low-level AX voice.
498         for (i=0; i<AX_MAX_VOICES; i++)
499         {
500             // found it!
501             if  ( (AXVPB *)(p) == demo_voice[i].ax_voice)
502             {
503                 // release mixer channel, delete reference to AX voice (and SP entry, just for neatness)
504                 MIXReleaseChannel(demo_voice[i].ax_voice);
505                 demo_voice[i].ax_voice = NULL;
506                 demo_voice[i].sp_entry = NULL;
507 
508 
509                 break;
510             }
511         }
512 
513         // freak out if the voice doesn't exist in our voice abstraction list
514         ASSERTMSG(i != AX_MAX_VOICES, "AXVoiceCallback: unknown voice reference!\n");
515 
516 } // end ax_demo_callback()
517 
518 
519 /*---------------------------------------------------------------------------*
520  * Name        : stop_all_sfx()
521  * Description :
522  * Arguments   : None.
523  * Returns     : None.
524  *---------------------------------------------------------------------------*/
525 
stop_all_sfx(void)526 static void stop_all_sfx(void)
527 {
528 
529     u32    i;
530     BOOL old;
531 
532         old = OSDisableInterrupts();
533 
534         for (i=0; i<AX_MAX_VOICES; i++)
535         {
536             if (demo_voice[i].ax_voice)
537             {
538                 AXSetVoiceState(demo_voice[i].ax_voice, AX_PB_STATE_STOP);
539             }
540         }
541 
542         OSRestoreInterrupts(old);
543 
544 
545 } // end stop_all_sfx()
546 
547 
548 /*---------------------------------------------------------------------------*
549  * Name        : play_sfx()
550  * Description :
551  * Arguments   : None.
552  * Returns     : None.
553  *---------------------------------------------------------------------------*/
554 
play_sfx(u32 sfx)555 static void play_sfx(u32 sfx)
556 {
557 
558     DEMO_VOICE *v;
559     BOOL old;
560 
561 
562         old = OSDisableInterrupts();
563 
564         v = get_demo_voice();
565         if (v)
566         {
567 
568             v->ax_voice = AXAcquireVoice(15, ax_drop_voice_callback, 0);
569             if (v->ax_voice)
570             {
571 
572                 v->sp_entry = SPGetSoundEntry(sp_table, sfx);
573 
574                 SPPrepareSound(v->sp_entry, v->ax_voice, (v->sp_entry)->sampleRate);
575 
576                 MIXInitChannel(v->ax_voice, 0, 0, -960, -960, -960, 64, 127, 0);
577                 AXSetVoiceState(v->ax_voice, AX_PB_STATE_RUN);
578 
579                 OSRestoreInterrupts(old);
580 
581             }
582             else
583             {
584                 OSRestoreInterrupts(old);
585                 DEMOWinLogPrintf(DebugWin, "SFX: AX Voice allocation failed.\n");
586             }
587 
588         }
589         else
590         {
591             OSRestoreInterrupts(old);
592             DEMOWinLogPrintf(DebugWin, "(No free voices in abstraction layer)\n");
593         }
594 
595 } // end play_sfx()
596 
597 
598 /*---------------------------------------------------------------------------*
599  * Name        : ping_alarm_handler()
600  * Description :
601  * Arguments   : None.
602  * Returns     : None.
603  *---------------------------------------------------------------------------*/
604 
ping_alarm_handler(OSAlarm * alarm,OSContext * context)605 static void ping_alarm_handler(OSAlarm *alarm, OSContext *context)
606 {
607 #pragma unused(alarm, context)
608 
609 
610     // last four counts, play a ping
611     if (ping_counter > 7 )
612     {
613         play_sfx(SFX_PING);
614     }
615 
616     // for the first eight counts, stay silent
617     ping_counter = (ping_counter + 1) % 12;
618 
619 
620 }
621 
622 
623 /*---------------------------------------------------------------------------*
624  * Name        : voice_alarm_handler()
625  * Description :
626  * Arguments   : None.
627  * Returns     : None.
628  *---------------------------------------------------------------------------*/
629 
voice_alarm_handler(OSAlarm * alarm,OSContext * context)630 static void voice_alarm_handler(OSAlarm *alarm, OSContext *context)
631 {
632 #pragma unused(alarm, context)
633 
634 
635     // play the voice for just one count
636     if (ping_counter == 19 )
637     {
638         play_sfx(SFX_VOICE_NGC_MAN);
639     }
640 
641     // for the remaining counts, stay silent
642     ping_counter = (ping_counter + 1) % 25;
643 
644 }
645 
646 
647 /*---------------------------------------------------------------------------*
648  * Name        : ping_test_refresh()
649  * Description :
650  * Arguments   : None.
651  * Returns     : None.
652  *---------------------------------------------------------------------------*/
653 
ping_test_refresh(DEMOWinInfo * handle)654 static void ping_test_refresh(DEMOWinInfo *handle)
655 {
656 
657     DEMOWinPrintfXY(handle, 0, 3, "Compressor: %s", (compressor_mode ? "ON " : "OFF"));
658     DEMOWinPrintfXY(handle, 0, 5, "Clip Left : %s", ((clip_tick_left > 0) && (clip_tick_left < 19))   ? "CLIP" : "    ");
659     DEMOWinPrintfXY(handle, 0, 6, "Clip Right: %s", ((clip_tick_right > 0) && (clip_tick_right < 19)) ? "CLIP" : "    ");
660 
661 
662 } // end of ping_test_refresh()
663 
664 
665 /*---------------------------------------------------------------------------*
666  * Name        : MNU_start_ping_test()
667  * Description :
668  * Arguments   : None.
669  * Returns     : None.
670  *---------------------------------------------------------------------------*/
671 
MNU_start_ping_test(DEMOWinMenuInfo * menu,u32 item,u32 * result)672 static void MNU_start_ping_test(DEMOWinMenuInfo *menu, u32 item, u32 *result)
673 {
674 #pragma unused(menu, item, result)
675 
676     do_test(SFX_PING);
677 
678 }
679 
680 
681 /*---------------------------------------------------------------------------*
682  * Name        : NNU_start_voice_test()
683  * Description :
684  * Arguments   : None.
685  * Returns     : None.
686  *---------------------------------------------------------------------------*/
687 
MNU_start_voice_test(DEMOWinMenuInfo * menu,u32 item,u32 * result)688 static void MNU_start_voice_test(DEMOWinMenuInfo *menu, u32 item, u32 *result)
689 {
690 #pragma unused(menu, item, result)
691 
692     do_test(SFX_VOICE_NGC_MAN);
693 }
694 
695 
696 /*---------------------------------------------------------------------------*
697  * Name        : do_test()
698  * Description :
699  * Arguments   : sound effect with which to induce clipping.
700  * Returns     : None.
701  *---------------------------------------------------------------------------*/
702 
do_test(u32 sfx)703 static void do_test(u32 sfx)
704 {
705 
706     DEMOWinInfo   *handle;
707     DEMOWinPadInfo pad;
708 
709     BOOL old;
710 
711     OSTime now;
712 
713     u32 num_samples = 0;
714     u32 start_index = 0;
715     u32 end_index   = 0;
716 
717     u32 index       = 0;
718 
719     u32 i;
720 
721 
722         // stop all voices, just in case
723         stop_all_sfx();
724 
725         handle = DEMOWinCreateWindow(150, 90, 540, 180, "Compressor Test", 0, ping_test_refresh);
726 
727         DEMOWinOpenWindow(handle);
728 
729         DEMOWinPrintfXY(handle, 0, 0, "A: Toggle Compressor");
730         DEMOWinPrintfXY(handle, 0, 1, "B: Exit");
731 
732         // debounce
733         DEMOWinPadInit(&pad);
734 
735         DEMOBeforeRender();
736         DEMOWinRefresh();
737         DEMODoneRender();
738 
739         DEMOWinPadRead(&pad);
740 
741         DEMOBeforeRender();
742         DEMOWinRefresh();
743         DEMODoneRender();
744 
745         DEMOWinPadRead(&pad);
746 
747         // start low-freq hum
748         play_sfx(SFX_HUM_LOOPED);
749 
750 
751         // start periodic ping
752         ping_counter = 0;
753         OSCreateAlarm(&PingAlarm);
754         now = OSGetTime();
755 
756         if (SFX_PING == sfx)
757         {
758             // set alarm using "ping" handler
759             OSSetPeriodicAlarm(&PingAlarm, now, OSMillisecondsToTicks(PING_PERIOD), ping_alarm_handler);
760         }
761         else if (SFX_VOICE_NGC_MAN)
762         {
763             // set alarm using "voice" handler
764             OSSetPeriodicAlarm(&PingAlarm, now, OSMillisecondsToTicks(PING_PERIOD), voice_alarm_handler);
765         }
766         else
767         {
768 
769             OSHalt("Unknown sound effect reference for test!\n");
770         }
771 
772 
773         // reset clip-o-meter
774         clip_left       = 0;
775         clip_right      = 0;
776         clip_tick_left  = 0;
777         clip_tick_right = 0;
778 
779 
780         while (1)
781         {
782 
783             if (pad.changed_button[0] & PAD_BUTTON_B)
784             {
785                 break;
786             }
787 
788             if (pad.changed_button[0] & PAD_BUTTON_A)
789             {
790 
791                 old = OSDisableInterrupts();
792 
793                 compressor_mode ^= 1;
794                 AXSetCompressor(compressor_mode);
795 
796                 OSRestoreInterrupts(old);
797             }
798 
799 
800 
801             // Clip detection
802             num_samples = DEMOAVXRefreshBuffer(&start_index, &end_index);
803 
804             index = start_index;
805             for (i=0; i<num_samples; i++)
806             {
807 
808                 if ((__left_channel[index] > 32766) || (__right_channel[index] < -32766))
809                 {
810                     clip_left++;            // count number of clips, just for fun
811                     clip_tick_left = 20;
812                 }
813 
814                 if ((__right_channel[index] > 32766) || (__right_channel[index] < -32766))
815                 {
816                     clip_right++;           // count number of clips, just for fun
817                     clip_tick_right = 20;
818                 }
819 
820                 index = (index + 1) % AVX_BUFFER_SIZE_WORDS;
821             }
822 
823             DEMOBeforeRender();
824             DEMOWinRefresh();
825             DEMODoneRender();
826 
827             DEMOWinPadRead(&pad);
828 
829             // decrement clip-o-meter animation ticks
830             clip_tick_right = (clip_tick_right ? (clip_tick_right - 1) : 0);
831             clip_tick_left  = (clip_tick_left  ? (clip_tick_left  - 1) : 0);
832 
833         }
834 
835         stop_all_sfx();
836 
837         OSRestoreInterrupts(old);
838         OSCancelAlarm(&PingAlarm);
839 
840         DEMOWinCloseWindow(handle);
841         DEMOWinDestroyWindow(handle);
842 
843         DEMOWinLogPrintf(DebugWin, "Left : clipped %d times.\n", clip_left);
844         DEMOWinLogPrintf(DebugWin, "Right: clipped %d times.\n", clip_right);
845         DEMOWinLogPrintf(DebugWin, "\n");
846 
847 
848 } // end do_test()
849 
850 
851 /*---------------------------------------------------------------------------*
852  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)853 static void* LoadFileIntoRam(char *path)
854 {
855     DVDFileInfo handle;
856     u32         round_length;
857     s32         read_length;
858     void        *buffer;
859 
860     // Open File
861     if (!DVDOpen(path, &handle))
862     {
863         OSReport("WARNING! Failed to open %s\n", path);
864         return NULL;
865     }
866 
867     // Make sure file length is not 0
868     if (DVDGetLength(&handle) == 0)
869     {
870         OSReport("WARNING! File length is 0\n");
871         return NULL;
872     }
873 
874     round_length = OSRoundUp32B(DVDGetLength(&handle));
875     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
876 
877     // Make sure we got a buffer
878     if (buffer == NULL)
879     {
880         OSReport("WARNING! Unable to allocate buffer\n");
881         return NULL;
882     }
883 
884     // Read Files
885     read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
886 
887     // Make sure we read the file correctly
888     if (read_length <= 0)
889     {
890         OSReport("WARNING! File lenght is wrong\n");
891         return NULL;
892     }
893 
894     return buffer;
895 }
896 
897 
898 /*---------------------------------------------------------------------------*
899  * Name        : main()
900  * Description : Hold on to your seatbelts!
901  * Arguments   : None.
902  * Returns     : None.
903  *---------------------------------------------------------------------------*/
904 
main(void)905 void main(void)
906 {
907 
908     void       *arenaMem2Lo;
909     void       *arenaMem2Hi;
910     void       *axBuffer;
911     void       *mixBuffer;
912 
913     // initialize system
914     DEMOInit(NULL);
915     DEMOWinInit();
916 
917     arenaMem2Lo = OSGetMEM2ArenaLo();
918     arenaMem2Hi = OSGetMEM2ArenaHi();
919     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
920 
921     // initialize AI subsystem
922     AIInit(NULL);
923 
924     // initialize AX audio system and MIXer application
925     axBuffer  = MEMAllocFromExpHeapEx(hExpHeap, AXGetMemorySize(AX_MAX_VOICES), 32);
926     mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES));
927 
928     AXInitSpecifyMem(AX_MAX_VOICES, axBuffer);
929     MIXInitSpecifyMem(mixBuffer);
930 
931     // turn on compressor!
932     AXSetCompressor(compressor_mode);
933 
934     // -----------------------------------------------------------
935     // Load SP data!
936     // -----------------------------------------------------------
937 
938     // Load sound table
939     sp_table = LoadFileIntoRam(SPT_FILE);
940 
941     // Load sound effects
942     sp_data  = LoadFileIntoRam(SPD_FILE);
943 
944     // -----------------------------------------------------------
945     // initialize sound table!
946     // -----------------------------------------------------------
947     SPInitSoundTable(sp_table, sp_data, NULL);
948 
949     // -----------------------------------------------------------
950     // Initialize demo voice abstraction layer
951     // -----------------------------------------------------------
952     init_demo_voices();
953     AXRegisterCallback(ax_demo_callback);
954 
955     // initialize profiling for AX
956     AXInitProfile(ax_profile, NUM_AX_PROFILE_FRAMES);
957 
958     // -----------------------------------------------------------
959     // Initialize DEMO-AVX functions.
960     // This allows us to snoop a copy of the contents of the DSP
961     // DSP output before it is consumed by the DAC. We want this
962     // data so we can search for clipping.
963     // -----------------------------------------------------------
964     DEMOAVXInit(__left_channel, __right_channel, AVX_BUFFER_SIZE_WORDS);
965 
966     // -----------------------------------------------------------
967     // Invoke menu system!
968     // -----------------------------------------------------------
969 
970     MenuPtr    = DEMOWinCreateMenuWindow(&Menu, 20, 100);
971     DebugWin   = DEMOWinCreateWindow((u16)(MenuPtr->handle->x2+10), 20, 620, 440, "Debug", 1024, NULL);
972     ProfileWin = DEMOWinCreateWindow((u16)(MenuPtr->handle->x1), (u16)(MenuPtr->handle->y2+10), (u16)(MenuPtr->handle->x2), (u16)(MenuPtr->handle->y2+160), "AX Status", 0, ax_profile_update);
973 
974     DEMOWinOpenWindow(DebugWin);
975     DEMOWinOpenWindow(ProfileWin);
976 
977     DEMOWinLogPrintf(DebugWin, "-------------------------------\n");
978     DEMOWinLogPrintf(DebugWin, "AX Compressor Demo\n");
979     DEMOWinLogPrintf(DebugWin, "-------------------------------\n");
980 
981     while (1)
982     {
983 
984         DEMOWinMenu(MenuPtr);
985 
986     }
987 
988 } // end main()
989