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.
47 #pragma pack (4); // Use 32-bit packing!
48 #pragma off (check_stack); // No stack checking!
50 #include "win\winmidi.h"
53 #define MAX_CHANNELS 32
55 typedef struct digi_channel {
56 ubyte used; // Non-zero if a sound is playing on this channel
57 int soundnum; // Which sound effect is on this channel, -1 if none
58 WORD handle; // What SS handle this is playing on
59 int soundobj; // Which soundobject is on this channel
60 int persistant; // This can't be pre-empted
61 int volume; // the volume of this channel
66 // ----------------------------------------------------------------------------
68 #define DIGI_PAUSE_BROKEN 1 //if this is defined, don't pause MIDI songs
69 #define _DIGI_SAMPLE_FLAGS (0)
70 #define _DIGI_MAX_VOLUME (16384)
71 #define MAX_SOUND_OBJECTS 22
76 // ----------------------------------------------------------------------------
78 int Digi_initialized = 0;
79 static int digi_atexit_called = 0; // Set to 1 if atexit(digi_close) was called
81 int digi_sample_rate = SAMPLE_RATE_22K; // rate to use driver at
82 int digi_max_channels = 8;
84 int digi_total_locks = 0;
86 static int digi_volume = _DIGI_MAX_VOLUME; // Max volume
87 static int digi_system_initialized = 0;
88 static int digi_sound_locks[MAX_SOUNDS];
89 BOOL DIGIDriverInit = FALSE;
93 // ----------------------------------------------------------------------------
97 HGLOBAL hSongData=NULL;
100 char digi_last_midi_song[16] = "";
102 static BOOL MIDIDriverInit = FALSE;
104 static int midi_system_initialized = 0;
105 static int midi_volume = 128/2; // Max volume
107 extern int Redbook_playing;
111 WORD hSOSDigiDriver = 0xffff; // handle for the SOS driver being used
112 WORD hSOSMidiDriver = 0xffff; // handle for the loaded MIDI driver
113 WORD hTimerEventHandle = 0xffff; // handle for the timer function
114 int digi_driver_dma = 0;
115 int digi_driver_board = 0;
116 int digi_driver_port = 0;
117 int digi_driver_irq = 0;
118 int digi_midi_type = 0;
119 int digi_midi_port = 0;
120 LPSTR digi_driver_path = NULL;
124 // Sound Handle stuff
125 // ----------------------------------------------------------------------------
126 digi_channel channels[MAX_CHANNELS];
127 int next_channel = 0;
128 int channels_inited = 0;
132 // ----------------------------------------------------------------------------
133 int verify_sound_channel_free(int channel);
135 void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length );
146 // ----------------------------------------------------------------------------
152 Digi_initialized = 1;
154 // Perform MIDI Detection
156 // Initialize MIDI driver
157 if (! FindArg( "-nomusic" )) {
158 midi_system_initialized = 1;
159 if (digi_init_midi()) {
160 mprintf((1, "Couldn't initialize MIDI system.\n"));
161 midi_system_initialized = 0;
166 // Initialize DIGI driver
167 if (! FindArg( "-nosound" )) {
168 digi_system_initialized = 1;
169 if (digi_init_digi()) {
170 mprintf((1, "Couldn't initialize digital sound system.\n"));
176 if (!digi_atexit_called) {
178 digi_atexit_called = 1;
181 // Miscellaneous Initialization
184 for (i = 0; i < MAX_SOUNDS; i++)
185 digi_sound_locks[i] = 0;
187 digi_stop_all_channels();
193 void digi_close(void)
196 if (!Digi_initialized) return;
197 Digi_initialized = 0;
202 digi_system_initialized = 0;
203 midi_system_initialized = 0;
207 int digi_init_digi(void)
211 Assert(digi_sample_rate == SAMPLE_RATE_11K || digi_sample_rate == SAMPLE_RATE_22K);
213 if (!digi_system_initialized)
216 // Determine board type?
217 digi_driver_board = 1;
219 // Initialize Sound System
220 if (!SSInit(_hAppWnd, 32, DSSCL_NORMAL)) {
221 DIGIDriverInit = FALSE;
226 if (sscaps.sample_rate < SAMPLE_RATE_22K)
227 digi_sample_rate = SAMPLE_RATE_11K;
229 // logentry("Detected sound card using (%d Hz). Using (%d Hz) samples.\n", sscaps.sample_rate, digi_sample_rate);
231 // Crank up the WAV volume for Wave-Table and full range of FX volumes
232 DIGIDriverInit = TRUE;
237 void digi_close_digi()
239 if (DIGIDriverInit) {
240 SSDestroy(); // resets WAV vol to SSInit value.
241 DIGIDriverInit = FALSE;
246 int digi_init_midi(void)
250 // check to see if MIDI is going to be used.
251 if (!midi_system_initialized)
254 // Initialize MIDI system and driver
255 res = wmidi_init(MIDI_MAPPER);
258 MIDIDriverInit = FALSE;
262 //@@ switch(sMIDICaps.wTechnology)
265 //@@ mprintf((0, "Using SB/SYNTH for MIDI.\n")); break;
267 //@@ case MOD_FMSYNTH:
268 //@@ mprintf((0, "Using ADLIB FM for MIDI.\n")); break;
270 //@@ case MOD_MAPPER:
271 //@@ mprintf((0, "Using MIDI mapping.\n")); break;
273 //@@ case MOD_MIDIPORT:
274 //@@ mprintf((0, "Using SB/External MIDI port.\n")); break;
276 //@@ case MOD_SQSYNTH:
277 //@@ mprintf((0, "Using Wave Synthesis for MIDI.\n")); break;
280 //@@ mprintf((0, "Using another method (%d) for MIDI.\n", sMIDICaps.wMID)); break;
285 MIDIDriverInit = TRUE;
288 digi_set_midi_volume(Config_midi_volume.intval * 16);
294 void digi_close_midi()
296 if (!midi_system_initialized) return;
298 if (MIDIDriverInit) {
300 // stop the last MIDI song from playing
306 GlobalUnlock(SongData);
307 GlobalFree(hSongData);
313 MIDIDriverInit = FALSE;
320 if ( Digi_initialized ) {
321 digi_stop_all_channels();
323 mprintf( (0, "Sound system DISABLED.\n" ));
326 mprintf( (0, "Sound system ENABLED.\n" ));
332 // ----------------------------------------------------------------------------
334 void digi_stop_all_channels()
338 for (i=0; i<MAX_CHANNELS; i++ )
341 for (i=0; i<MAX_SOUNDS; i++ ) {
342 Assert( digi_sound_locks[i] == 0 );
346 void digi_set_max_channels(int n)
348 digi_max_channels = n;
350 if ( digi_max_channels < 1 )
351 digi_max_channels = 1;
352 if ( digi_max_channels > 32 )
353 digi_max_channels = 32;
355 if ( !Digi_initialized ) return;
356 if ( !DIGIDriverInit ) return;
358 digi_stop_all_channels();
361 int digi_get_max_channels()
363 return digi_max_channels;
366 int digi_is_channel_playing( int c )
368 if (!Digi_initialized) return 0;
369 if (!DIGIDriverInit) return 0;
371 if ( channels[c].used && SSChannelPlaying((int)channels[c].handle))
376 void digi_set_channel_volume( int c, int volume )
378 if (!Digi_initialized) return;
379 if (!DIGIDriverInit) return;
381 if ( !channels[c].used ) return;
383 SSSetChannelVolume(channels[c].handle, (unsigned short)fixmuldiv(volume,digi_volume,F1_0));
386 void digi_set_channel_pan( int c, int pan )
388 if (!Digi_initialized) return;
389 if (!DIGIDriverInit) return;
391 if ( !channels[c].used ) return;
393 SSSetChannelPan(channels[c].handle, (unsigned short)pan);
396 void digi_stop_sound( int c )
398 if (!Digi_initialized) return;
399 if (!DIGIDriverInit) return;
401 if (!channels[c].used) return;
403 if ( digi_is_channel_playing(c) ) {
404 SSStopChannel(channels[c].handle);
406 channels[c].used = 0;
408 channels[c].soundobj = -1;
409 channels[c].persistant = 0;
412 void digi_end_sound( int c )
414 if (!Digi_initialized) return;
415 if (!DIGIDriverInit) return;
417 if (!channels[c].used) return;
419 channels[c].soundobj = -1;
420 channels[c].persistant = 0;
424 // Returns the channel a sound number is playing on, or
426 int digi_find_channel(int soundno)
430 if (!Digi_initialized) return -1;
431 if (!DIGIDriverInit) return -1;
433 if (soundno < 0 ) return -1;
434 if (GameSounds[soundno].data==NULL) {
440 for (i=0; i<digi_max_channels; i++ ) {
441 if ( channels[i].used && (channels[i].soundnum==soundno) )
442 if ( digi_is_channel_playing(i) )
448 extern void digi_end_soundobj(int channel);
449 extern int SoundQ_channel;
450 extern void SoundQ_end();
453 // DIGI Start Sample function
454 // ----------------------------------------------------------------------------
455 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
457 int i, starting_channel;
461 if ( !Digi_initialized ) return -1;
462 if ( !DIGIDriverInit ) return -1;
464 Assert(GameSounds[soundnum].data != -1);
466 memset(&ssb, 0, sizeof(SSoundBuffer));
468 ssb.data = (char *)GameSounds[soundnum].data;
469 ssb.length = GameSounds[soundnum].length;
470 ssb.pan = (unsigned short)pan+1;
471 // ssb.id = soundnum;
472 ssb.vol = (unsigned short)fixmuldiv(volume, digi_volume, F1_0);
473 ssb.vol = (ssb.vol << 2);
474 ssb.rate = digi_sample_rate;
476 ssb.bits_per_sample = 8;
480 ssb.loop_start = ssb.loop_end = -1;
482 if (loop_start != -1) {
483 Assert( loop_end != -1);
484 ssb.loop_start = loop_start;
485 ssb.loop_end = loop_end;
486 ssb.loop_length = loop_end - loop_start;
489 starting_channel = next_channel;
492 if ( !channels[next_channel].used ) break;
494 if (!SSChannelPlaying((int)channels[next_channel].handle)) break;
496 if ( !channels[next_channel].persistant ) {
497 SSStopChannel(channels[next_channel].handle);
498 break; // use this channel!
501 if ( next_channel >= digi_max_channels )
503 if ( next_channel == starting_channel ) {
504 mprintf(( 1, "OUT OF SOUND CHANNELS!!!\n" ));
508 if ( channels[next_channel].used ) {
509 channels[next_channel].used = 0;
510 if ( channels[next_channel].soundobj > -1 ) {
511 digi_end_soundobj(channels[next_channel].soundobj);
513 if (SoundQ_channel==next_channel)
517 sHandle = SSInitChannel(&ssb);
519 mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!!\n" ));
524 verify_sound_channel_free(next_channel);
527 //free up any sound objects that were using this handle
528 for (i=0; i<digi_max_channels; i++ ) {
529 if ( channels[i].used && (channels[i].handle == sHandle) ) {
530 channels[i].used = 0;
531 if ( channels[i].soundobj > -1 ) {
532 digi_end_soundobj(channels[i].soundobj);
534 if (SoundQ_channel==i)
539 channels[next_channel].used = 1;
540 channels[next_channel].soundnum = soundnum;
541 channels[next_channel].soundobj = soundobj;
542 channels[next_channel].handle = sHandle;
543 channels[next_channel].volume = volume;
544 channels[next_channel].persistant = 0;
545 if ( (soundobj > -1) || (looping) || (volume>F1_0) )
546 channels[next_channel].persistant = 1;
550 if ( next_channel >= digi_max_channels )
558 // ----------------------------------------------------------------------------
559 void digi_set_midi_volume( int mvolume )
562 int old_volume = midi_volume;
566 else if ( mvolume < 0 )
569 midi_volume = mvolume;
571 if ( (MIDIDriverInit) ) {
572 if (!Redbook_playing && (old_volume < 1) && ( midi_volume > 1 ) ) {
573 if (WMidiHandle == 0 )
574 digi_play_midi_song( digi_last_midi_song, NULL, NULL, 1 );
576 wmidi_set_volume(midi_volume);
579 mprintf((0, "Changing midi volume=%d.\n", midi_volume));
582 void digi_set_digi_volume( int dvolume )
584 dvolume = fixmuldiv( dvolume, _DIGI_MAX_VOLUME, 0x7fff);
585 if ( dvolume > _DIGI_MAX_VOLUME )
586 digi_volume = _DIGI_MAX_VOLUME;
587 else if ( dvolume < 0 )
590 digi_volume = dvolume;
592 if ( !Digi_initialized ) return;
593 if ( !digi_system_initialized ) return;
595 //digi_sync_sounds();
600 void digi_set_volume( int dvolume, int mvolume )
602 digi_set_midi_volume( mvolume );
603 digi_set_digi_volume( dvolume );
604 mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
607 // allocate memory for file, load fil
608 void * digi_load_file( char * szFileName, HGLOBAL *hmem, int * length )
614 fp = cfopen( szFileName, "rb" );
615 if ( !fp ) return NULL;
617 *length = cfilelength(fp);
619 *hmem = GlobalAlloc(GPTR, *length);
620 if (!(*hmem)) return NULL;
621 pDataPtr = GlobalLock(*hmem);
624 cfread( pDataPtr, *length, 1, fp);
634 void digi_stop_current_song()
636 if (!Digi_initialized) return;
638 if ( MIDIDriverInit ) {
640 if (WMidiHandle > 0 ) {
641 // stop the last MIDI song from playing
647 GlobalUnlock(SongData);
648 GlobalFree(hSongData);
656 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop )
662 if (!Digi_initialized) return;
663 if ( !MIDIDriverInit ) return;
665 digi_stop_current_song();
667 if ( filename == NULL ) return;
669 strcpy( digi_last_midi_song, filename );
673 sl = strlen( filename );
674 strcpy( fname, filename );
679 fp = cfopen( fname, "rb" );
680 mprintf((0, "Loading %s\n", fname));
683 mprintf( (1, "Error opening midi file, '%s'", filename ));
686 if ( midi_volume < 1 ) {
688 return; // Don't play song if volume == 0;
690 SongSize = cfilelength( fp );
691 hSongData = GlobalAlloc(GPTR, SongSize);
692 if (hSongData==NULL) {
694 mprintf( (1, "Error allocating %d bytes for '%s'", SongSize, filename ));
697 SongData = GlobalLock(hSongData);
698 if ( cfread ( SongData, SongSize, 1, fp )!=1) {
699 mprintf( (1, "Error reading midi file, '%s'", filename ));
701 GlobalUnlock(SongData);
702 GlobalFree(hSongData);
710 // setup the song initialization structure
711 WMidiSong.data = SongData;
712 WMidiSong.length = SongSize;
715 WMidiSong.looping = 1;
717 WMidiSong.looping = 0;
719 // initialize the song
720 WMidiHandle = wmidi_init_song(&WMidiSong);
722 mprintf((1, "Unable to initialize MIDI song.\n"));
723 GlobalUnlock(SongData);
724 GlobalFree(hSongData);
730 Assert( WMidiHandle == 1 );
732 // start the song playing
733 mprintf((0, "Playing song %x.\n", WMidiHandle));
736 mprintf( (1, "\nUnable to play midi song.\n"));
738 GlobalUnlock(SongData);
739 GlobalFree(hSongData);
747 int sound_paused = 0;
749 void digi_pause_midi()
751 if (!Digi_initialized) return;
753 if (sound_paused==0) {
754 if ( digi_midi_type > 0 && WMidiHandle > 0) {
764 void digi_resume_midi()
766 if (!Digi_initialized) return;
768 Assert( sound_paused > 0 );
770 if (sound_paused==1) {
772 if ( digi_midi_type > 0 && WMidiHandle > 0) {
786 if (!Digi_initialized) return;
787 if (!DIGIDriverInit) return;
789 for (i=0; i<digi_max_channels; i++ ) {
790 if ( digi_is_channel_playing(i) )
794 mprintf_at(( 0, 2, 0, "DIGI: Active Sound Channels: %d/%d ", n_voices, digi_max_channels));
798 void digi_midi_debug()
806 extern BOOL WMidi_NewStream;
808 void digi_midi_wait()
813 tech = wmidi_get_tech();
816 ftime = timer_get_fixed_seconds() + 0x50000;
817 WMidi_NewStream = FALSE;
818 while ((WMidi_NewStream < 2 && WMidiHandle) || (timer_get_fixed_seconds() < ftime)) Sleep(0);