/*---------------------------------------------------------------------------* Project: Delay (expanded version) Test File: expdelay.c Copyright (C)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: expdelay.c,v $ Revision 1.5 2006/11/21 08:21:38 aka Removed the zero buffer. Revision 1.4 2006/10/23 02:05:52 aka Changed from AXInit() to AXInitSpecifyMem(). Changed from MIXInit() to MIXInitSpecifyMem(). Changed from SYNInit() to SYNInitSpecifyMem(). Revision 1.3 2006/10/10 08:30:06 aka Revised AXInit(), MIXInit() and SYNInit(). Revision 1.2 2006/09/18 04:28:22 aka Modified using AX_MAX_VOICES instead of MAX_DEMO_VOICES. Revision 1.1 2006/06/08 08:16:15 aka Imported new demos for new AXFX made by Kawamura-san (EAD). $NoKeywords: $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* * Includes *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include "dpl2reverb.h" /*---------------------------------------------------------------------------* * SP data *---------------------------------------------------------------------------*/ #define SPT_FILE "/axdemo/dpl2/dpl2reverb.spt" #define SPD_FILE "/axdemo/dpl2/dpl2reverb.spd" // use only a single SP sound table static SPSoundTable *sp_table; static u8 *sp_data; /*---------------------------------------------------------------------------* * Exp Heap *---------------------------------------------------------------------------*/ static MEMHeapHandle hExpHeap; /*---------------------------------------------------------------------------* * AX and Application-layer voice abstraction *---------------------------------------------------------------------------*/ // Checks SP entry 'type' to see if the voice is looped or not #define mISLOOPED(x) ((x->type)&0x1) int panX; // pan value for left/right int panY; // pan value for front/back // Each voice has an associated AX parameter block and an SP entry typedef struct { AXVPB *ax_voice; SPSoundEntry *sp_entry; } DEMO_VOICE; DEMO_VOICE demo_voices[AX_MAX_VOICES]; // Constructs for Aux-bus effects static AXFX_DELAY_EXP delay; // AX profiling structures // store up to 8 frames, just to be safe #define NUM_AX_PROFILE_FRAMES 8 static AXPROFILE ax_profile[NUM_AX_PROFILE_FRAMES]; /*---------------------------------------------------------------------------* * Prototypes *---------------------------------------------------------------------------*/ // for AX and voice abstraction layer static void ax_demo_callback (void); static void ax_drop_voice_callback (void *p); static void stop_all_voices (void); static void stop_voice (DEMO_VOICE *v); static DEMO_VOICE *play_sfx (u32 sfx); // for UI menus static void MNU_sound (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_position (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_stop_sfx (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_auxa (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_compressor (DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_kill_all (DEMOWinMenuInfo *menu, u32 item, u32 *result); /*---------------------------------------------------------------------------* * User Interface stuff *---------------------------------------------------------------------------*/ static u32 soundIndex = 0; // current sound effect to play static u32 positionIndex = 0; // current panning static u32 auxaIndex = 0; // current effect to apply to AuxA bus static u32 compressFlag = 0; // current compressor state DEMOWinInfo *DebugWin; DEMOWinInfo *PositionWin; DEMOWinMenuItem MenuItem[] = { { "Sound : (none)", DEMOWIN_ITM_NONE, MNU_sound, NULL }, { "AuxA : (none)", DEMOWIN_ITM_NONE, MNU_auxa, NULL }, { "", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { "Position: C Stick", DEMOWIN_ITM_NONE, MNU_position, NULL }, { "", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { "Compress: No", DEMOWIN_ITM_NONE, MNU_compressor, NULL }, { "", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { "Kill All Voices", DEMOWIN_ITM_NONE, MNU_kill_all, NULL }, { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL } }; DEMOWinMenuInfo Menu = { "AX DelayExp Test", // title NULL, // window handle MenuItem, // list of menu items 9, // max num of items to display at a time DEMOWIN_MNU_NONE, // attribute flags // user callbacks NULL, // callback for menu open event NULL, // 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 *===========================================================================*/ /*---------------------------------------------------------------------------* * VOICE ABSTRACTION LAYER STUFF /*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void stop_voice(DEMO_VOICE *v) { u32 i; BOOL old; old = OSDisableInterrupts(); for (i=0; iindex].ax_voice = ax_v; // assign a pointer for convenience v = &demo_voices[ax_v->index]; // grab the requested sound from the SP table v->sp_entry = SPGetSoundEntry(sp_table, sfx); SPPrepareSound(v->sp_entry, v->ax_voice, (v->sp_entry)->sampleRate); MIXInitChannel(v->ax_voice, 0, 0, 0, -960, -960, panX, 127-panY, 0); AXSetVoiceState(v->ax_voice, AX_PB_STATE_RUN); (void)OSRestoreInterrupts(old); } else { v = NULL; (void)OSRestoreInterrupts(old); DEMOWinLogPrintf(DebugWin, "ERROR: AX voice allocation failed.\n"); } return(v); } // end play_sfx() /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : None. * Returns : None. *---------------------------------------------------------------------------*/ static void ax_demo_callback(void) { u32 i; // check for voices which have stopped and remove them from the // abstraction layer for (i=0; ipb.state)) { // if the voice has stopped, clear it from the abstraction layer MIXReleaseChannel(demo_voices[i].ax_voice); AXFreeVoice(demo_voices[i].ax_voice); demo_voices[i].ax_voice = NULL; } else { // otherwise, update the panning MIXSetPan(demo_voices[i].ax_voice, panX); MIXSetSPan(demo_voices[i].ax_voice, 127 - panY); MIXUpdateSettings(); } } } } // 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) { AXVPB *v; v = (AXVPB *)p; MIXReleaseChannel(demo_voices[v->index].ax_voice); demo_voices[v->index].ax_voice = NULL; demo_voices[v->index].sp_entry = NULL; } // end ax_demo_callback() /*---------------------------------------------------------------------------* * MENU FUNCTIONS /*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_compressor(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu, item, result) BOOL old; old = OSDisableInterrupts(); compressFlag ^= 1; AXSetCompressor(compressFlag); (void)OSRestoreInterrupts(old); if (compressFlag) { menu->items[item].name = "Compress: YES"; } else { menu->items[item].name = "Compress: NO "; } } // end MNU_compressor() /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_kill_all(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu, item, result) u32 i; BOOL old; old = OSDisableInterrupts(); for (i=0; iitems[item].name = "Delay : (none)"; break; case 1: AXFX_PRESET_DELAY_EXP_TYPE1(&delay); AXFXDelayExpSettings(&delay); AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay); menu->items[item].name = "Delay : Type 1"; break; case 2: AXFX_PRESET_DELAY_EXP_TYPE2(&delay); AXFXDelayExpSettings(&delay); AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay); menu->items[item].name = "Delay : Type 2"; break; case 3: AXFX_PRESET_DELAY_EXP_FLANGE1(&delay); AXFXDelayExpSettings(&delay); AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay); menu->items[item].name = "Delay : Flange 1"; break; case 4: AXFX_PRESET_DELAY_EXP_FLANGE2(&delay); AXFXDelayExpSettings(&delay); AXRegisterAuxACallback((void*)&AXFXDelayExpCallback, (void*)&delay); menu->items[item].name = "Delay : Flange 2"; break; } } // end MNU_auxa() /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_sound(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(result) soundIndex++; soundIndex %= 5; stop_all_voices(); switch (soundIndex) { case 0: // None menu->items[item].name = "Sound : None"; break; case 1: play_sfx(SFX_TICK); menu->items[item].name = "Sound : TICK"; break; case 2: play_sfx(SFX_EXPLODE); menu->items[item].name = "Sound : EXPLOSION"; break; case 3: play_sfx(SFX_MACHINEGUN); menu->items[item].name = "Sound : MACHINEGUN"; break; case 4: play_sfx(SFX_SYNTH); menu->items[item].name = "Sound : SYNTH"; break; } // end switch() } // end MNU_sound /*---------------------------------------------------------------------------* * Name : * Description : * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void MNU_position(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(result) positionIndex++; positionIndex %= 7; switch (positionIndex) { case 0: menu->items[item].name = "Position: C Stick"; break; case 1: panX = 0; panY = 0; menu->items[item].name = "Position: L"; break; case 2: panX = 63; panY = 0; menu->items[item].name = "Position: C"; break; case 3: panX = 127; panY = 0; menu->items[item].name = "Position: R"; break; case 4: panX = 0; panY = 127; menu->items[item].name = "Position: Ls"; break; case 5: panX = 127; panY = 127; menu->items[item].name = "Position: Rs"; break; case 6: panX = 63; panY = 127; menu->items[item].name = "Position: Bs"; break; } } // end MNU_position() /*---------------------------------------------------------------------------* * Name : position_win_update() * Description : refresh callback for position window * Arguments : * Returns : *---------------------------------------------------------------------------*/ static void position_win_update(DEMOWinInfo *window) { int substickX; int substickY; BOOL old; u32 i; u32 cpuCycles; u32 userCycles; u32 axCycles; u32 voices; u32 maxCpuCycles =0; u32 maxUserCycles=0; u32 maxAxCycles =0; u32 maxVoices =0; substickX = (MenuPtr->handle)->pad.pads[0].substickX; substickY = (MenuPtr->handle)->pad.pads[0].substickY; // Update panning position if (positionIndex == 0) { // if positionIndex is zero, then get panning information from // the C-stick panX = substickX + 63; panY = (substickY - 63) * -1; } DEMOWinPrintfXY(window, 0, 1, "Pan : %1.2f ", (f32)panX/127); DEMOWinPrintfXY(window, 0, 2, "SPan : %1.2f ", (f32)panY/127); 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; } (void)OSRestoreInterrupts(old); DEMOWinPrintfXY(window, 0, 4, "Total CPU : %5.2f\n", (f32)OSTicksToNanoseconds(maxCpuCycles) / 50000); DEMOWinPrintfXY(window, 0, 6, "User : %5.2f\n", (f32)OSTicksToNanoseconds(maxUserCycles) / 50000); DEMOWinPrintfXY(window, 0, 7, "AX : %5.2f\n", (f32)OSTicksToNanoseconds(maxAxCycles) / 50000); DEMOWinPrintfXY(window, 0, 9, "Voices : %5d", maxVoices); } (void)OSRestoreInterrupts(old); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ 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; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void* PrivateAlloc(u32 size) { return MEMAllocFromExpHeapEx(hExpHeap, size, 32); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void PrivateFree(void* addr) { MEMFreeToExpHeap(hExpHeap, addr); } /*---------------------------------------------------------------------------* * 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(); SISetSamplingRate(5); 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); AXSetMode(AX_MODE_SURROUND); MIXSetSoundMode(MIX_SOUND_MODE_SURROUND); // ----------------------------------------------------------- // 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 // ----------------------------------------------------------- AXRegisterCallback(ax_demo_callback); // ----------------------------------------------------------- // Initialize AUX-bus effects // ----------------------------------------------------------- AXFXSetHooks((AXFXAlloc)PrivateAlloc, (AXFXFree)PrivateFree); AXFX_PRESET_DELAY_EXP_TYPE1(&delay); AXFXDelayExpInit(&delay); // ----------------------------------------------------------- // initialize profiling for AX // ----------------------------------------------------------- AXInitProfile(ax_profile, NUM_AX_PROFILE_FRAMES); // ----------------------------------------------------------- // Invoke menu system! // ----------------------------------------------------------- MenuPtr = DEMOWinCreateMenuWindow( &Menu, 20, 120 ); DebugWin = DEMOWinCreateWindow( (u16)(MenuPtr->handle->x2+10), 20, 620, 440, "Debug", 1024, NULL ); PositionWin = DEMOWinCreateWindow( (u16)(MenuPtr->handle->x1), (u16)(MenuPtr->handle->y2+10), (u16)(MenuPtr->handle->x2), (u16)(MenuPtr->handle->y2+120), "Position", 0, position_win_update ); DEMOWinOpenWindow(DebugWin); DEMOWinOpenWindow(PositionWin); DEMOWinLogPrintf(DebugWin, "-----------------------------\n"); DEMOWinLogPrintf(DebugWin, "Delay (expanded version) Test\n"); DEMOWinLogPrintf(DebugWin, "-----------------------------\n"); DEMOWinLogPrintf(DebugWin, "\n"); DEMOWinLogPrintf(DebugWin, "Mode is AX_MODE_SURROUND.\n"); while (1) { DEMOWinMenu(MenuPtr); } } // end main()