/*---------------------------------------------------------------------------* Project: SP Demo application File: spdemo.c Copyright (C)1998-2006 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: spdemo.c,v $ Revision 1.12 2006/11/21 08:31:04 aka Removed the zero buffer. Revision 1.11 2006/10/23 02:08:18 aka Changed from AXInit() to AXInitSpecifyMem(). Changed from MIXInit() to MIXInitSpecifyMem(). Revision 1.10 2006/10/11 02:24:24 aka Revised AXInit() and MIXInit(). Revision 1.9 2006/09/18 04:30:42 aka Modified using AX_MAX_VOICES instead of MAX_DEMO_VOICES. Revision 1.8 2006/03/06 09:59:03 kawaset Eliminated warnings. Revision 1.7 2006/02/21 01:04:31 mitu modified am.h path. Revision 1.6 2006/02/20 04:13:12 mitu changed include path from dolphin/ to revolution/. Revision 1.5 2006/02/02 08:17:04 aka Modified using MEM functions instead of OSAlloc()/OSFree(). Revision 1.4 2006/02/01 08:30:07 aka Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif. Revision 1.3 2006/01/27 04:55:47 ekwon Corrected "\%" escape sequence warning (replaced with "%%"). Revision 1.2 2005/11/08 03:01:25 aka Changed suiting to Revolution's audio spec. Revision 1.1 2005/11/04 05:02:22 aka Copyright 2001 Nintendo. All rights reserved. 1 9/05/01 8:09p Eugene Demonstration of SP and AM libraries. Uses AX! created $NoKeywords: $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* * Includes *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include "spdemo.h" /*---------------------------------------------------------------------------* * SP data *---------------------------------------------------------------------------*/ #define SPT_FILE "/SPDEMO/spdemo.spt" #define SPD_FILE "/SPDEMO/spdemo.spd" static SPSoundTable *sp_table; static u8 *sp_data; /*---------------------------------------------------------------------------* * Exp Heap *---------------------------------------------------------------------------*/ static MEMHeapHandle hExpHeap; /*---------------------------------------------------------------------------* * AX Profiling *---------------------------------------------------------------------------*/ // store up to 8 frames, just to be safe #define NUM_AX_PROFILE_FRAMES 8 static AXPROFILE ax_profile[NUM_AX_PROFILE_FRAMES]; /*---------------------------------------------------------------------------* * Application-layer voice abstraction *---------------------------------------------------------------------------*/ typedef struct { AXVPB *ax_voice; SPSoundEntry *sp_entry; } DEMO_VOICE; DEMO_VOICE demo_voice[AX_MAX_VOICES]; // Checks SP entry 'type' to see if the voice is looped or not #define mISLOOPED(x) ((x->type)&0x1) /*---------------------------------------------------------------------------* * Prototypes *---------------------------------------------------------------------------*/ static DEMO_VOICE *get_demo_voice (void); static void init_demo_voices (void); static void ax_demo_callback (void); static void ax_drop_voice_callback (void *p); static void play_sfx (u32 sfx); // for UI menus static void MNU_play_click (DEMOWinMenuInfo *menu, u32 item); static void MNU_play_sfx (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_stop_sfx (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_stop_looping (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void ax_profile_update (DEMOWinInfo *window); /*---------------------------------------------------------------------------* * UI Stuff *---------------------------------------------------------------------------*/ DEMOWinInfo *DebugWin; DEMOWinInfo *ProfileWin; DEMOWinMenuItem MenuItem[] = { { "Sound Effect", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { " Noisy Drum", DEMOWIN_ITM_NONE, MNU_play_sfx, NULL }, { " Gunshot", DEMOWIN_ITM_NONE, MNU_play_sfx, NULL }, { " Voice-Man", DEMOWIN_ITM_NONE, MNU_play_sfx, NULL }, { " Voice-Woman", DEMOWIN_ITM_NONE, MNU_play_sfx, NULL }, { " Looping Strings", DEMOWIN_ITM_NONE, MNU_play_sfx, NULL }, { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { "Voice Control", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { " Stop All", DEMOWIN_ITM_NONE, MNU_stop_sfx, NULL }, { " Stop All Looping", DEMOWIN_ITM_NONE, MNU_stop_looping, NULL }, { " ", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL } }; DEMOWinMenuInfo Menu = { "AX Sound Pipeline Demo", // title NULL, // window handle MenuItem, // list of menu items 10, // max num of items to display at a time DEMOWIN_MNU_NONE, // attribute flags // user callbacks NULL, // callback for menu open event MNU_play_click, // callback for cursor move event NULL, // callback for item select event NULL, // callback for cancel event // private members 0, 0, 0, 0, 0 }; DEMOWinMenuInfo *MenuPtr; /*===========================================================================* * F U N C T I O N D E F I N I T I O N S *===========================================================================*/ /*---------------------------------------------------------------------------* * Name : ax_profile_updatek() * Description : refresh callback for AX profile window * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void ax_profile_update(DEMOWinInfo *window) { BOOL old; u32 i; u32 cpuCycles; u32 userCycles; u32 axCycles; u32 voices; u32 maxCpuCycles =0; u32 maxUserCycles=0; u32 maxAxCycles =0; u32 maxVoices =0; old = OSDisableInterrupts(); i = AXGetProfile(); if (i) { // up to 4 audio frames can complete within a 60Hz video frame // so spin thru the accumulated audio frame profiles and find the peak values while (i) { i--; cpuCycles = (u32)(ax_profile[i].axFrameEnd - ax_profile[i].axFrameStart); userCycles = (u32)(ax_profile[i].userCallbackEnd - ax_profile[i].userCallbackStart); axCycles = cpuCycles - userCycles; voices = ax_profile[i].axNumVoices; // find peak values over the last i audio frames if (cpuCycles > maxCpuCycles) maxCpuCycles = cpuCycles; if (userCycles > maxUserCycles) maxUserCycles = userCycles; if (axCycles > maxAxCycles) maxAxCycles = axCycles; if (voices > maxVoices) maxVoices = voices; } OSRestoreInterrupts(old); DEMOWinPrintfXY(window, 0, 2, "Total CPU : %5.2f%%", (f32)OSTicksToNanoseconds(maxCpuCycles) / 50000); DEMOWinPrintfXY(window, 0, 4, "User : %5.2f%%", (f32)OSTicksToNanoseconds(maxUserCycles) / 50000); DEMOWinPrintfXY(window, 0, 5, "AX : %5.2f%%", (f32)OSTicksToNanoseconds(maxAxCycles) / 50000); DEMOWinPrintfXY(window, 0, 7, "Voices : %5d", maxVoices); } OSRestoreInterrupts(old); } // end profile_update() /*---------------------------------------------------------------------------* * Name : MNU_play_click() * Description : Callback for menu system, plays 'click' for cursor movement * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_play_click(DEMOWinMenuInfo *menu, u32 item) { #pragma unused(menu) #pragma unused(item) play_sfx(SFX_MENU); } // end MNU_play_click() /*---------------------------------------------------------------------------* * Name : MNU_play_sfx() * Description : Play sound effect selected from menu. * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_play_sfx(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu) #pragma unused(result) play_sfx(item); } // end MNU_play_sfx() /*---------------------------------------------------------------------------* * Name : MNU_stop_sfx() * Description : Stops all voices. Note that voices are freed by the AX user * callback on the next frame. * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_stop_sfx(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu) #pragma unused(item) #pragma unused(result) u32 i; BOOL old; old = OSDisableInterrupts(); for (i=0; ipb.state)) { MIXReleaseChannel(demo_voice[i].ax_voice); AXFreeVoice(demo_voice[i].ax_voice); demo_voice[i].ax_voice = NULL; } } } } // end ax_demo_callback() /*---------------------------------------------------------------------------* * Name : ax_drop_voice_callback() * Description : Invoked by AX when a voice has been forciby dropped. * Must delete references to the voice from our abstraction layer * and release the associated MIXer channel. * Arguments : None. * Returns : None. *---------------------------------------------------------------------------*/ static void ax_drop_voice_callback(void *p) { u32 i; // search for abstracted voice associated with low-level AX voice. for (i=0; iax_voice = AXAcquireVoice(15, ax_drop_voice_callback, 0); if (v->ax_voice) { v->sp_entry = SPGetSoundEntry(sp_table, sfx); SPPrepareSound(v->sp_entry, v->ax_voice, (v->sp_entry)->sampleRate); MIXInitChannel(v->ax_voice, 0, 0, -960, -960, -960, 64, 127, 0); AXSetVoiceState(v->ax_voice, AX_PB_STATE_RUN); OSRestoreInterrupts(old); } else { OSRestoreInterrupts(old); DEMOWinLogPrintf(DebugWin, "SFX: AX Voice allocation failed.\n"); } } else { OSRestoreInterrupts(old); DEMOWinLogPrintf(DebugWin, "(No free voices in abstraction layer)\n"); } } // end play_sfx() /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void* LoadFileIntoRam(char *path) { DVDFileInfo handle; u32 round_length; s32 read_length; void *buffer; // Open File if (!DVDOpen(path, &handle)) { OSReport("WARNING! Failed to open %s\n", path); return NULL; } // Make sure file length is not 0 if (DVDGetLength(&handle) == 0) { OSReport("WARNING! File length is 0\n"); return NULL; } round_length = OSRoundUp32B(DVDGetLength(&handle)); buffer = MEMAllocFromExpHeapEx(hExpHeap, round_length, 32); // Make sure we got a buffer if (buffer == NULL) { OSReport("WARNING! Unable to allocate buffer\n"); return NULL; } // Read Files read_length = DVDRead(&handle, buffer, (s32)(round_length), 0); // Make sure we read the file correctly if (read_length <= 0) { OSReport("WARNING! File lenght is wrong\n"); return NULL; } return buffer; } /*---------------------------------------------------------------------------* * Name : main() * Description : Hold on to your seatbelts! * Arguments : None. * Returns : None. *---------------------------------------------------------------------------*/ void main(void) { void *arenaMem2Lo; void *arenaMem2Hi; void *axBuffer; void *mixBuffer; // initialize system DEMOInit(NULL); DEMOWinInit(); // initialize Exp Heap on MEM2 arenaMem2Lo = OSGetMEM2ArenaLo(); arenaMem2Hi = OSGetMEM2ArenaHi(); hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo); // initialize AI subsystem AIInit(NULL); // initialize AX audio system and MIXer application axBuffer = MEMAllocFromExpHeapEx(hExpHeap, AXGetMemorySize(AX_MAX_VOICES), 32); mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES)); AXInitSpecifyMem(AX_MAX_VOICES, axBuffer); MIXInitSpecifyMem(mixBuffer); // ----------------------------------------------------------- // Load SP data! // ----------------------------------------------------------- // Load sound table sp_table = LoadFileIntoRam(SPT_FILE); // Load sound effects sp_data = LoadFileIntoRam(SPD_FILE); // ----------------------------------------------------------- // initialize sound table! // ----------------------------------------------------------- SPInitSoundTable(sp_table, sp_data, NULL); // ----------------------------------------------------------- // Initialize demo voice abstraction layer // ----------------------------------------------------------- init_demo_voices(); AXRegisterCallback(ax_demo_callback); // initialize profiling for AX AXInitProfile(ax_profile, NUM_AX_PROFILE_FRAMES); // ----------------------------------------------------------- // Invoke menu system! // ----------------------------------------------------------- MenuPtr = DEMOWinCreateMenuWindow(&Menu, 20, 100); DebugWin = DEMOWinCreateWindow((u16)(MenuPtr->handle->x2+10), 20, 620, 440, "Debug", 1024, NULL); ProfileWin = DEMOWinCreateWindow((u16)(MenuPtr->handle->x1), (u16)(MenuPtr->handle->y2+10), (u16)(MenuPtr->handle->x2), (u16)(MenuPtr->handle->y2+160), "AX Profile", 0, ax_profile_update); DEMOWinOpenWindow(DebugWin); DEMOWinOpenWindow(ProfileWin); DEMOWinLogPrintf(DebugWin, "-------------------------------\n"); DEMOWinLogPrintf(DebugWin, "AX Sound Pipeline Demo!\n"); DEMOWinLogPrintf(DebugWin, "-------------------------------\n"); while (1) { DEMOWinMenu(MenuPtr); } } // end main()