/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #pragma off (unreferenced) static char rcsid[] = "$Id: windigi.c,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $"; #pragma on (unreferenced) #include "desw.h" #include "win\ds.h" #include #include #include #include #include #include #include #include #include #include #include #include "fix.h" #include "object.h" #include "mono.h" #include "timer.h" #include "joy.h" #include "digi.h" #include "sounds.h" #include "args.h" #include "key.h" #include "newdemo.h" #include "game.h" #include "error.h" #include "wall.h" #include "cfile.h" #include "piggy.h" #include "text.h" #pragma pack (4); // Use 32-bit packing! #pragma off (check_stack); // No stack checking! #include "win\winmidi.h" #include "config.h" #define MAX_CHANNELS 32 typedef struct digi_channel { ubyte used; // Non-zero if a sound is playing on this channel int soundnum; // Which sound effect is on this channel, -1 if none WORD handle; // What SS handle this is playing on int soundobj; // Which soundobject is on this channel int persistant; // This can't be pre-empted int volume; // the volume of this channel } digi_channel; // Defines // ---------------------------------------------------------------------------- #define DIGI_PAUSE_BROKEN 1 //if this is defined, don't pause MIDI songs #define _DIGI_SAMPLE_FLAGS (0) #define _DIGI_MAX_VOLUME (16384) #define MAX_SOUND_OBJECTS 22 // Variables // ---------------------------------------------------------------------------- int Digi_initialized = 0; static int digi_atexit_called = 0; // Set to 1 if atexit(digi_close) was called int digi_sample_rate = SAMPLE_RATE_22K; // rate to use driver at int digi_max_channels = 8; int digi_total_locks = 0; static int digi_volume = _DIGI_MAX_VOLUME; // Max volume static int digi_system_initialized = 0; static int digi_sound_locks[MAX_SOUNDS]; BOOL DIGIDriverInit = FALSE; // MIDI stuff // ---------------------------------------------------------------------------- WMIDISONG WMidiSong; int WMidiHandle=0; ubyte *SongData=NULL; HGLOBAL hSongData=NULL; int SongSize; char digi_last_midi_song[16] = ""; static BOOL MIDIDriverInit = FALSE; static int midi_system_initialized = 0; static int midi_volume = 128/2; // Max volume extern int Redbook_playing; /* Obsolete */ WORD hSOSDigiDriver = 0xffff; // handle for the SOS driver being used WORD hSOSMidiDriver = 0xffff; // handle for the loaded MIDI driver WORD hTimerEventHandle = 0xffff; // handle for the timer function int digi_driver_dma = 0; int digi_driver_board = 0; int digi_driver_port = 0; int digi_driver_irq = 0; int digi_midi_type = 0; int digi_midi_port = 0; LPSTR digi_driver_path = NULL; /* Not Obsolete */ // Sound Handle stuff // ---------------------------------------------------------------------------- digi_channel channels[MAX_CHANNELS]; int next_channel = 0; int channels_inited = 0; // Functions // ---------------------------------------------------------------------------- int verify_sound_channel_free(int channel); void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length ); // FUNCTIONS!!! // DIGI SYSTEM // Initialization // Play // Sound System // // MIDI SYSTEM // ---------------------------------------------------------------------------- int digi_init(void) { int i; Digi_initialized = 1; // Perform MIDI Detection // Initialize MIDI driver if (! FindArg( "-nomusic" )) { midi_system_initialized = 1; if (digi_init_midi()) { mprintf((1, "Couldn't initialize MIDI system.\n")); midi_system_initialized = 0; return 1; } } // Initialize DIGI driver if (! FindArg( "-nosound" )) { digi_system_initialized = 1; if (digi_init_digi()) { mprintf((1, "Couldn't initialize digital sound system.\n")); digi_close(); return 2; } } if (!digi_atexit_called) { atexit(digi_close); digi_atexit_called = 1; } // Miscellaneous Initialization digi_init_sounds(); for (i = 0; i < MAX_SOUNDS; i++) digi_sound_locks[i] = 0; digi_stop_all_channels(); return 0; } void digi_close(void) { if (!Digi_initialized) return; Digi_initialized = 0; digi_close_midi(); digi_close_digi(); digi_system_initialized = 0; midi_system_initialized = 0; } int digi_init_digi(void) { SSCaps sscaps; Assert(digi_sample_rate == SAMPLE_RATE_11K || digi_sample_rate == SAMPLE_RATE_22K); if (!digi_system_initialized) return 1; // Determine board type? digi_driver_board = 1; // Initialize Sound System if (!SSInit(_hAppWnd, 32, DSSCL_NORMAL)) { DIGIDriverInit = FALSE; return 1; } SSGetCaps(&sscaps); if (sscaps.sample_rate < SAMPLE_RATE_22K) digi_sample_rate = SAMPLE_RATE_11K; // logentry("Detected sound card using (%d Hz). Using (%d Hz) samples.\n", sscaps.sample_rate, digi_sample_rate); // Crank up the WAV volume for Wave-Table and full range of FX volumes DIGIDriverInit = TRUE; return 0; } void digi_close_digi() { if (DIGIDriverInit) { SSDestroy(); // resets WAV vol to SSInit value. DIGIDriverInit = FALSE; } } int digi_init_midi(void) { DWORD res; // check to see if MIDI is going to be used. if (!midi_system_initialized) return 1; // Initialize MIDI system and driver res = wmidi_init(MIDI_MAPPER); if (!res) { MIDIDriverInit = FALSE; return 1; } else { //@@ switch(sMIDICaps.wTechnology) //@@ { //@@ case MOD_SYNTH: //@@ mprintf((0, "Using SB/SYNTH for MIDI.\n")); break; //@@ //@@ case MOD_FMSYNTH: //@@ mprintf((0, "Using ADLIB FM for MIDI.\n")); break; //@@ //@@ case MOD_MAPPER: //@@ mprintf((0, "Using MIDI mapping.\n")); break; //@@ //@@ case MOD_MIDIPORT: //@@ mprintf((0, "Using SB/External MIDI port.\n")); break; //@@ //@@ case MOD_SQSYNTH: //@@ mprintf((0, "Using Wave Synthesis for MIDI.\n")); break; //@@ //@@ default: //@@ mprintf((0, "Using another method (%d) for MIDI.\n", sMIDICaps.wMID)); break; //@@ } digi_midi_type = 1; MIDIDriverInit = TRUE; } digi_set_midi_volume(Config_midi_volume*16); return 0; } void digi_close_midi() { if (!midi_system_initialized) return; if (MIDIDriverInit) { if (WMidiHandle) { // stop the last MIDI song from playing wmidi_stop(); wmidi_close_song(); WMidiHandle = 0; } if (SongData) { GlobalUnlock(SongData); GlobalFree(hSongData); SongData = NULL; hSongData = NULL; } wmidi_close(); MIDIDriverInit = FALSE; } } void digi_reset() { if ( Digi_initialized ) { digi_stop_all_channels(); digi_close(); mprintf( (0, "Sound system DISABLED.\n" )); } else { digi_init(); mprintf( (0, "Sound system ENABLED.\n" )); } } // Channel Functions // ---------------------------------------------------------------------------- void digi_stop_all_channels() { int i; for (i=0; i 32 ) digi_max_channels = 32; if ( !Digi_initialized ) return; if ( !DIGIDriverInit ) return; digi_stop_all_channels(); } int digi_get_max_channels() { return digi_max_channels; } int digi_is_channel_playing( int c ) { if (!Digi_initialized) return 0; if (!DIGIDriverInit) return 0; if ( channels[c].used && SSChannelPlaying((int)channels[c].handle)) return 1; return 0; } void digi_set_channel_volume( int c, int volume ) { if (!Digi_initialized) return; if (!DIGIDriverInit) return; if ( !channels[c].used ) return; SSSetChannelVolume(channels[c].handle, (unsigned short)fixmuldiv(volume,digi_volume,F1_0)); } void digi_set_channel_pan( int c, int pan ) { if (!Digi_initialized) return; if (!DIGIDriverInit) return; if ( !channels[c].used ) return; SSSetChannelPan(channels[c].handle, (unsigned short)pan); } void digi_stop_sound( int c ) { if (!Digi_initialized) return; if (!DIGIDriverInit) return; if (!channels[c].used) return; if ( digi_is_channel_playing(c) ) { SSStopChannel(channels[c].handle); } channels[c].used = 0; channels[c].soundobj = -1; channels[c].persistant = 0; } void digi_end_sound( int c ) { if (!Digi_initialized) return; if (!DIGIDriverInit) return; if (!channels[c].used) return; channels[c].soundobj = -1; channels[c].persistant = 0; } // Returns the channel a sound number is playing on, or // -1 if none. int digi_find_channel(int soundno) { int i, is_playing; if (!Digi_initialized) return -1; if (!DIGIDriverInit) return -1; if (soundno < 0 ) return -1; if (GameSounds[soundno].data==NULL) { Int3(); return -1; } is_playing = 0; for (i=0; i= digi_max_channels ) next_channel = 0; if ( next_channel == starting_channel ) { mprintf(( 1, "OUT OF SOUND CHANNELS!!!\n" )); return -1; } } if ( channels[next_channel].used ) { channels[next_channel].used = 0; if ( channels[next_channel].soundobj > -1 ) { digi_end_soundobj(channels[next_channel].soundobj); } if (SoundQ_channel==next_channel) SoundQ_end(); } sHandle = SSInitChannel(&ssb); if (sHandle == -1) { mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!!\n" )); return -1; } #ifndef NDEBUG verify_sound_channel_free(next_channel); #endif //free up any sound objects that were using this handle for (i=0; i -1 ) { digi_end_soundobj(channels[i].soundobj); } if (SoundQ_channel==i) SoundQ_end(); } } channels[next_channel].used = 1; channels[next_channel].soundnum = soundnum; channels[next_channel].soundobj = soundobj; channels[next_channel].handle = sHandle; channels[next_channel].volume = volume; channels[next_channel].persistant = 0; if ( (soundobj > -1) || (looping) || (volume>F1_0) ) channels[next_channel].persistant = 1; i = next_channel; next_channel++; if ( next_channel >= digi_max_channels ) next_channel = 0; return i; } // Volume Functions // ---------------------------------------------------------------------------- void digi_set_midi_volume( int mvolume ) { int old_volume = midi_volume; if ( mvolume > 127 ) midi_volume = 127; else if ( mvolume < 0 ) midi_volume = 0; else midi_volume = mvolume; if ( (MIDIDriverInit) ) { if (!Redbook_playing && (old_volume < 1) && ( midi_volume > 1 ) ) { if (WMidiHandle == 0 ) digi_play_midi_song( digi_last_midi_song, NULL, NULL, 1 ); } wmidi_set_volume(midi_volume); } mprintf((0, "Changing midi volume=%d.\n", midi_volume)); } void digi_set_digi_volume( int dvolume ) { dvolume = fixmuldiv( dvolume, _DIGI_MAX_VOLUME, 0x7fff); if ( dvolume > _DIGI_MAX_VOLUME ) digi_volume = _DIGI_MAX_VOLUME; else if ( dvolume < 0 ) digi_volume = 0; else digi_volume = dvolume; if ( !Digi_initialized ) return; if ( !digi_system_initialized ) return; //digi_sync_sounds(); } // 0-0x7FFF void digi_set_volume( int dvolume, int mvolume ) { digi_set_midi_volume( mvolume ); digi_set_digi_volume( dvolume ); mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume )); } // allocate memory for file, load fil void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length ) { PSTR pDataPtr; CFILE * fp; // open file fp = cfopen( szFileName, "rb" ); if ( !fp ) return NULL; *length = cfilelength(fp); *hmem = GlobalAlloc(GPTR, *length); if (!(*hmem)) return NULL; pDataPtr = GlobalLock(*hmem); // read in driver cfread( pDataPtr, *length, 1, fp); // close driver file cfclose( fp ); // return return( pDataPtr ); } void digi_stop_current_song() { if (!Digi_initialized) return; if ( MIDIDriverInit ) { // Stop last song... if (WMidiHandle > 0 ) { // stop the last MIDI song from playing wmidi_stop(); wmidi_close_song(); WMidiHandle = 0; } if (SongData) { GlobalUnlock(SongData); GlobalFree(hSongData); SongData = NULL; hSongData = NULL; } } } void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) { char fname[128]; CFILE *fp; int sl; if (!Digi_initialized) return; if ( !MIDIDriverInit ) return; digi_stop_current_song(); if ( filename == NULL ) return; strcpy( digi_last_midi_song, filename ); fp = NULL; sl = strlen( filename ); strcpy( fname, filename ); fname[sl-3] = 'm'; fname[sl-2] = 'i'; fname[sl-1] = 'd'; fp = cfopen( fname, "rb" ); mprintf((0, "Loading %s\n", fname)); if ( !fp ) { mprintf( (1, "Error opening midi file, '%s'", filename )); return; } if ( midi_volume < 1 ) { cfclose(fp); return; // Don't play song if volume == 0; } SongSize = cfilelength( fp ); hSongData = GlobalAlloc(GPTR, SongSize); if (hSongData==NULL) { cfclose(fp); mprintf( (1, "Error allocating %d bytes for '%s'", SongSize, filename )); return; } SongData = GlobalLock(hSongData); if ( cfread ( SongData, SongSize, 1, fp )!=1) { mprintf( (1, "Error reading midi file, '%s'", filename )); cfclose(fp); GlobalUnlock(SongData); GlobalFree(hSongData); SongData=NULL; hSongData = NULL; return; } cfclose(fp); // setup the song initialization structure WMidiSong.data = SongData; WMidiSong.length = SongSize; if ( loop ) WMidiSong.looping = 1; else WMidiSong.looping = 0; // initialize the song WMidiHandle = wmidi_init_song(&WMidiSong); if (!WMidiHandle) { mprintf((1, "Unable to initialize MIDI song.\n")); GlobalUnlock(SongData); GlobalFree(hSongData); SongData=NULL; hSongData = NULL; return; } Assert( WMidiHandle == 1 ); // start the song playing mprintf((0, "Playing song %x.\n", WMidiHandle)); if (!wmidi_play()) { mprintf( (1, "\nUnable to play midi song.\n")); wmidi_close_song(); GlobalUnlock(SongData); GlobalFree(hSongData); SongData=NULL; hSongData = NULL; return; } } int sound_paused = 0; void digi_pause_midi() { if (!Digi_initialized) return; if (sound_paused==0) { if ( digi_midi_type > 0 && WMidiHandle > 0) { // pause here wmidi_pause(); } } sound_paused++; } void digi_resume_midi() { if (!Digi_initialized) return; Assert( sound_paused > 0 ); if (sound_paused==1) { // resume sound here if ( digi_midi_type > 0 && WMidiHandle > 0) { wmidi_resume(); } } sound_paused--; } #ifndef NDEBUG void digi_debug() { int i; int n_voices=0; if (!Digi_initialized) return; if (!DIGIDriverInit) return; for (i=0; i