/*---------------------------------------------------------------------------* 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.11 2006/11/21 08:10:02 aka Removed the zero buffer. Revision 1.10 2006/10/23 02:05:52 aka Changed from AXInit() to AXInitSpecifyMem(). Changed from MIXInit() to MIXInitSpecifyMem(). Changed from SYNInit() to SYNInitSpecifyMem(). Revision 1.9 2006/10/10 08:30:06 aka Revised AXInit(), MIXInit() and SYNInit(). Revision 1.8 2006/03/06 09:59:03 kawaset Eliminated warnings. Revision 1.7 2006/02/21 01:04:15 mitu modified am.h path. Revision 1.6 2006/02/20 04:13:07 mitu changed include path from dolphin/ to revolution/. Revision 1.5 2006/02/02 08:22:39 aka Removed unused header files. Revision 1.4 2006/02/02 06:53:15 aka Modified using MEM functions instead of OSAlloc()/OSFree(). Revision 1.3 2006/02/01 06:36:47 aka Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif. Revision 1.2 2006/02/01 04:25:24 aka Added cast from u32 to u8* in relation to changing API around ARAM. Revision 1.1 2005/11/04 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 aufdio 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 #include #include static MEMHeapHandle hExpHeap; static u8 noteA = 0; static u8 noteNumber = 0; static u8 program = 0; static int programChangeButton; SYNSYNTH synth; static u32 hold = 0; /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ 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; } } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ 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; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ void main(void) { PADStatus pads[PAD_MAX_CONTROLLERS]; u8 *wavetable; void *arenaMem2Lo; void *arenaMem2Hi; u8 *samples; void *axBuffer; void *mixBuffer; void *synBuffer; DEMOInit(NULL); arenaMem2Lo = OSGetMEM2ArenaLo(); arenaMem2Hi = OSGetMEM2ArenaHi(); hExpHeap = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo); AIInit(NULL); axBuffer = MEMAllocFromExpHeapEx(hExpHeap, AXGetMemorySize(AX_MAX_VOICES), 32); mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES)); synBuffer = MEMAllocFromExpHeap(hExpHeap, SYNGetMemorySize(AX_MAX_VOICES)); AXInitSpecifyMem(AX_MAX_VOICES, axBuffer); MIXInitSpecifyMem(mixBuffer); SYNInitSpecifyMem(synBuffer); wavetable = LoadFileIntoRam("/axdemo/synth/gm16pcm.wt"); samples = LoadFileIntoRam("/axdemo/synth/gm16pcm.pcm"); // register user callback for audio frames notification AXRegisterCallback(&callbackAudioFrame); // initialize synth SYNInitSynth( &synth, // pointer to synth object wavetable, // pointer to wavetable samples, // pointer to samples NULL, // pointer to zero buffer (no need) 16, // priority for voice allocation 15, // priority for notes 1 // priority for notes that have been released ); 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(); if (wavetable) { MEMFreeToExpHeap(hExpHeap, wavetable); } if (samples) { MEMFreeToExpHeap(hExpHeap, samples); } if (axBuffer) { MEMFreeToExpHeap(hExpHeap, axBuffer); } if (mixBuffer) { MEMFreeToExpHeap(hExpHeap, mixBuffer); } if (synBuffer) { MEMFreeToExpHeap(hExpHeap, synBuffer); } OSHalt("End of program\n"); } // end main()