/* Copyright (C) 1994-1995 Apogee Software, Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*********** *********************************************************** file: GUSMIDI.C author: James R. Dose date: March 23, 1994 General MIDI playback functions for the Gravis Ultrasound (c) Copyright 1994 James R. Dose. All Rights Reserved. **********************************************************************/ // Module MUST be compiled with structure allignment set to a maximum // of 1 byte ( zp1 ). #include #include #include #include #include #include #include #include "usrhooks.h" #include "interrup.h" #include "newgf1.h" #include "gusmidi.h" #define TRUE ( 1 == 1 ) #define FALSE ( !TRUE ) // size of DMA buffer for patch loading #define DMABUFFSIZE 2048U #define MAX_MEM_CONFIG 3 // size of patch array (128 perc, 128 melodic) #define NUM_PATCHES 256 // size of largest patch name #define BIGGEST_NAME 9 #define UNUSED_PATCH -1 static struct patch Patch[ NUM_PATCHES ]; static unsigned char *PatchWaves[ NUM_PATCHES ]; static int PatchMap[ NUM_PATCHES ][ MAX_MEM_CONFIG + 1 ]; static char ProgramName[ NUM_PATCHES ][ BIGGEST_NAME ]; static char PatchLoaded[ NUM_PATCHES ]; static char ConfigFileName[] = "ULTRAMID.INI"; static char ConfigDirectory[ 80 ] = { '\0' }; // The name of the configuration directory static char InstrumentDirectory[ 80 ]; extern struct gf1_dma_buff GUS_HoldBuffer; extern unsigned long GUS_TotalMemory; extern int GUS_MemConfig; static int GUSMIDI_Volume = 255; extern int GUS_AuxError; extern int GUS_ErrorCode; int GUSMIDI_Installed = FALSE; #define GUS_SetErrorCode( status ) \ GUS_ErrorCode = ( status ); /*--------------------------------------------------------------------- Function: GUS_GetPatchMap Reads the patch map from disk. ---------------------------------------------------------------------*/ int GUS_GetPatchMap ( char *name ) { char text[ 80 ]; char *ud; int index; int ignore; FILE *fp; for( index = 0; index < NUM_PATCHES; index++ ) { PatchMap[ index ][ 0 ] = UNUSED_PATCH; PatchMap[ index ][ 1 ] = UNUSED_PATCH; PatchMap[ index ][ 2 ] = UNUSED_PATCH; PatchMap[ index ][ 3 ] = UNUSED_PATCH; ProgramName[ index ][ 0 ] = 0; } ud = getenv( "ULTRADIR" ); if ( ud == NULL ) { GUS_SetErrorCode( GUS_ULTRADIRNotSet ); return( GUS_Error ); } strcpy( InstrumentDirectory, ud ); strcat( InstrumentDirectory, "\\midi\\" ); strcpy( ConfigDirectory, ud ); strcat( ConfigDirectory, "\\midi\\" ); strcpy( text, name ); fp = fopen( text, "r" ); if ( fp == NULL ) { strcpy( text, InstrumentDirectory ); strcat( text, name ); fp = fopen( text, "r" ); if ( fp == NULL ) { GUS_SetErrorCode( GUS_MissingConfig ); return( GUS_Error ); } } while( 1 ) { if ( fgets( text, 80, fp ) == NULL ) { break; } if ( text[ 0 ] == '#' ) { continue; } if ( sscanf( text, "%d", &index ) != 1 ) { continue; } sscanf( text, "%d, %d, %d, %d, %d, %s\n", &ignore, &PatchMap[ index ][ 0 ], &PatchMap[ index ][ 1 ], &PatchMap[ index ][ 2 ], &PatchMap[ index ][ 3 ], ProgramName[ index ] ); } fclose( fp ); return( GUS_Ok ); } /*--------------------------------------------------------------------- Function: GUSMIDI_UnloadPatch Unloads a patch from the GUS's memory. ---------------------------------------------------------------------*/ int GUSMIDI_UnloadPatch ( int prognum ) { int prog; unsigned flags; prog = PatchMap[ prognum ][ GUS_MemConfig ]; if ( PatchLoaded[ prog ] ) { flags = DisableInterrupts(); gf1_unload_patch( &Patch[ prog ] ); if ( PatchWaves[ prog ] != NULL ) { USRHOOKS_FreeMem( PatchWaves[ prog ] ); PatchWaves[ prog ] = NULL; } // just in case sequence is still playing Patch[ prog ].nlayers = 0; PatchLoaded[ prog ] = FALSE; RestoreInterrupts( flags ); } return( GUS_Ok ); } /*--------------------------------------------------------------------- Function: GUSMIDI_LoadPatch Loads a patch into the GUS's memory. ---------------------------------------------------------------------*/ int GUSMIDI_LoadPatch ( int prognum ) { int prog; char text[ 80 ]; int ret; unsigned char *wave_buff; struct patchinfo patchi; int status; prog = PatchMap[ prognum ][ GUS_MemConfig ]; if ( ( PatchLoaded[ prog ] ) || ( prog == UNUSED_PATCH ) ) { return( GUS_Ok ); } if ( !ProgramName[ prog ][ 0 ] ) { return( GUS_Ok ); } strcpy( text, InstrumentDirectory ); strcat( text, ProgramName[ prog ] ); strcat( text, ".pat" ); ret = gf1_get_patch_info( text, &patchi ); if ( ret != OK ) { GUS_AuxError = ret; GUS_SetErrorCode( GUS_GF1Error ); return( GUS_Error ); } status = USRHOOKS_GetMem( &wave_buff, patchi.header.wave_forms * sizeof( struct wave_struct ) ); if ( status != USRHOOKS_Ok ) { GUS_SetErrorCode( GUS_OutOfMemory ); return( GUS_Error ); } ret = gf1_load_patch( text, &patchi, &Patch[ prog ], &GUS_HoldBuffer, DMABUFFSIZE, ( unsigned char * )wave_buff, PATCH_LOAD_8_BIT ); if ( ret != OK ) { USRHOOKS_FreeMem( wave_buff ); GUS_AuxError = ret; GUS_SetErrorCode( GUS_GF1Error ); return( GUS_Error ); } PatchWaves[ prog ] = wave_buff; PatchLoaded[ prog ] = TRUE; return( GUS_Ok ); } /*--------------------------------------------------------------------- Function: GUSMIDI_ProgramChange Selects the instrument to use on the specified MIDI channel. ---------------------------------------------------------------------*/ void GUSMIDI_ProgramChange ( int channel, int prognum ) { int prog; prog = PatchMap[ prognum ][ GUS_MemConfig ]; if ( PatchLoaded[ prog ] ) { gf1_midi_change_program( &Patch[ prog ], channel ); } else { gf1_midi_change_program( NULL, channel ); } } /*--------------------------------------------------------------------- Function: GUSMIDI_NoteOn Plays a note on the specified channel. ---------------------------------------------------------------------*/ void GUSMIDI_NoteOn ( int chan, int note, int velocity ) { int prog; if ( chan == 9 ) { prog = PatchMap[ note + 128 ][ GUS_MemConfig ]; if ( PatchLoaded[ prog ] ) { gf1_midi_note_on( &Patch[ note + 128 ], 1, note, velocity, 9 ); } } else { gf1_midi_note_on( 0L, 1, note, velocity, chan ); } } /*--------------------------------------------------------------------- Function: GUSMIDI_NoteOff Turns off a note on the specified channel. ---------------------------------------------------------------------*/ #pragma warn -par void GUSMIDI_NoteOff ( int chan, int note, int velocity ) { gf1_midi_note_off( note, chan ); } #pragma warn .par /*--------------------------------------------------------------------- Function: GUSMIDI_ControlChange Sets the value of a controller on the specified channel. ---------------------------------------------------------------------*/ void GUSMIDI_ControlChange ( int channel, int number, int value ) { gf1_midi_parameter( channel, number, value ); } /*--------------------------------------------------------------------- Function: GUSMIDI_PitchBend Sets the pitch bend on the specified MIDI channel. ---------------------------------------------------------------------*/ void GUSMIDI_PitchBend ( int channel, int lsb, int msb ) { gf1_midi_pitch_bend( channel, lsb, msb ); } /*--------------------------------------------------------------------- Function: GUSMIDI_ReleasePatches Removes all the instruments from the GUS's memory. ---------------------------------------------------------------------*/ void GUSMIDI_ReleasePatches ( void ) { int i; for( i = 0; i < 256; i++ ) { GUSMIDI_UnloadPatch( i ); } } /*--------------------------------------------------------------------- Function: GUSMIDI_SetVolume Sets the total music volume. ---------------------------------------------------------------------*/ void GUSMIDI_SetVolume ( int volume ) { // Set the minimum to 2 because 0 has a tremolo problem volume = max( 2, volume ); volume = min( volume, 255 ); GUSMIDI_Volume = volume; // range = 0 to 127 gf1_midi_synth_volume( 0, volume >> 1 ); } /*--------------------------------------------------------------------- Function: GUSMIDI_GetVolume Returns the total music volume. ---------------------------------------------------------------------*/ int GUSMIDI_GetVolume ( void ) { return( GUSMIDI_Volume ); } /*--------------------------------------------------------------------- Function: GUSMIDI_Init Initializes the Gravis Ultrasound for music playback. ---------------------------------------------------------------------*/ int GUSMIDI_Init ( void ) { int ret; int i; int startmem; // unsigned long mem; extern int GUSWAVE_Installed; if ( GUSMIDI_Installed ) { GUSMIDI_Shutdown(); } ret = GUS_Init(); if ( ret != GUS_Ok ) { return( ret ); } if ( GUS_MemConfig < 0 ) { GUS_MemConfig = 0; } if ( GUS_MemConfig > MAX_MEM_CONFIG ) { GUS_MemConfig = MAX_MEM_CONFIG; } for( i = 0; i < NUM_PATCHES; i++ ) { ProgramName[ i ][ 0 ] = '\0'; PatchWaves[ i ] = NULL; PatchLoaded[ i ] = FALSE; } GUSMIDI_SetVolume( 255 ); GUSMIDI_Installed = TRUE; ret = GUS_GetPatchMap( ConfigFileName ); if ( ret != GUS_Ok ) { GUSMIDI_Shutdown(); return( ret ); } // if ( !GUSWAVE_Installed ) // { // mem = gf1_malloc( 8192 ); // } startmem = gf1_mem_avail(); for( i = 0; i < NUM_PATCHES; i++ ) { ret = GUSMIDI_LoadPatch( i ); if ( ret != GUS_Ok ) { } // if ( ret != GUS_Ok ) // { // return( ret ); // } } // if ( !GUSWAVE_Installed ) // { // gf1_free( mem ); // } GUSMIDI_Installed = TRUE; return( GUS_Ok ); } /*--------------------------------------------------------------------- Function: GUSMIDI_Shutdown Ends use of the Gravis Ultrasound for music playback. ---------------------------------------------------------------------*/ void GUSMIDI_Shutdown ( void ) { GUSMIDI_ReleasePatches(); GUS_Shutdown(); GUSMIDI_Installed = FALSE; }