/*---------------------------------------------------------------------------* Project: Revolution AX + synth Demo File: syndemo.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: syndemo.c,v $ Revision 1.8 2006/03/06 09:59:03 kawaset Eliminated warnings. Revision 1.7 02/21/2006 01:04:15 mitu modified am.h path. Revision 1.6 02/20/2006 04:13:07 mitu changed include path from dolphin/ to revolution/. Revision 1.5 02/02/2006 08:22:39 aka Removed unused header files. Revision 1.4 02/02/2006 06:53:15 aka Modified using MEM functions instead of OSAlloc()/OSFree(). Revision 1.3 02/01/2006 06:36:47 aka Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif. Revision 1.2 02/01/2006 04:25:24 aka Added cast from u32 to u8* in relation to changing API around ARAM. Revision 1.1 11/04/2005 05:01:39 aka Imported from dolphin tree. 9 12/11/01 7:02p Billyjack - keep interrupts disabled during audio frame callback 8 9/05/01 4:33p Eugene Updated AM API. 7 8/29/01 1:52p Billyjack 6 8/17/01 10:59a Billyjack changed AMLoadFile() API 5 8/16/01 12:25p Billyjack - now uses AM - changed code for SYN and SEQ init API change 4 8/03/01 4:32p Billyjack added OSEnableInterrupts() and OSRestoreInterrupts() to AX audio frame callback per change in AX lib. 3 7/06/01 11:50a Billyjack commented DCInvalidateRange for DVD to RAM transfers 2 5/14/01 1:39p Billyjack - reworked for DVDDATA file location and names - uses ARGetBaseAddress where applicable 1 5/09/01 6:09p Billyjack created $NoKeywords: $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* This program shows how to set up and use the AX *---------------------------------------------------------------------------*/ #include #include #include #include #ifndef HOLLYWOOD_REV #include #else #include #include #endif #ifndef HOLLYWOOD_REV #define MAX_ARAM_BLOCKS 2 static u32 aramMemArray[MAX_ARAM_BLOCKS]; #else static MEMHeapHandle hExpHeap; #endif static u8 noteA = 0; static u8 noteNumber = 0; static u8 program = 0; static int programChangeButton; SYNSYNTH synth; static u32 hold = 0; #ifdef HOLLYWOOD_REV #define ZEROBUFFER_BYTES 256 #endif /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void callbackDropVoice(void *p) { AXVPB *pvpb = p; OSReport("PVPB %.8x is being dropped context %d\n", pvpb, pvpb->userContext); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void callbackAudioFrame(void) { // run the synth SYNRunAudioFrame(); // tell the mixer to update settings MIXUpdateSettings(); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void programChange(void) { u8 ch[3]; int old; if (programChangeButton) return; programChangeButton = 1; program++; program %= 128; ch[0] = 0xC0; ch[1] = program; OSReport("program: %d\n", program); old = OSDisableInterrupts(); SYNMidiInput(&synth, ch); OSRestoreInterrupts(old); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void programChange_(void) { programChangeButton = 0; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void startNote(void) { if (noteA == 0) { u8 ch[3]; int old; ch[0] = 0x90; ch[1] = noteNumber; ch[2] = 0x7F; old = OSDisableInterrupts(); SYNMidiInput(&synth, ch); OSRestoreInterrupts(old); OSReport("program: %d keyNum: %d\n", program, noteNumber); noteA = 1; } } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void stopNote(void) { if (noteA) { u8 ch[3]; int old; ch[0] = 0x80; ch[1] = noteNumber; ch[2] = 0x00; old = OSDisableInterrupts(); SYNMidiInput(&synth, ch); noteA = 0; noteNumber++; noteNumber %= 128; if (noteNumber == 127) { program++; program %= 128; ch[0] = 0xC0; ch[1] = program; SYNMidiInput(&synth, ch); } OSRestoreInterrupts(old); } } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void holdPedalDown(void) { u8 ch[3]; int old; if (hold) return; ch[0] = 0xB0; ch[1] = 0x40; ch[2] = 127; old = OSDisableInterrupts(); SYNMidiInput(&synth, ch); OSRestoreInterrupts(old); hold = 1; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ static void holdPedalUp(void) { if (hold) { u8 ch[3]; int old; ch[0] = 0xB0; ch[1] = 0x40; ch[2] = 0; old = OSDisableInterrupts(); SYNMidiInput(&synth, ch); OSRestoreInterrupts(old); hold = 0; } } #ifdef HOLLYWOOD_REV /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ 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; } #endif /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ void main(void) { PADStatus pads[PAD_MAX_CONTROLLERS]; u8 *wavetable; #ifndef HOLLYWOOD_REV u32 aramBase; u32 aramSize; u32 aramAddr; #else void *arenaMem2Lo; void *arenaMem2Hi; u8 *samples; u8 *zeroBuffer; #endif DEMOInit(NULL); #ifndef HOLLYWOOD_REV ARInit(aramMemArray, MAX_ARAM_BLOCKS); ARQInit(); #else arenaMem2Lo = OSGetMEM2ArenaLo(); arenaMem2Hi = OSGetMEM2ArenaHi(); hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo); #endif AIInit(NULL); AXInit(); MIXInit(); SYNInit(); #ifndef HOLLYWOOD_REV // for the purpose of this demo we take all the ARAM HAHA! aramSize = ARGetSize() - ARGetBaseAddress(); aramBase = ARAlloc(aramSize); AMInit(aramBase, aramSize); aramAddr = AMPush("/axdemo/synth/gm16pcm.pcm"); wavetable = AMLoadFile("/axdemo/synth/gm16pcm.wt", NULL); #else wavetable = LoadFileIntoRam("/axdemo/synth/gm16pcm.wt"); samples = LoadFileIntoRam("/axdemo/synth/gm16pcm.pcm"); zeroBuffer = MEMAllocFromExpHeapEx(hExpHeap, ZEROBUFFER_BYTES, 8); memset(zeroBuffer, 0, ZEROBUFFER_BYTES); DCFlushRange(zeroBuffer, ZEROBUFFER_BYTES); #endif // register user callback for audio frames notification AXRegisterCallback(&callbackAudioFrame); // initialize synth #ifndef HOLLYWOOD_REV SYNInitSynth( &synth, // pointer to synth object wavetable, // pointer to wavetable (u8*)aramAddr, // address of samples in ARAM (u8*)AMGetZeroBuffer(), // address of zero buffer in ARAM 16, // priority for voice allocation 15, // priority for notes 1 // priority for notes that have been released ); #else SYNInitSynth( &synth, // pointer to synth object wavetable, // pointer to wavetable samples, // pointer to samples zeroBuffer, // pointer to zero buffer 16, // priority for voice allocation 15, // priority for notes 1 // priority for notes that have been released ); #endif OSReport("Press the A button to increment key number and play note.\n"); OSReport("Press the B button to inclrement program number and change program.\n"); OSReport("Press the left trigger to hold pedal.\n"); OSReport("Press Menu button to exit program\n"); programChangeButton = 0; while (1) { // wait for retrace VIWaitForRetrace(); // check pad PADRead(pads); // see if we should quit if (pads[0].button & PAD_BUTTON_MENU) break; // use A button for key if (pads[0].button & PAD_BUTTON_A) startNote(); else stopNote(); // use B button for program change if (pads[0].button & PAD_BUTTON_B) programChange(); else programChange_(); // use the left trigger for a hold pedal if (pads[0].button & PAD_TRIGGER_L) holdPedalDown(); else holdPedalUp(); } SYNQuit(); MIXQuit(); AXQuit(); #ifndef HOLLYWOOD_REV if (wavetable) { OSFree(wavetable); } #else if (wavetable) { MEMFreeToExpHeap(hExpHeap, wavetable); } if (samples) { MEMFreeToExpHeap(hExpHeap, samples); } if (zeroBuffer) { MEMFreeToExpHeap(hExpHeap, zeroBuffer); } #endif OSHalt("End of program\n"); } // end main()