2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: windigi.c,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $";
17 #pragma on (unreferenced)
51 #pragma pack (4); // Use 32-bit packing!
52 #pragma off (check_stack); // No stack checking!
54 #include "win\winmidi.h"
57 #define MAX_CHANNELS 32
59 typedef struct digi_channel {
60 ubyte used; // Non-zero if a sound is playing on this channel
61 int soundnum; // Which sound effect is on this channel, -1 if none
62 WORD handle; // What SS handle this is playing on
63 int soundobj; // Which soundobject is on this channel
64 int persistant; // This can't be pre-empted
65 int volume; // the volume of this channel
70 // ----------------------------------------------------------------------------
72 #define DIGI_PAUSE_BROKEN 1 //if this is defined, don't pause MIDI songs
73 #define _DIGI_SAMPLE_FLAGS (0)
74 #define _DIGI_MAX_VOLUME (16384)
75 #define MAX_SOUND_OBJECTS 22
80 // ----------------------------------------------------------------------------
82 int Digi_initialized = 0;
83 static int digi_atexit_called = 0; // Set to 1 if atexit(digi_close) was called
85 int digi_sample_rate = SAMPLE_RATE_22K; // rate to use driver at
86 int digi_max_channels = 8;
88 int digi_total_locks = 0;
90 static int digi_volume = _DIGI_MAX_VOLUME; // Max volume
91 static int digi_system_initialized = 0;
92 static int digi_sound_locks[MAX_SOUNDS];
93 BOOL DIGIDriverInit = FALSE;
97 // ----------------------------------------------------------------------------
100 ubyte *SongData=NULL;
101 HGLOBAL hSongData=NULL;
104 char digi_last_midi_song[16] = "";
106 static BOOL MIDIDriverInit = FALSE;
108 static int midi_system_initialized = 0;
109 static int midi_volume = 128/2; // Max volume
111 extern int Redbook_playing;
115 WORD hSOSDigiDriver = 0xffff; // handle for the SOS driver being used
116 WORD hSOSMidiDriver = 0xffff; // handle for the loaded MIDI driver
117 WORD hTimerEventHandle = 0xffff; // handle for the timer function
118 int digi_driver_dma = 0;
119 int digi_driver_board = 0;
120 int digi_driver_port = 0;
121 int digi_driver_irq = 0;
122 int digi_midi_type = 0;
123 int digi_midi_port = 0;
124 LPSTR digi_driver_path = NULL;
128 // Sound Handle stuff
129 // ----------------------------------------------------------------------------
130 digi_channel channels[MAX_CHANNELS];
131 int next_channel = 0;
132 int channels_inited = 0;
136 // ----------------------------------------------------------------------------
137 int verify_sound_channel_free(int channel);
139 void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length );
150 // ----------------------------------------------------------------------------
156 Digi_initialized = 1;
158 // Perform MIDI Detection
160 // Initialize MIDI driver
161 if (! FindArg( "-nomusic" )) {
162 midi_system_initialized = 1;
163 if (digi_init_midi()) {
164 mprintf((1, "Couldn't initialize MIDI system.\n"));
165 midi_system_initialized = 0;
170 // Initialize DIGI driver
171 if (! FindArg( "-nosound" )) {
172 digi_system_initialized = 1;
173 if (digi_init_digi()) {
174 mprintf((1, "Couldn't initialize digital sound system.\n"));
180 if (!digi_atexit_called) {
182 digi_atexit_called = 1;
185 // Miscellaneous Initialization
188 for (i = 0; i < MAX_SOUNDS; i++)
189 digi_sound_locks[i] = 0;
191 digi_stop_all_channels();
197 void digi_close(void)
200 if (!Digi_initialized) return;
201 Digi_initialized = 0;
206 digi_system_initialized = 0;
207 midi_system_initialized = 0;
211 int digi_init_digi(void)
215 Assert(digi_sample_rate == SAMPLE_RATE_11K || digi_sample_rate == SAMPLE_RATE_22K);
217 if (!digi_system_initialized)
220 // Determine board type?
221 digi_driver_board = 1;
223 // Initialize Sound System
224 if (!SSInit(_hAppWnd, 32, DSSCL_NORMAL)) {
225 DIGIDriverInit = FALSE;
230 if (sscaps.sample_rate < SAMPLE_RATE_22K)
231 digi_sample_rate = SAMPLE_RATE_11K;
233 // logentry("Detected sound card using (%d Hz). Using (%d Hz) samples.\n", sscaps.sample_rate, digi_sample_rate);
235 // Crank up the WAV volume for Wave-Table and full range of FX volumes
236 DIGIDriverInit = TRUE;
241 void digi_close_digi()
243 if (DIGIDriverInit) {
244 SSDestroy(); // resets WAV vol to SSInit value.
245 DIGIDriverInit = FALSE;
250 int digi_init_midi(void)
254 // check to see if MIDI is going to be used.
255 if (!midi_system_initialized)
258 // Initialize MIDI system and driver
259 res = wmidi_init(MIDI_MAPPER);
262 MIDIDriverInit = FALSE;
266 //@@ switch(sMIDICaps.wTechnology)
269 //@@ mprintf((0, "Using SB/SYNTH for MIDI.\n")); break;
271 //@@ case MOD_FMSYNTH:
272 //@@ mprintf((0, "Using ADLIB FM for MIDI.\n")); break;
274 //@@ case MOD_MAPPER:
275 //@@ mprintf((0, "Using MIDI mapping.\n")); break;
277 //@@ case MOD_MIDIPORT:
278 //@@ mprintf((0, "Using SB/External MIDI port.\n")); break;
280 //@@ case MOD_SQSYNTH:
281 //@@ mprintf((0, "Using Wave Synthesis for MIDI.\n")); break;
284 //@@ mprintf((0, "Using another method (%d) for MIDI.\n", sMIDICaps.wMID)); break;
289 MIDIDriverInit = TRUE;
292 digi_set_midi_volume(Config_midi_volume*16);
298 void digi_close_midi()
300 if (!midi_system_initialized) return;
302 if (MIDIDriverInit) {
304 // stop the last MIDI song from playing
310 GlobalUnlock(SongData);
311 GlobalFree(hSongData);
317 MIDIDriverInit = FALSE;
324 if ( Digi_initialized ) {
325 digi_stop_all_channels();
327 mprintf( (0, "Sound system DISABLED.\n" ));
330 mprintf( (0, "Sound system ENABLED.\n" ));
336 // ----------------------------------------------------------------------------
338 void digi_stop_all_channels()
342 for (i=0; i<MAX_CHANNELS; i++ )
345 for (i=0; i<MAX_SOUNDS; i++ ) {
346 Assert( digi_sound_locks[i] == 0 );
350 void digi_set_max_channels(int n)
352 digi_max_channels = n;
354 if ( digi_max_channels < 1 )
355 digi_max_channels = 1;
356 if ( digi_max_channels > 32 )
357 digi_max_channels = 32;
359 if ( !Digi_initialized ) return;
360 if ( !DIGIDriverInit ) return;
362 digi_stop_all_channels();
365 int digi_get_max_channels()
367 return digi_max_channels;
370 int digi_is_channel_playing( int c )
372 if (!Digi_initialized) return 0;
373 if (!DIGIDriverInit) return 0;
375 if ( channels[c].used && SSChannelPlaying((int)channels[c].handle))
380 void digi_set_channel_volume( int c, int volume )
382 if (!Digi_initialized) return;
383 if (!DIGIDriverInit) return;
385 if ( !channels[c].used ) return;
387 SSSetChannelVolume(channels[c].handle, (unsigned short)fixmuldiv(volume,digi_volume,F1_0));
390 void digi_set_channel_pan( int c, int pan )
392 if (!Digi_initialized) return;
393 if (!DIGIDriverInit) return;
395 if ( !channels[c].used ) return;
397 SSSetChannelPan(channels[c].handle, (unsigned short)pan);
400 void digi_stop_sound( int c )
402 if (!Digi_initialized) return;
403 if (!DIGIDriverInit) return;
405 if (!channels[c].used) return;
407 if ( digi_is_channel_playing(c) ) {
408 SSStopChannel(channels[c].handle);
410 channels[c].used = 0;
412 channels[c].soundobj = -1;
413 channels[c].persistant = 0;
416 void digi_end_sound( int c )
418 if (!Digi_initialized) return;
419 if (!DIGIDriverInit) return;
421 if (!channels[c].used) return;
423 channels[c].soundobj = -1;
424 channels[c].persistant = 0;
428 // Returns the channel a sound number is playing on, or
430 int digi_find_channel(int soundno)
434 if (!Digi_initialized) return -1;
435 if (!DIGIDriverInit) return -1;
437 if (soundno < 0 ) return -1;
438 if (GameSounds[soundno].data==NULL) {
444 for (i=0; i<digi_max_channels; i++ ) {
445 if ( channels[i].used && (channels[i].soundnum==soundno) )
446 if ( digi_is_channel_playing(i) )
452 extern void digi_end_soundobj(int channel);
453 extern int SoundQ_channel;
454 extern void SoundQ_end();
457 // DIGI Start Sample function
458 // ----------------------------------------------------------------------------
459 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
461 int i, starting_channel;
465 if ( !Digi_initialized ) return -1;
466 if ( !DIGIDriverInit ) return -1;
468 Assert(GameSounds[soundnum].data != -1);
470 memset(&ssb, 0, sizeof(SSoundBuffer));
472 ssb.data = (char *)GameSounds[soundnum].data;
473 ssb.length = GameSounds[soundnum].length;
474 ssb.pan = (unsigned short)pan+1;
475 // ssb.id = soundnum;
476 ssb.vol = (unsigned short)fixmuldiv(volume, digi_volume, F1_0);
477 ssb.vol = (ssb.vol << 2);
478 ssb.rate = digi_sample_rate;
480 ssb.bits_per_sample = 8;
484 ssb.loop_start = ssb.loop_end = -1;
486 if (loop_start != -1) {
487 Assert( loop_end != -1);
488 ssb.loop_start = loop_start;
489 ssb.loop_end = loop_end;
490 ssb.loop_length = loop_end - loop_start;
493 starting_channel = next_channel;
496 if ( !channels[next_channel].used ) break;
498 if (!SSChannelPlaying((int)channels[next_channel].handle)) break;
500 if ( !channels[next_channel].persistant ) {
501 SSStopChannel(channels[next_channel].handle);
502 break; // use this channel!
505 if ( next_channel >= digi_max_channels )
507 if ( next_channel == starting_channel ) {
508 mprintf(( 1, "OUT OF SOUND CHANNELS!!!\n" ));
512 if ( channels[next_channel].used ) {
513 channels[next_channel].used = 0;
514 if ( channels[next_channel].soundobj > -1 ) {
515 digi_end_soundobj(channels[next_channel].soundobj);
517 if (SoundQ_channel==next_channel)
521 sHandle = SSInitChannel(&ssb);
523 mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!!\n" ));
528 verify_sound_channel_free(next_channel);
531 //free up any sound objects that were using this handle
532 for (i=0; i<digi_max_channels; i++ ) {
533 if ( channels[i].used && (channels[i].handle == sHandle) ) {
534 channels[i].used = 0;
535 if ( channels[i].soundobj > -1 ) {
536 digi_end_soundobj(channels[i].soundobj);
538 if (SoundQ_channel==i)
543 channels[next_channel].used = 1;
544 channels[next_channel].soundnum = soundnum;
545 channels[next_channel].soundobj = soundobj;
546 channels[next_channel].handle = sHandle;
547 channels[next_channel].volume = volume;
548 channels[next_channel].persistant = 0;
549 if ( (soundobj > -1) || (looping) || (volume>F1_0) )
550 channels[next_channel].persistant = 1;
554 if ( next_channel >= digi_max_channels )
562 // ----------------------------------------------------------------------------
563 void digi_set_midi_volume( int mvolume )
566 int old_volume = midi_volume;
570 else if ( mvolume < 0 )
573 midi_volume = mvolume;
575 if ( (MIDIDriverInit) ) {
576 if (!Redbook_playing && (old_volume < 1) && ( midi_volume > 1 ) ) {
577 if (WMidiHandle == 0 )
578 digi_play_midi_song( digi_last_midi_song, NULL, NULL, 1 );
580 wmidi_set_volume(midi_volume);
583 mprintf((0, "Changing midi volume=%d.\n", midi_volume));
586 void digi_set_digi_volume( int dvolume )
588 dvolume = fixmuldiv( dvolume, _DIGI_MAX_VOLUME, 0x7fff);
589 if ( dvolume > _DIGI_MAX_VOLUME )
590 digi_volume = _DIGI_MAX_VOLUME;
591 else if ( dvolume < 0 )
594 digi_volume = dvolume;
596 if ( !Digi_initialized ) return;
597 if ( !digi_system_initialized ) return;
599 //digi_sync_sounds();
604 void digi_set_volume( int dvolume, int mvolume )
606 digi_set_midi_volume( mvolume );
607 digi_set_digi_volume( dvolume );
608 mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
611 // allocate memory for file, load fil
612 void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length )
618 fp = cfopen( szFileName, "rb" );
619 if ( !fp ) return NULL;
621 *length = cfilelength(fp);
623 *hmem = GlobalAlloc(GPTR, *length);
624 if (!(*hmem)) return NULL;
625 pDataPtr = GlobalLock(*hmem);
628 cfread( pDataPtr, *length, 1, fp);
638 void digi_stop_current_song()
640 if (!Digi_initialized) return;
642 if ( MIDIDriverInit ) {
644 if (WMidiHandle > 0 ) {
645 // stop the last MIDI song from playing
651 GlobalUnlock(SongData);
652 GlobalFree(hSongData);
660 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop )
666 if (!Digi_initialized) return;
667 if ( !MIDIDriverInit ) return;
669 digi_stop_current_song();
671 if ( filename == NULL ) return;
673 strcpy( digi_last_midi_song, filename );
677 sl = strlen( filename );
678 strcpy( fname, filename );
683 fp = cfopen( fname, "rb" );
684 mprintf((0, "Loading %s\n", fname));
687 mprintf( (1, "Error opening midi file, '%s'", filename ));
690 if ( midi_volume < 1 ) {
692 return; // Don't play song if volume == 0;
694 SongSize = cfilelength( fp );
695 hSongData = GlobalAlloc(GPTR, SongSize);
696 if (hSongData==NULL) {
698 mprintf( (1, "Error allocating %d bytes for '%s'", SongSize, filename ));
701 SongData = GlobalLock(hSongData);
702 if ( cfread ( SongData, SongSize, 1, fp )!=1) {
703 mprintf( (1, "Error reading midi file, '%s'", filename ));
705 GlobalUnlock(SongData);
706 GlobalFree(hSongData);
714 // setup the song initialization structure
715 WMidiSong.data = SongData;
716 WMidiSong.length = SongSize;
719 WMidiSong.looping = 1;
721 WMidiSong.looping = 0;
723 // initialize the song
724 WMidiHandle = wmidi_init_song(&WMidiSong);
726 mprintf((1, "Unable to initialize MIDI song.\n"));
727 GlobalUnlock(SongData);
728 GlobalFree(hSongData);
734 Assert( WMidiHandle == 1 );
736 // start the song playing
737 mprintf((0, "Playing song %x.\n", WMidiHandle));
740 mprintf( (1, "\nUnable to play midi song.\n"));
742 GlobalUnlock(SongData);
743 GlobalFree(hSongData);
751 int sound_paused = 0;
753 void digi_pause_midi()
755 if (!Digi_initialized) return;
757 if (sound_paused==0) {
758 if ( digi_midi_type > 0 && WMidiHandle > 0) {
768 void digi_resume_midi()
770 if (!Digi_initialized) return;
772 Assert( sound_paused > 0 );
774 if (sound_paused==1) {
776 if ( digi_midi_type > 0 && WMidiHandle > 0) {
790 if (!Digi_initialized) return;
791 if (!DIGIDriverInit) return;
793 for (i=0; i<digi_max_channels; i++ ) {
794 if ( digi_is_channel_playing(i) )
798 mprintf_at(( 0, 2, 0, "DIGI: Active Sound Channels: %d/%d ", n_voices, digi_max_channels));
802 void digi_midi_debug()
810 extern BOOL WMidi_NewStream;
812 void digi_midi_wait()
817 tech = wmidi_get_tech();
820 ftime = timer_get_fixed_seconds() + 0x50000;
821 WMidi_NewStream = FALSE;
822 while ((WMidi_NewStream < 2 && WMidiHandle) || (timer_get_fixed_seconds() < ftime)) Sleep(0);