]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/digiallg.c
fixed a major memory leak and removed a bit of redundancy (d1x r1.5)
[btb/d2x.git] / arch / dos / digiallg.c
1 /*
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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <malloc.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include "fix.h"
21 #include "object.h"
22 #include "mono.h"
23 #include "timer.h"
24 #include "joy.h"
25 #include "digi.h"
26 #include "sounds.h"
27 #include "args.h"
28 #include "key.h"
29 #include "newdemo.h"
30 #include "game.h"
31 #include "u_dpmi.h"
32 #include "error.h"
33 #include "wall.h"
34 #include "cfile.h"
35 #include "piggy.h"
36 #include "text.h"
37 #include "midiallg.h"
38
39 #include "kconfig.h"
40
41 #define _DIGI_MAX_VOLUME 128 // set lower to have difference with > F1_0 sounds
42
43 #define MIN_VOLUME 10 // minimal volume to be played (in 0-F1_0(?) range)
44
45 // patch files
46 #define  _MELODIC_PATCH       "melodic.bnk"
47 #define  _DRUM_PATCH          "drum.bnk"
48 #define  _DIGDRUM_PATCH       "drum32.dig"
49
50  
51 static int      Digi_initialized                = 0;
52 static int      digi_atexit_called      = 0;                    // Set to 1 if atexit(digi_close) was called
53
54 int digi_driver_board                           = 0;
55 int digi_driver_port                                    = 0;
56 int digi_driver_irq                                     = 0;
57 int digi_driver_dma                                     = 0;
58 //int digi_midi_type                                      = 0;                    // Midi driver type
59 //int digi_midi_port                                      = 0;                    // Midi driver port
60 static int digi_max_channels            = 8;
61 //static int digi_driver_rate             = 11025;                        // rate to use driver at
62 //static int digi_dma_buffersize  = 4096;                 // size of the dma buffer to use (4k)
63 int digi_timer_rate                                     = 9943;                 // rate for the timer to go off to handle the driver system (120 Hz)
64 int digi_lomem                                          = 0;
65 static int digi_volume                          = _DIGI_MAX_VOLUME;             // Max volume
66 //static int midi_volume                          = 128/2;                                                // Max volume
67 //static int midi_system_initialized              = 0;
68 //static int digi_system_initialized              = 0;
69 static int timer_system_initialized             = 0;
70 static int digi_sound_locks[MAX_SOUNDS];
71 //char digi_last_midi_song[16] = "";
72 //char digi_last_melodic_bank[16] = "";
73 //char digi_last_drum_bank[16] = "";
74 char *digi_driver_path = NULL;
75
76 extern int midi_volume;
77
78 //static void * lpInstruments = NULL;             // pointer to the instrument file
79 //static int InstrumentSize = 0;
80 //static void * lpDrums = NULL;                           // pointer to the drum file
81 //static int DrumSize = 0;
82
83 // handle for the initialized MIDI song
84 //MIDI *SongHandle = NULL;
85
86 #define SOF_USED                        1               // Set if this sample is used
87 #define SOF_PLAYING                     2               // Set if this sample is playing on a channel
88 #define SOF_LINK_TO_OBJ         4               // Sound is linked to a moving object. If object dies, then finishes play and quits.
89 #define SOF_LINK_TO_POS         8               // Sound is linked to segment, pos
90 #define SOF_PLAY_FOREVER        16              // Play forever (or until level is stopped), otherwise plays once
91
92 typedef int WORD;
93
94 typedef struct sound_object {
95         short           signature;              // A unique signature to this sound
96         ubyte           flags;                  // Used to tell if this slot is used and/or currently playing, and how long.
97         fix                     max_volume;             // Max volume that this sound is playing at
98         fix                     max_distance;   // The max distance that this sound can be heard at...
99         int                     volume;                 // Volume that this sound is playing at
100         int             pan;                    // Pan value that this sound is playing at
101         WORD            handle;                 // What handle this sound is playing on.  Valid only if SOF_PLAYING is set.
102         short           soundnum;               // The sound number that is playing
103         union { 
104                 struct {
105                         short           segnum;                         // Used if SOF_LINK_TO_POS field is used
106                         short           sidenum;
107                         vms_vector      position;
108                 }pos;
109                 struct {
110                         short            objnum;                         // Used if SOF_LINK_TO_OBJ field is used
111                         short            objsignature;
112                 }obj;
113         }link;
114 } sound_object;
115 #define lp_segnum link.pos.segnum
116 #define lp_sidenum link.pos.sidenum
117 #define lp_position link.pos.position
118
119 #define lo_objnum link.obj.objnum
120 #define lo_objsignature link.obj.objsignature
121
122 #define MAX_SOUND_OBJECTS 16
123 sound_object SoundObjects[MAX_SOUND_OBJECTS];
124 short next_signature=0;
125
126 int digi_sounds_initialized=0;
127
128
129 // a channel (voice) id is an int in Allegro
130 typedef int CHANNEL;
131 #define VALID_CHANNEL(ch) (ch >= 0)
132 #define INVALID_CHANNEL -1
133
134 #define DIGI_SLOTS DIGI_VOICES
135
136 // next_handle is a Descent internal number (hereafter reffered to as slot),
137 // which indexes into SampleHandles, SoundNums and SoundVolumes.
138 // only digi_max_channels entries are used.
139 // SampleHandles points to sounddriver handles (voices)
140 static int next_handle = 0;
141 static CHANNEL SampleHandles[DIGI_SLOTS] = {
142     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
143     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
144     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
145     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
146     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
147     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
148     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL,
149     INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL, INVALID_CHANNEL };
150 static int SoundNums[DIGI_SLOTS] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
151 static uint SoundVolumes[DIGI_SLOTS] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
152
153 void digi_reset_digi_sounds();
154 int verify_channel_not_used_by_soundobjects( int channel );
155
156 int digi_xlat_sound(int soundno)
157 {
158         if ( soundno < 0 ) return -1;
159
160         if ( digi_lomem )       {
161                 soundno = AltSounds[soundno];
162                 if ( soundno == 255 ) return -1;
163         }
164         return Sounds[soundno];
165 }
166
167 void digi_close() {
168         if (!Digi_initialized) return;
169
170         remove_sound();
171         Digi_initialized = 0;
172
173         if ( timer_system_initialized ) {
174                 // Remove timer...
175                 timer_set_function( NULL );
176     }
177     timer_system_initialized = 0;
178 }
179
180 /* initialize sound system. 0=ok, 1=error */
181 int digi_init() {
182         int i;
183
184         if (!timer_system_initialized)
185         {
186             allg_snd_init();
187             timer_system_initialized = 1;
188         }
189         if (!Digi_initialized) {
190                 // amount of voices we need
191                 // 16 for normal sounds and 16 for SoundObjects (fan, boss)
192                 // for DIGMID we sacrify some sounds (32 is the max).
193 //                reserve_voices(allegro_using_digmid() ? 16 : 32, -1);
194                 if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL))
195                         return 1;
196                 set_volume(255, -1);
197                 digi_driver_board = digi_card; // only for 0, !=0
198                 digi_midi_type = midi_card; // only for 0, !=0
199         }
200         Digi_initialized = 1;
201
202
203         if (!digi_atexit_called)        {
204                 atexit( digi_close );
205                 digi_atexit_called = 1;
206         }
207
208         digi_init_sounds();
209         digi_set_midi_volume( midi_volume );
210
211         for (i=0; i<MAX_SOUNDS; i++ )
212                 digi_sound_locks[i] = 0;
213         digi_reset_digi_sounds();
214
215         return 0;
216 }
217
218 // Toggles sound system on/off
219 void digi_reset()       
220 {
221         if ( Digi_initialized ) {
222                 digi_reset_digi_sounds();
223                 digi_close();
224                 mprintf( (0, "Sound system DISABLED.\n" ));
225         } else {
226                 digi_init();
227                 mprintf( (0, "Sound system ENABLED.\n" ));
228         }
229 }
230
231 int digi_total_locks = 0;
232
233 ubyte * digi_lock_sound_data( int soundnum )
234 {
235         int i;
236
237         if ( !Digi_initialized ) return NULL;
238         if ( digi_driver_board <= 0 )   return NULL;
239
240         if ( digi_sound_locks[soundnum] == 0 )  {
241                 digi_total_locks++;
242                 //mprintf(( 0, "Total sound locks = %d\n", digi_total_locks ));
243                 i = dpmi_lock_region( GameSounds[soundnum].data, GameSounds[soundnum].len );
244                 if ( !i ) Error( "Error locking sound %d\n", soundnum );
245         }
246         digi_sound_locks[soundnum]++;
247         return GameSounds[soundnum].data;
248 }
249
250 void digi_unlock_sound_data( int soundnum )
251 {
252         int i;
253
254         if ( !Digi_initialized ) return;
255         if ( digi_driver_board <= 0 )   return;
256
257         Assert( digi_sound_locks[soundnum] > 0 );
258
259         if ( digi_sound_locks[soundnum] == 1 )  {
260                 digi_total_locks--;
261                 //mprintf(( 0, "Total sound locks = %d\n", digi_total_locks ));
262                 i = dpmi_unlock_region( GameSounds[soundnum].data, GameSounds[soundnum].len );
263                 if ( !i ) Error( "Error unlocking sound %d\n", soundnum );
264         }
265         digi_sound_locks[soundnum]--;
266 }
267
268
269 void digi_reset_digi_sounds() {
270         int i;
271
272         for (i = 0; i < DIGI_SLOTS; i++) {
273                 if (VALID_CHANNEL(SampleHandles[i])) {
274                         deallocate_voice(SampleHandles[i]);
275                         SampleHandles[i] = INVALID_CHANNEL;
276                 }
277                 if (SoundNums[i] != -1) {
278                         digi_unlock_sound_data(SoundNums[i]);
279                         SoundNums[i] = -1;
280         }
281         }
282         for (i=0; i<MAX_SOUNDS; i++ )   {
283                 Assert( digi_sound_locks[i] == 0 );
284         }
285 }
286
287 void reset_slots_on_channel( int channel ) {
288         int i;
289
290         if ( !Digi_initialized ) return;
291         if ( digi_driver_board <= 0 )   return;
292
293         for (i=0; i<DIGI_SLOTS; i++) {
294                 if (SampleHandles[i] == channel) {
295                         SampleHandles[i] = INVALID_CHANNEL;
296                         if (SoundNums[i] != -1)   {
297                                 digi_unlock_sound_data(SoundNums[i]);
298                                 SoundNums[i] = -1;
299                         }
300                 }
301         }
302 }
303
304 void digi_set_max_channels(int n) {
305         digi_max_channels       = n;
306
307         if ( digi_max_channels < 1 ) 
308                 digi_max_channels = 1;
309         if ( digi_max_channels > DIGI_VOICES)
310                 digi_max_channels = DIGI_VOICES;
311 }
312
313 int digi_get_max_channels()
314 {
315         return digi_max_channels;
316 }
317
318 int get_free_slot() {
319         int ntries = 0;
320         int ret_slot;
321
322 TryNextChannel:
323         // sound playing on slot <next_handle>?
324         if ( (VALID_CHANNEL(SampleHandles[next_handle])) &&
325              (voice_check(SampleHandles[next_handle])) ) {
326                 // don't use this slot if loud sound
327                 if ( (SoundVolumes[next_handle] > digi_volume) &&
328                          (ntries<digi_max_channels) )  {
329                         mprintf(( 0, "Not stopping loud sound %d (%d).\n", next_handle, SoundNums[next_handle]));
330                         next_handle++;
331                         if ( next_handle >= digi_max_channels )
332                                 next_handle = 0;
333                         ntries++;
334                         goto TryNextChannel;
335                 }
336                 //mprintf(( 0, "[SS:%d]", next_handle ));
337                 if (voice_check(next_handle))
338                         mprintf((0,"Sound: deallocating used voice %d sound %d vol %d pos %d/%d\n", next_handle, SoundNums[next_handle], SoundVolumes[next_handle], voice_get_position(next_handle), GameSounds[SoundNums[next_handle]].len));
339                 deallocate_voice(SampleHandles[next_handle]);
340                 SampleHandles[next_handle] = INVALID_CHANNEL;
341         }
342
343         if ( SoundNums[next_handle] != -1 ) {
344                 digi_unlock_sound_data(SoundNums[next_handle]);
345                 SoundNums[next_handle] = -1;
346         }
347         ret_slot = next_handle;
348         next_handle++;
349         if ( next_handle >= digi_max_channels )
350                 next_handle = 0;
351         return ret_slot;
352 }
353
354 CHANNEL digi_start_sound(int soundnum, int volume, int pan) {
355         int i;
356         int channel;
357         int slot;
358
359         volume = fixmul(volume, digi_volume);
360         slot = get_free_slot();
361
362         digi_lock_sound_data(soundnum);
363         channel = play_sample(&GameSounds[soundnum], volume, pan >> 8, 1000, 0);
364         if (channel < 0) {
365                 mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!!\n" ));
366                 digi_unlock_sound_data(soundnum);
367                 return -1;
368         }
369         release_voice(channel);
370
371         //mprintf(( 0, "Starting sound on channel %d\n", channel ));
372         #ifndef NDEBUG
373         verify_channel_not_used_by_soundobjects(channel);
374         #endif
375
376         // find slots pointing to just allocated channel and kill sounds on it
377         // (because they can't be playing right now)
378         for (i=0; i<digi_max_channels; i++ )    {
379                 if (SampleHandles[i] == channel)   {
380                         SampleHandles[i] = INVALID_CHANNEL;
381                         if (SoundNums[i] != -1)   {
382                                 digi_unlock_sound_data(SoundNums[i]);
383                                 SoundNums[i] = -1;
384                         }
385                 }
386         }
387
388         // fill slot with data of just started sample
389         SampleHandles[slot] = channel;
390         SoundNums[slot] = soundnum;
391         SoundVolumes[slot] = volume;
392
393         return channel;
394 }
395
396 int digi_is_sound_playing(int soundno)
397 {
398         int i;
399
400         soundno = digi_xlat_sound(soundno);
401
402         for (i = 0; i < DIGI_VOICES; i++)
403                   if (voice_check(i) == &GameSounds[soundno])
404                         return 1;
405         return 0;
406 }
407
408 void digi_play_sample_once( int soundno, fix max_volume ) {
409         int i;
410
411 #ifdef NEWDEMO
412         if ( Newdemo_state == ND_STATE_RECORDING )
413                 newdemo_record_sound( soundno );
414 #endif
415         soundno = digi_xlat_sound(soundno);
416
417         if (!Digi_initialized) return;
418         if (digi_driver_board<1) return;
419
420         if (soundno < 0 ) return;
421
422         for (i = 0; i < DIGI_VOICES; i++)
423             if (voice_check(i) == &GameSounds[soundno])
424                         deallocate_voice(i);
425
426         digi_start_sound(soundno, max_volume, F0_5);
427 }
428
429 void digi_play_sample( int soundno, fix max_volume ) {
430 #ifdef NEWDEMO
431         if ( Newdemo_state == ND_STATE_RECORDING )
432                 newdemo_record_sound( soundno );
433 #endif
434         soundno = digi_xlat_sound(soundno);
435
436         if (!Digi_initialized) return;
437         if (digi_driver_board<1) return;
438
439         if (soundno < 0 ) return;
440
441         digi_start_sound(soundno, max_volume, F0_5);
442 }
443
444 void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups )
445 {
446         no_dups = 1;
447
448 #ifdef NEWDEMO
449         if ( Newdemo_state == ND_STATE_RECORDING )              {
450                 if ( no_dups )
451                         newdemo_record_sound_3d_once( soundno, angle, volume );
452                 else
453                         newdemo_record_sound_3d( soundno, angle, volume );
454         }
455 #endif
456         soundno = digi_xlat_sound(soundno);
457
458         if (!Digi_initialized) return;
459         if (digi_driver_board<1) return;
460         if (soundno < 0 ) return;
461
462         if (volume < MIN_VOLUME ) return;
463
464         digi_start_sound(soundno, volume, angle);
465 }
466
467 //-killed- void digi_set_midi_volume( int mvolume )
468 //-killed- {
469 //-killed-         int old_volume = midi_volume;
470 //-killed- 
471 //-killed-         if ( mvolume > 127 )
472 //-killed-                 midi_volume = 127;
473 //-killed-         else if ( mvolume < 0 )
474 //-killed-                 midi_volume = 0;
475 //-killed-         else
476 //-killed-                 midi_volume = mvolume;
477 //-killed- 
478 //-killed-         if ( (digi_midi_type > 0) )        {
479 //-killed-                 if (  (old_volume < 1) && ( midi_volume > 1 ) ) {
480 //-killed-                         if (SongHandle == NULL )
481 //-killed-                                 digi_play_midi_song( digi_last_midi_song, digi_last_melodic_bank, digi_last_drum_bank, 1 );
482 //-killed-                 }
483 //-killed-                 set_volume(-1, midi_volume * 2 + (midi_volume & 1));
484 //-killed-         }
485 //-killed- }
486
487 void digi_set_digi_volume( int dvolume )
488 {
489         dvolume = fixmuldiv( dvolume, _DIGI_MAX_VOLUME, 0x7fff);
490         if ( dvolume > _DIGI_MAX_VOLUME )
491                 digi_volume = _DIGI_MAX_VOLUME;
492         else if ( dvolume < 0 )
493                 digi_volume = 0;
494         else
495                 digi_volume = dvolume;
496
497         if ( !Digi_initialized ) return;
498         if ( digi_driver_board <= 0 )   return;
499
500         digi_sync_sounds();
501 }
502
503 // 0-0x7FFF
504 void digi_set_volume( int dvolume, int mvolume )
505 {
506         digi_set_midi_volume( mvolume );
507         digi_set_digi_volume( dvolume );
508 //      mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume ));
509 }
510
511 //-killed- void digi_stop_current_song()
512 //-killed- {
513 //-killed-         if (SongHandle) {
514 //-killed-                 destroy_midi(SongHandle);
515 //-killed-                 SongHandle = NULL;
516 //-killed-         }
517 //-killed- }
518 //-killed- 
519 //-killed- void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop )
520 //-killed- {
521 //-killed-         //char fname[128];
522 //-killed- 
523 //-killed-         if (!Digi_initialized) return;
524 //-killed-         if ( digi_midi_type <= 0 )      return;
525 //-killed- 
526 //-killed-         digi_stop_current_song();
527 //-killed- 
528 //-killed-         if ( filename == NULL ) return;
529 //-killed- 
530 //-killed-         strcpy( digi_last_midi_song, filename );
531 //-killed-         strcpy( digi_last_melodic_bank, melodic_bank );
532 //-killed-         strcpy( digi_last_drum_bank, drum_bank );
533 //-killed- 
534 //-killed-         if ( midi_volume < 1 )
535 //-killed- 
536 //-killed-         SongHandle = NULL;
537 //-killed- 
538 //-killed- #if 0 /* needs bank loading to sound right */
539 //-killed-         if (midi_card <= 4) { /* FM cards */
540 //-killed-                 int sl;
541 //-killed-                 sl = strlen( filename );
542 //-killed-                 strcpy( fname, filename ); 
543 //-killed-                 fname[sl-1] = 'q';
544 //-killed-                 SongHandle = load_hmp(fname);
545 //-killed-         }
546 //-killed- #endif
547 //-killed- 
548 //-killed-         if ( !SongHandle  )
549 //-killed-                 SongHandle = load_hmp(filename);
550 //-killed- 
551 //-killed-         if (SongHandle) {
552 //-killed-                 if (play_midi(SongHandle, loop)) {
553 //-killed-                         destroy_midi(SongHandle);
554 //-killed-                         SongHandle = NULL;
555 //-killed-                 }
556 //-killed-         }
557 //-killed-         if (!SongHandle) {
558 //-killed-                         mprintf( (1, "\nAllegro Error : %s", allegro_error ));
559 //-killed-         }
560 //-killed- }
561
562 void digi_get_sound_loc( vms_matrix * listener, vms_vector * listener_pos, int listener_seg, vms_vector * sound_pos, int sound_seg, fix max_volume, int *volume, int *pan, fix max_distance )
563 {         
564         vms_vector      vector_to_sound;
565         fix angle_from_ear, cosang,sinang;
566         fix distance;
567         fix path_distance;
568
569         *volume = 0;
570         *pan = 0;
571
572         max_distance = (max_distance*5)/4;              // Make all sounds travel 1.25 times as far.
573
574         //      Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the fang computation.
575         distance = vm_vec_normalized_dir_quick( &vector_to_sound, sound_pos, listener_pos );
576                 
577         if (distance < max_distance )   {
578                 int num_search_segs = f2i(max_distance/20);
579                 if ( num_search_segs < 1 ) num_search_segs = 1;
580
581                 path_distance = find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG );
582                 if ( path_distance > -1 )       {
583                         *volume = max_volume - fixdiv(path_distance,max_distance);
584                         //mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume ));
585                         if (*volume > 0 )       {
586                                 angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec);
587                                 fix_sincos(angle_from_ear,&sinang,&cosang);
588                                 //mprintf( (0, "volume is %.2f\n", f2fl(*volume) ));
589                                 if (Config_channels_reversed) cosang *= -1;
590                                 *pan = (cosang + F1_0)/2;
591                         } else {
592                                 *volume = 0;
593                         }
594                 }
595         }                                                                                                                                                                         
596 }
597
598 void digi_init_sounds()
599 {
600         int i;
601
602         if (!Digi_initialized) return;
603         if (digi_driver_board<1) return;
604
605         digi_reset_digi_sounds();
606
607         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
608                 if (digi_sounds_initialized) {
609                         if ( SoundObjects[i].flags & SOF_PLAYING )      {
610                                 deallocate_voice(SoundObjects[i].handle);
611                         }
612                 }
613                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
614         }
615         digi_sounds_initialized = 1;
616 }
617
618 void digi_start_sound_object(int i)
619 {
620         if (!Digi_initialized) return;
621         if (digi_driver_board<1) return;
622
623         // this doesn't use digi_lock_sound because these sounds are
624         // never unlocked, so we couldn't check if we unlocked all other sounds then
625         if (!dpmi_lock_region( GameSounds[SoundObjects[i].soundnum].data, GameSounds[SoundObjects[i].soundnum].len ))
626                 Error( "Error locking sound object %d\n", SoundObjects[i].soundnum );
627         
628         SoundObjects[i].signature=next_signature++;
629
630         SoundObjects[i].handle = play_sample(&GameSounds[SoundObjects[i].soundnum],
631          fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0), /* 0-255 */
632          SoundObjects[i].pan >> 8, /* 0-255 */
633          1000,
634          (SoundObjects[i].flags & SOF_PLAY_FOREVER) ? 1 : 0
635         );
636         if (SoundObjects[i].handle < 0) {
637                 mprintf(( 1, "NOT ENOUGH SOUND SLOTS!!! (SoundObject)\n" ));
638                 //digi_unlock_sound(SoundObjects[i].soundnum); //never unlocked...
639         } else {
640                 SoundObjects[i].flags |= SOF_PLAYING;
641                 reset_slots_on_channel( SoundObjects[i].handle );
642         }
643 }
644
645 int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix  max_distance )
646 {
647         int i,volume,pan;
648         object * objp;
649         int soundnum;
650
651         soundnum = digi_xlat_sound(org_soundnum);
652
653         if ( max_volume < 0 ) return -1;
654 //      if ( max_volume > F1_0 ) max_volume = F1_0;
655
656         if (!Digi_initialized) return -1;
657         if (soundnum < 0 ) return -1;
658         if (GameSounds[soundnum].data==NULL) {
659                 Int3();
660                 return -1;
661         }
662         if ((objnum<0)||(objnum>Highest_object_index))
663                 return -1;
664         if (digi_driver_board<1) return -1;
665
666         if ( !forever ) {
667                 // Hack to keep sounds from building up...
668                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum, max_volume,&volume, &pan, max_distance );
669                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
670                 return -1;
671         }
672
673         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
674                 if (SoundObjects[i].flags==0)
675                         break;
676         
677         if (i==MAX_SOUND_OBJECTS) {
678                 mprintf((1, "Too many sound objects!\n" ));
679                 return -1;
680         }
681
682         SoundObjects[i].signature=next_signature++;
683         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_OBJ;
684         if ( forever )
685                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
686         SoundObjects[i].lo_objnum = objnum;
687         SoundObjects[i].lo_objsignature = Objects[objnum].signature;
688         SoundObjects[i].max_volume = max_volume;
689         SoundObjects[i].max_distance = max_distance;
690         SoundObjects[i].volume = 0;
691         SoundObjects[i].pan = 0;
692         SoundObjects[i].soundnum = soundnum;
693
694         objp = &Objects[SoundObjects[i].lo_objnum];
695         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
696                        &objp->pos, objp->segnum, SoundObjects[i].max_volume,
697                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
698
699         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
700                digi_start_sound_object(i);
701
702         return SoundObjects[i].signature;
703 }
704
705 int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume )
706 {                                                                                                                                                                                                       // 10 segs away
707         return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0      );
708 }
709
710 int digi_link_sound_to_pos2( int org_soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance )
711 {
712         int i, volume, pan;
713         int soundnum;
714
715         soundnum = digi_xlat_sound(org_soundnum);
716
717         if ( max_volume < 0 ) return -1;
718 //      if ( max_volume > F1_0 ) max_volume = F1_0;
719
720         if (!Digi_initialized) return -1;
721         if (soundnum < 0 ) return -1;
722         if (GameSounds[soundnum].data==NULL) {
723                 Int3();
724                 return -1;
725         }
726         if (digi_driver_board<1) return -1;
727
728         if ((segnum<0)||(segnum>Highest_segment_index))
729                 return -1;
730
731         if ( !forever ) {
732                 // Hack to keep sounds from building up...
733                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, pos, segnum, max_volume, &volume, &pan, max_distance );
734                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
735                 return -1;
736         }
737
738         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
739                 if (SoundObjects[i].flags==0)
740                         break;
741         
742         if (i==MAX_SOUND_OBJECTS) {
743                 mprintf((1, "Too many sound objects!\n" ));
744                 return -1;
745         }
746
747
748         SoundObjects[i].signature=next_signature++;
749         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_POS;
750         if ( forever )
751                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
752         SoundObjects[i].lp_segnum = segnum;
753         SoundObjects[i].lp_sidenum = sidenum;
754         SoundObjects[i].lp_position = *pos;
755         SoundObjects[i].soundnum = soundnum;
756         SoundObjects[i].max_volume = max_volume;
757         SoundObjects[i].max_distance = max_distance;
758         SoundObjects[i].volume = 0;
759         SoundObjects[i].pan = 0;
760         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
761                                            &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
762                                            SoundObjects[i].max_volume,
763                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
764         
765         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
766                 digi_start_sound_object(i);
767
768         return SoundObjects[i].signature;
769 }
770
771 int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume )
772 {
773         return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 );
774 }
775
776 void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum )
777 {
778         int i,killed;
779
780         soundnum = digi_xlat_sound(soundnum);
781
782         if (!Digi_initialized) return;
783         if (digi_driver_board<1) return;
784
785         killed = 0;
786
787         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
788                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_POS) )  {
789                         if ((SoundObjects[i].lp_segnum == segnum) && (SoundObjects[i].soundnum==soundnum ) && (SoundObjects[i].lp_sidenum==sidenum) ) {
790                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
791                                         deallocate_voice(SoundObjects[i].handle);
792                                 }
793                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
794                                 killed++;
795                         }
796                 }
797         }
798         // If this assert happens, it means that there were 2 sounds
799         // that got deleted. Weird, get John.
800         if ( killed > 1 )       {
801                 mprintf( (1, "ERROR: More than 1 sounds were deleted from seg %d\n", segnum ));
802         }
803 }
804
805 void digi_kill_sound_linked_to_object( int objnum )
806 {
807         int i,killed;
808
809         if (!Digi_initialized) return;
810         if (digi_driver_board<1) return;
811
812         killed = 0;
813
814         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
815                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_OBJ ) ) {
816                         if (SoundObjects[i].lo_objnum == objnum)   {
817                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
818                                         deallocate_voice(SoundObjects[i].handle );
819                                 }
820                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
821                                 killed++;
822                         }
823                 }
824         }
825         // If this assert happens, it means that there were 2 sounds
826         // that got deleted. Weird, get John.
827         if ( killed > 1 )       {
828                 mprintf( (1, "ERROR: More than 1 sounds were deleted from object %d\n", objnum ));
829         }
830 }
831
832 void digi_sync_sounds()
833 {
834         int i;
835         int oldvolume, oldpan;
836
837         if (!Digi_initialized) return;
838         if (digi_driver_board<1) return;
839
840         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
841                 if ( SoundObjects[i].flags & SOF_USED ) {
842                         oldvolume = SoundObjects[i].volume;
843                         oldpan = SoundObjects[i].pan;
844
845                         if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) )      {
846                                 // Check if its done.
847                                 if (SoundObjects[i].flags & SOF_PLAYING) {
848                                         if (voice_get_position(SoundObjects[i].handle) < 0) {
849                                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
850                                                 continue;               // Go on to next sound...
851                                         }
852                                 }
853                         }                       
854                 
855                         if ( SoundObjects[i].flags & SOF_LINK_TO_POS )  {
856                                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
857                                                                 &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
858                                                                 SoundObjects[i].max_volume,
859                                 &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
860
861                         } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ )   {
862                                 object * objp;
863         
864                                 objp = &Objects[SoundObjects[i].lo_objnum];
865                 
866                                 if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].lo_objsignature))  {
867                                         // The object that this is linked to is dead, so just end this sound if it is looping.
868                                         if ( (SoundObjects[i].flags & SOF_PLAYING)  && (SoundObjects[i].flags & SOF_PLAY_FOREVER))      {
869                                                 deallocate_voice(SoundObjects[i].handle);
870                                         }
871                                         SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
872                                         continue;               // Go on to next sound...
873                                 } else {
874                                         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
875                                         &objp->pos, objp->segnum, SoundObjects[i].max_volume,
876                                    &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
877                                 }
878                         }
879                          
880                         if (oldvolume != SoundObjects[i].volume)        {
881                                 if ( SoundObjects[i].volume < MIN_VOLUME )       {
882                                         // Sound is too far away, so stop it from playing.
883                                         if ((SoundObjects[i].flags & SOF_PLAYING)&&(SoundObjects[i].flags & SOF_PLAY_FOREVER))  {
884                                                 deallocate_voice(SoundObjects[i].handle);
885                                                 SoundObjects[i].flags &= ~SOF_PLAYING;          // Mark sound as not playing
886                                         }
887                                 } else {
888                                         if (!(SoundObjects[i].flags & SOF_PLAYING))     {
889                                                 digi_start_sound_object(i);
890                                         } else {
891                                                 voice_set_volume(SoundObjects[i].handle, fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0));
892                                         }
893                                 }
894                         }
895                                 
896                         if (oldpan != SoundObjects[i].pan)      {
897                                 if (SoundObjects[i].flags & SOF_PLAYING)
898                                         voice_set_pan(SoundObjects[i].handle, SoundObjects[i].pan >> 8);
899                         }
900                 }
901         }
902 }
903
904 int sound_paused = 0;
905
906 void digi_pause_all()
907 {
908         int i;
909
910         if (!Digi_initialized) return;
911
912         if (sound_paused==0)    {
913 //                 if ( digi_midi_type > 0 )       {
914 //                         if (SongHandle)
915 //                                midi_pause();
916 //                }
917                 digi_midi_pause();
918                 if (digi_driver_board>0)        {
919                         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
920                                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_PLAYING)&& (SoundObjects[i].flags & SOF_PLAY_FOREVER) ) {
921                                         deallocate_voice(SoundObjects[i].handle );
922                                         SoundObjects[i].flags &= ~SOF_PLAYING;          // Mark sound as not playing
923                                 }                       
924                         }
925                 }
926         }
927         sound_paused++;
928 }
929
930 void digi_resume_all()
931 {
932         if (!Digi_initialized) return;
933
934         Assert( sound_paused > 0 );
935
936         if (sound_paused==1)    {
937                 // resume sound here
938 //                if ( digi_midi_type > 0 )       {
939 //                        if (SongHandle)
940 //                                midi_resume();
941 //                }
942                   digi_midi_resume();
943         }
944         sound_paused--;
945 }
946
947 void digi_stop_all()
948 {
949         int i;
950
951         if (!Digi_initialized) return;
952
953 //        if ( digi_midi_type > 0 )       {
954 //                if (SongHandle)  {
955 //                   destroy_midi(SongHandle);
956 //                   SongHandle = NULL;
957 //                }
958 //        }
959         digi_midi_stop();
960
961         if (digi_driver_board>0)        {
962                 for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
963                         if ( SoundObjects[i].flags & SOF_USED ) {
964                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
965                                         deallocate_voice(SoundObjects[i].handle );
966                                 }
967                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
968                         }
969                 }
970         }
971 }
972
973 #ifndef NDEBUG
974 int verify_channel_not_used_by_soundobjects( int channel )
975 {
976         int i;
977         if (digi_driver_board>0)        {
978                 for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
979                         if ( SoundObjects[i].flags & SOF_USED ) {
980                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
981                                         if ( SoundObjects[i].handle == channel )        {
982                                                 mprintf(( 0, "ERROR STARTING SOUND CHANNEL ON USED SLOT!!\n" ));
983                                                 Int3(); // Get John!
984                                         }
985                                 }
986                         }
987                 }
988         }
989         return 0;
990 }
991 #endif
992
993 #if 0 // hud sound debug info
994 #include "gr.h"
995 #include "gamefont.h"
996 #define VIRTUAL_VOICES 256
997 void show_digi_info() {
998         int i, active_slots = 0, done_slots = 0, allg_used = 0;
999
1000         for (i=0; i<DIGI_SLOTS; i++)
1001                 if (VALID_CHANNEL(SampleHandles[i])) {
1002                         active_slots++;
1003                         if (!voice_check(SampleHandles[i]))
1004                                 done_slots++;
1005                 }
1006         for (i=0; i<VIRTUAL_VOICES; i++)
1007                 if (voice_check(i))
1008                         allg_used++;
1009
1010
1011         gr_set_curfont( GAME_FONT );
1012         gr_set_fontcolor(gr_getcolor(0,31,0),-1 );
1013         gr_printf(0,32,"voices: real:%d exp:%d locks:%d sluse:%d sldone:%d aused:%d slnxt:%d",
1014          digi_driver->voices, digi_max_channels, digi_total_locks,
1015          active_slots,done_slots,allg_used, next_handle);
1016 }
1017 #endif