]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/digimm.c
fix off by .5 errors in ogl_upixelc and ogl_ulinec (d1x r1.29)
[btb/d2x.git] / arch / dos / digimm.c
1 // SDL digital audio support
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #include "mm_drv.h"
8 #include "timer.h"
9
10 //#include "SDL.h"
11 //#include "SDL_audio.h"
12
13 #include "error.h"
14 #include "mono.h"
15 #include "fix.h"
16 #include "vecmat.h"
17 #include "gr.h" // needed for piggy.h
18 #include "piggy.h"
19 #include "digi.h"
20 #include "sounds.h"
21 #include "wall.h"
22 #include "newdemo.h"
23 #include "kconfig.h"
24 #include "midiallg.h"
25
26 int digi_driver_board                                   = 0;
27 int digi_driver_port                                    = 0;
28 int digi_driver_irq                                     = 0;
29 int digi_driver_dma                                     = 0;
30 //int digi_midi_type                                    = 0;                    // Midi driver type
31 //int digi_midi_port                                    = 0;                    // Midi driver port
32 int digi_timer_rate                                     = 9943;                 // rate for the timer to go off to handle the driver system (120 Hz)
33
34 #ifndef ALLG_MIDI
35 /* stub vars/functions for midi */
36 int digi_midi_type                                      = 0;
37 int digi_midi_port                                     = 0;
38
39 void digi_set_midi_volume( int mvolume ) {}
40 void digi_play_midi_song( char * filename, char * melodic_bank,
41 char * drum_bank, int loop ) {}
42 void digi_midi_pause() {}
43 void digi_midi_resume() {}
44 void digi_midi_stop() {}
45 #endif
46
47
48 //added on 980905 by adb to add inline fixmul for mixer on i386
49 #ifdef __i386__
50 #define do_fixmul(x,y)                          \
51 ({                                              \
52         int _ax, _dx;                           \
53         asm("imull %2\n\tshrdl %3,%1,%0"        \
54             : "=a"(_ax), "=d"(_dx)              \
55             : "rm"(y), "i"(16), "0"(x));        \
56         _ax;                                    \
57 })
58 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
59 #endif
60 //end edit by adb
61
62 //changed on 980905 by adb to increase number of concurrent sounds
63 #define MAX_SOUND_SLOTS 32
64 //end changes by adb
65 #define SOUND_BUFFER_SIZE 512
66
67 #define MIN_VOLUME 10
68
69 /* This table is used to add two sound values together and pin
70  * the value to avoid overflow.  (used with permission from ARDI)
71  * DPH: Taken from SDL/src/SDL_mixer.c.
72  */
73 static const unsigned char mix8[] =
74 {
75   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
87   0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
88   0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
89   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
90   0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
91   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
92   0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
93   0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
94   0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
95   0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
96   0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
97   0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
98   0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
99   0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
100   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
101   0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
102   0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
103   0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
104   0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
105   0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
106   0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
107   0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
108   0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
109   0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
110   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
111   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
112   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
113   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
114   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
115   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
116   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
117   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
118   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
119   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
120   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
121   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
122 };
123
124 #define SOF_USED                        1               // Set if this sample is used
125 #define SOF_PLAYING                     2               // Set if this sample is playing on a channel
126 #define SOF_LINK_TO_OBJ         4               // Sound is linked to a moving object. If object dies, then finishes play and quits.
127 #define SOF_LINK_TO_POS         8               // Sound is linked to segment, pos
128 #define SOF_PLAY_FOREVER        16              // Play forever (or until level is stopped), otherwise plays once
129
130 typedef struct sound_object {
131         short           signature;              // A unique signature to this sound
132         ubyte           flags;                  // Used to tell if this slot is used and/or currently playing, and how long.
133         fix             max_volume;             // Max volume that this sound is playing at
134         fix             max_distance;           // The max distance that this sound can be heard at...
135         int             volume;                 // Volume that this sound is playing at
136         int             pan;                    // Pan value that this sound is playing at
137         int             handle;                 // What handle this sound is playing on.  Valid only if SOF_PLAYING is set.
138         short           soundnum;               // The sound number that is playing
139         union { 
140                 struct {
141                         short           segnum;                         // Used if SOF_LINK_TO_POS field is used
142                         short           sidenum;
143                         vms_vector      position;
144                 }pos;
145                 struct {
146                         short            objnum;                         // Used if SOF_LINK_TO_OBJ field is used
147                         short            objsignature;
148                 }obj;
149         }link;
150 } sound_object;
151 #define lp_segnum link.pos.segnum
152 #define lp_sidenum link.pos.sidenum
153 #define lp_position link.pos.position
154
155 #define lo_objnum link.obj.objnum
156 #define lo_objsignature link.obj.objsignature
157
158 #define MAX_SOUND_OBJECTS 16
159 sound_object SoundObjects[MAX_SOUND_OBJECTS];
160 short next_signature=0;
161
162 //added/changed on 980905 by adb to make sfx volume work
163 #define SOUND_MAX_VOLUME (F1_0/2) // don't use real max like in original
164 int digi_volume = SOUND_MAX_VOLUME;
165 //end edit by adb
166
167 int digi_lomem = 0;
168
169 static int digi_initialised = 0;
170 static int timer_system_initialized = 0;
171
172 struct sound_slot {
173  int soundno;
174  int playing;   // Is there a sample playing on this channel?
175  int looped;    // Play this sample looped?
176  fix pan;       // 0 = far left, 1 = far right
177  fix volume;    // 0 = nothing, 1 = fully on
178  //changed on 980905 by adb from char * to unsigned char * 
179  unsigned char *samples;
180  //end changes by adb
181  unsigned int length; // Length of the sample
182  unsigned int position; // Position we are at at the moment.
183 } SoundSlots[MAX_SOUND_SLOTS];
184
185 //static SDL_AudioSpec WaveSpec;
186 static int digi_sounds_initialized = 0;
187
188 //added on 980905 by adb to add rotating/volume based sound kill system
189 static int digi_max_channels = 16;
190 static int next_handle = 0;
191 int SampleHandles[32];
192 void reset_sounds_on_channel(int channel);
193 //end edit by adb
194
195 void digi_reset_digi_sounds(void);
196
197 /* Audio mixing callback */
198 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
199 ULONG VC_WriteBytes(SBYTE *stream, ULONG len)
200 {
201  unsigned char *streamend;
202  struct sound_slot *sl;
203
204 //    if (grd_curscreen)
205 //        grd_curscreen->sc_canvas.cv_bitmap.bm_data[8]++;
206  len &= ~1; /* stereo -> always write 2 byte pairs */
207  streamend = stream + len;
208
209 #if 0
210 {
211  static int n = 0;
212  while(stream < streamend) {
213     *(stream++) = (n & 256) ? 256 - (n & 255) : (n & 255);
214     n++;
215  }
216  return len;
217 }
218 #endif
219
220  memset(stream, 0x80, len);
221
222  for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
223  {
224   if (sl->playing)
225   {
226    unsigned char *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
227    unsigned char *sp = stream;
228    signed char v;
229    fix vl, vr;
230    int x;
231
232    if ((x = sl->pan) & 0x8000)
233    {
234     vl = 0x20000 - x * 2;
235     vr = 0x10000;
236    }
237    else
238    {
239     vl = 0x10000;
240     vr = x * 2;
241    }
242    vl = fixmul(vl, (x = sl->volume));
243    vr = fixmul(vr, x);
244    while (sp < streamend) 
245    {
246     if (sldata == slend)
247     {
248      if (!sl->looped)
249      {
250       sl->playing = 0;
251       break;
252      }
253      sldata = sl->samples;
254     }
255     v = *(sldata++) - 0x80;
256     *(sp++) = mix8[ *sp + fixmul(v, vl) + 0x80 ];
257     *(sp++) = mix8[ *sp + fixmul(v, vr) + 0x80 ];
258    }
259    sl->position = sldata - sl->samples;
260   }
261  }
262  return len;
263 }
264 //end changes by adb
265
266 extern MDRIVER drv_sb;
267 MDRIVER *drv = &drv_sb;
268 char allegro_error[128];
269
270 int md_mode = DMODE_STEREO;
271 int md_mixfreq = digi_sample_rate; //11025;
272 int md_dmabufsize = 1024;
273
274 void install_int_ex(void (*)(), long speed);
275 void remove_int(void(*)());
276
277 void mm_timer() {
278     drv->Update();
279 //    if (grd_curscreen)
280 //        (*grd_curscreen->sc_canvas.cv_bitmap.bm_data)++;
281 }
282
283 /* Initialise audio devices. */
284 int digi_init()
285 {
286  //added on 980905 by adb to init sound kill system
287  memset(SampleHandles, 255, sizeof(SampleHandles));
288  //end edit by adb
289
290  #if 0
291  WaveSpec.freq = digi_sample_rate; //11025;
292  WaveSpec.format = AUDIO_U8 | AUDIO_STEREO;
293  WaveSpec.samples = SOUND_BUFFER_SIZE;
294  WaveSpec.callback = audio_mixcallback;
295
296  if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) {
297   printf("Couldn't open audio: %s\n", SDL_GetError());
298   exit(2);
299  }
300  SDL_PauseAudio(0);
301 #endif
302  if (!drv->Init()) {
303         printf("Couldn't open audio: %s", myerr);
304         return -1;
305  }
306  drv->PlayStart();
307
308  if (!timer_system_initialized)
309  {
310   #ifdef ALLG_MIDI
311   install_int_ex(mm_timer, digi_timer_rate);
312   #else
313   timer_set_function(mm_timer);
314   #endif
315   timer_system_initialized = 1;
316  }
317
318  #ifdef ALLG_MIDI
319  digi_midi_init();
320  #endif
321
322  atexit(digi_close);
323  digi_initialised = 1;
324  return 0;
325 }
326
327 /* Toggle audio */
328 void digi_reset() { }
329
330 /* Shut down audio */
331 void digi_close()
332 {
333  if (!digi_initialised) return;
334  digi_initialised = 0;
335  drv->PlayStop();
336  drv->Exit();
337  if (timer_system_initialized)
338  {
339   #ifdef ALLG_MIDI
340   remove_int(mm_timer);
341   #else
342   timer_set_function(NULL);
343   #endif
344   timer_system_initialized = 0;
345  }
346  #ifdef ALLG_MIDI
347  digi_midi_close();
348  #endif
349 }
350
351 /* Find the sound which actually equates to a sound number */
352 int digi_xlat_sound(int soundno)
353 {
354         if ( soundno < 0 ) return -1;
355
356         if ( digi_lomem )       {
357                 soundno = AltSounds[soundno];
358                 if ( soundno == 255 ) return -1;
359         }
360         return Sounds[soundno];
361 }
362
363 static int get_free_slot()
364 {
365  int i;
366  for (i=0; i<MAX_SOUND_SLOTS; i++)
367  {
368   if (!SoundSlots[i].playing) return i;
369  }
370  return -1;
371 }
372
373 int digi_start_sound(int soundnum, fix volume, fix pan)
374 {
375  int ntries;
376  int slot;
377
378  if (!digi_initialised) return -1;
379
380  //added on 980905 by adb from original source to add sound kill system
381  // play at most digi_max_channel samples, if possible kill sample with low volume
382  ntries = 0;
383
384 TryNextChannel:
385  if ( (SampleHandles[next_handle] >= 0) && (SoundSlots[SampleHandles[next_handle]].playing)  )
386  {
387   if ( (SoundSlots[SampleHandles[next_handle]].volume > digi_volume) && (ntries<digi_max_channels) )
388   {
389    //mprintf(( 0, "Not stopping loud sound %d.\n", next_handle ));
390    next_handle++;
391    if ( next_handle >= digi_max_channels )
392     next_handle = 0;
393    ntries++;
394    goto TryNextChannel;
395   }
396   //mprintf(( 0, "[SS:%d]", next_handle ));
397   SoundSlots[SampleHandles[next_handle]].playing = 0;
398   SampleHandles[next_handle] = -1;
399  }
400  //end edit by adb
401
402  slot = get_free_slot();
403  if (slot<0) return -1;
404
405  if (volume > F2_0)
406   volume = F2_0;
407  SoundSlots[slot].soundno = soundnum;
408  SoundSlots[slot].samples = GameSounds[soundnum].data;
409  SoundSlots[slot].length = GameSounds[soundnum].length;
410  SoundSlots[slot].volume = fixmul(digi_volume, volume);
411  SoundSlots[slot].pan = pan;
412  SoundSlots[slot].position = 0;
413  SoundSlots[slot].looped = 0;
414  SoundSlots[slot].playing = 1;
415
416  //added on 980905 by adb to add sound kill system from original sos digi.c
417  reset_sounds_on_channel(slot);
418  SampleHandles[next_handle] = slot;
419  next_handle++;
420  if ( next_handle >= digi_max_channels )
421   next_handle = 0;
422  //end edit by adb
423
424  return slot;
425 }
426
427  //added on 980905 by adb to add sound kill system from original sos digi.c
428 void reset_sounds_on_channel( int channel )
429 {
430  int i;
431
432  for (i=0; i<digi_max_channels; i++)
433   if (SampleHandles[i] == channel)
434    SampleHandles[i] = -1;
435 }
436 //end edit by adb
437
438 int digi_start_sound_object(int obj)
439 {
440  int slot;
441
442  if (!digi_initialised) return -1;
443  slot = get_free_slot();
444
445  if (slot<0) return -1;
446
447
448  SoundSlots[slot].soundno = SoundObjects[obj].soundnum;
449  SoundSlots[slot].samples = GameSounds[SoundObjects[obj].soundnum].data;
450  SoundSlots[slot].length = GameSounds[SoundObjects[obj].soundnum].length;
451  SoundSlots[slot].volume = fixmul(digi_volume, SoundObjects[obj].volume);
452  SoundSlots[slot].pan = SoundObjects[obj].pan;
453  SoundSlots[slot].position = 0;
454  SoundSlots[slot].looped = (SoundObjects[obj].flags & SOF_PLAY_FOREVER);
455  SoundSlots[slot].playing = 1;
456
457  SoundObjects[obj].signature = next_signature++;
458  SoundObjects[obj].handle = slot;
459
460  SoundObjects[obj].flags |= SOF_PLAYING;
461  //added on 980905 by adb to add sound kill system from original sos digi.c
462  reset_sounds_on_channel(slot);
463  //end edit by adb
464  
465  return 0;
466 }
467
468
469 // Play the given sound number.
470 // Volume is max at F1_0.
471 void digi_play_sample( int soundno, fix max_volume )
472 {
473 #ifdef NEWDEMO
474         if ( Newdemo_state == ND_STATE_RECORDING )
475                 newdemo_record_sound( soundno );
476 #endif
477         soundno = digi_xlat_sound(soundno);
478
479         if (!digi_initialised) return;
480
481         if (soundno < 0 ) return;
482
483         digi_start_sound(soundno, max_volume, F0_5);
484 }
485
486 // Play the given sound number. If the sound is already playing,
487 // restart it.
488 void digi_play_sample_once( int soundno, fix max_volume )
489 {
490         int i;
491
492 #ifdef NEWDEMO
493         if ( Newdemo_state == ND_STATE_RECORDING )
494                 newdemo_record_sound( soundno );
495 #endif
496         soundno = digi_xlat_sound(soundno);
497
498         if (!digi_initialised) return;
499
500         if (soundno < 0 ) return;
501
502         for (i=0; i < MAX_SOUND_SLOTS; i++)
503           if (SoundSlots[i].soundno == soundno)
504             SoundSlots[i].playing = 0;
505         digi_start_sound(soundno, max_volume, F0_5);
506
507 }
508
509 void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups ) // Volume from 0-0x7fff
510 {
511         no_dups = 1;
512
513 #ifdef NEWDEMO
514         if ( Newdemo_state == ND_STATE_RECORDING )              {
515                 if ( no_dups )
516                         newdemo_record_sound_3d_once( soundno, angle, volume );
517                 else
518                         newdemo_record_sound_3d( soundno, angle, volume );
519         }
520 #endif
521         soundno = digi_xlat_sound(soundno);
522
523         if (!digi_initialised) return;
524         if (soundno < 0 ) return;
525
526         if (volume < MIN_VOLUME ) return;
527         digi_start_sound(soundno, volume, angle);
528 }
529
530 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 )
531 {         
532         vms_vector      vector_to_sound;
533         fix angle_from_ear, cosang,sinang;
534         fix distance;
535         fix path_distance;
536
537         *volume = 0;
538         *pan = 0;
539
540         max_distance = (max_distance*5)/4;              // Make all sounds travel 1.25 times as far.
541
542         //      Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the fang computation.
543         distance = vm_vec_normalized_dir_quick( &vector_to_sound, sound_pos, listener_pos );
544                 
545         if (distance < max_distance )   {
546                 int num_search_segs = f2i(max_distance/20);
547                 if ( num_search_segs < 1 ) num_search_segs = 1;
548
549                 path_distance = find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG );
550                 if ( path_distance > -1 )       {
551                         *volume = max_volume - fixdiv(path_distance,max_distance);
552                         //mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume ));
553                         if (*volume > 0 )       {
554                                 angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec);
555                                 fix_sincos(angle_from_ear,&sinang,&cosang);
556                                 //mprintf( (0, "volume is %.2f\n", f2fl(*volume) ));
557                                 if (Config_channels_reversed) cosang *= -1;
558                                 *pan = (cosang + F1_0)/2;
559                         } else {
560                                 *volume = 0;
561                         }
562                 }
563         }                                                                                                                                                                         
564 }
565
566 int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix  max_distance )
567 {
568         int i,volume,pan;
569         object * objp;
570         int soundnum;
571
572         soundnum = digi_xlat_sound(org_soundnum);
573
574         if ( max_volume < 0 ) return -1;
575 //      if ( max_volume > F1_0 ) max_volume = F1_0;
576
577         if (!digi_initialised) return -1;
578         if (soundnum < 0 ) return -1;
579         if (GameSounds[soundnum].data==NULL) {
580                 Int3();
581                 return -1;
582         }
583         if ((objnum<0)||(objnum>Highest_object_index))
584                 return -1;
585
586         if ( !forever ) {
587                 // Hack to keep sounds from building up...
588                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum, max_volume,&volume, &pan, max_distance );
589                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
590                 return -1;
591         }
592
593         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
594                 if (SoundObjects[i].flags==0)
595                    break;
596
597         if (i==MAX_SOUND_OBJECTS) {
598                 mprintf((1, "Too many sound objects!\n" ));
599                 return -1;
600         }
601
602         SoundObjects[i].signature=next_signature++;
603         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_OBJ;
604         if ( forever )
605                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
606         SoundObjects[i].lo_objnum = objnum;
607         SoundObjects[i].lo_objsignature = Objects[objnum].signature;
608         SoundObjects[i].max_volume = max_volume;
609         SoundObjects[i].max_distance = max_distance;
610         SoundObjects[i].volume = 0;
611         SoundObjects[i].pan = 0;
612         SoundObjects[i].soundnum = soundnum;
613
614         objp = &Objects[SoundObjects[i].lo_objnum];
615         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
616                        &objp->pos, objp->segnum, SoundObjects[i].max_volume,
617                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
618
619         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
620                digi_start_sound_object(i);
621
622         return SoundObjects[i].signature;
623 }
624
625 int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume )
626 { return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0); }
627
628 int digi_link_sound_to_pos2( int org_soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance )
629 {
630         int i, volume, pan;
631         int soundnum;
632
633         soundnum = digi_xlat_sound(org_soundnum);
634
635         if ( max_volume < 0 ) return -1;
636 //      if ( max_volume > F1_0 ) max_volume = F1_0;
637
638         if (!digi_initialised) return -1;
639         if (soundnum < 0 ) return -1;
640         if (GameSounds[soundnum].data==NULL) {
641                 Int3();
642                 return -1;
643         }
644
645         if ((segnum<0)||(segnum>Highest_segment_index))
646                 return -1;
647
648         if ( !forever ) {
649                 // Hack to keep sounds from building up...
650                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, pos, segnum, max_volume, &volume, &pan, max_distance );
651                 digi_play_sample_3d( org_soundnum, pan, volume, 0 );
652                 return -1;
653         }
654
655         for (i=0; i<MAX_SOUND_OBJECTS; i++ )
656                 if (SoundObjects[i].flags==0)
657                         break;
658         
659         if (i==MAX_SOUND_OBJECTS) {
660                 mprintf((1, "Too many sound objects!\n" ));
661                 return -1;
662         }
663
664
665         SoundObjects[i].signature=next_signature++;
666         SoundObjects[i].flags = SOF_USED | SOF_LINK_TO_POS;
667         if ( forever )
668                 SoundObjects[i].flags |= SOF_PLAY_FOREVER;
669         SoundObjects[i].lp_segnum = segnum;
670         SoundObjects[i].lp_sidenum = sidenum;
671         SoundObjects[i].lp_position = *pos;
672         SoundObjects[i].soundnum = soundnum;
673         SoundObjects[i].max_volume = max_volume;
674         SoundObjects[i].max_distance = max_distance;
675         SoundObjects[i].volume = 0;
676         SoundObjects[i].pan = 0;
677         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
678                                            &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
679                                            SoundObjects[i].max_volume,
680                        &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
681         
682         if (!forever || SoundObjects[i].volume >= MIN_VOLUME)
683                 digi_start_sound_object(i);
684
685         return SoundObjects[i].signature;
686 }
687
688 int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume )
689 {
690         return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 );
691 }
692
693 void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum )
694 {
695         int i,killed;
696
697         soundnum = digi_xlat_sound(soundnum);
698
699         if (!digi_initialised) return;
700
701         killed = 0;
702
703         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
704                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_POS) )  {
705                         if ((SoundObjects[i].lp_segnum == segnum) && (SoundObjects[i].soundnum==soundnum ) && (SoundObjects[i].lp_sidenum==sidenum) ) {
706                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
707                                         SoundSlots[SoundObjects[i].handle].playing = 0;
708                                 }
709                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
710                                 killed++;
711                         }
712                 }
713         }
714         // If this assert happens, it means that there were 2 sounds
715         // that got deleted. Weird, get John.
716         if ( killed > 1 )       {
717                 mprintf( (1, "ERROR: More than 1 sounds were deleted from seg %d\n", segnum ));
718         }
719 }
720
721 void digi_kill_sound_linked_to_object( int objnum )
722 {
723         int i,killed;
724
725         if (!digi_initialised) return;
726
727         killed = 0;
728
729         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
730                 if ( (SoundObjects[i].flags & SOF_USED) && (SoundObjects[i].flags & SOF_LINK_TO_OBJ ) ) {
731                         if (SoundObjects[i].lo_objnum == objnum)   {
732                                 if ( SoundObjects[i].flags & SOF_PLAYING )      {
733                                      SoundSlots[SoundObjects[i].handle].playing = 0;
734                                 }
735                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
736                                 killed++;
737                         }
738                 }
739         }
740         // If this assert happens, it means that there were 2 sounds
741         // that got deleted. Weird, get John.
742         if ( killed > 1 )       {
743                 mprintf( (1, "ERROR: More than 1 sounds were deleted from object %d\n", objnum ));
744         }
745 }
746
747 void digi_sync_sounds()
748 {
749         int i;
750         int oldvolume, oldpan;
751
752         if (!digi_initialised) return;
753
754         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
755                 if ( SoundObjects[i].flags & SOF_USED ) {
756                         oldvolume = SoundObjects[i].volume;
757                         oldpan = SoundObjects[i].pan;
758
759                         if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) )      {
760                                 // Check if its done.
761                                 if (SoundObjects[i].flags & SOF_PLAYING) {
762                                         if (!SoundSlots[SoundObjects[i].handle].playing) {
763                                                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
764                                                 continue;               // Go on to next sound...
765                                         }
766                                 }
767                         }                       
768                 
769                         if ( SoundObjects[i].flags & SOF_LINK_TO_POS )  {
770                                 digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
771                                                                 &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum,
772                                                                 SoundObjects[i].max_volume,
773                                 &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
774
775                         } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ )   {
776                                 object * objp;
777         
778                                 objp = &Objects[SoundObjects[i].lo_objnum];
779                 
780                                 if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].lo_objsignature))  {
781                                         // The object that this is linked to is dead, so just end this sound if it is looping.
782                                         if ( (SoundObjects[i].flags & SOF_PLAYING)  && (SoundObjects[i].flags & SOF_PLAY_FOREVER))      {
783                                              SoundSlots[SoundObjects[i].handle].playing = 0;
784                                         }
785                                         SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
786                                         continue;               // Go on to next sound...
787                                 } else {
788                                         digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, 
789                                         &objp->pos, objp->segnum, SoundObjects[i].max_volume,
790                                    &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance );
791                                 }
792                         }
793                          
794                         if (oldvolume != SoundObjects[i].volume)        {
795                                 if ( SoundObjects[i].volume < MIN_VOLUME )       {
796                                         // Sound is too far away, so stop it from playing.
797                                         if ((SoundObjects[i].flags & SOF_PLAYING)&&(SoundObjects[i].flags & SOF_PLAY_FOREVER))  {
798                                                 SoundSlots[SoundObjects[i].handle].playing = 0;
799                                                 SoundObjects[i].flags &= ~SOF_PLAYING;          // Mark sound as not playing
800                                         }
801                                 } else {
802                                         if (!(SoundObjects[i].flags & SOF_PLAYING))     {
803                                                 digi_start_sound_object(i);
804                                         } else {
805                                                 SoundSlots[SoundObjects[i].handle].volume = fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0);
806                                         }
807                                 }
808                         }
809                                 
810                         if (oldpan != SoundObjects[i].pan)      {
811                                 if (SoundObjects[i].flags & SOF_PLAYING)
812                                         SoundSlots[SoundObjects[i].handle].pan = SoundObjects[i].pan;
813                         }
814                 }
815         }
816 }
817
818 void digi_stop_soundobjects() {
819         int i;
820
821         for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
822                 if (digi_sounds_initialized) {
823                         if ( SoundObjects[i].flags & SOF_PLAYING )      {
824                                 SoundSlots[SoundObjects[i].handle].playing=0;
825                         }
826                 }
827                 SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
828         }
829 }
830
831 void digi_init_sounds()
832 {
833 //        int i;
834
835         if (!digi_initialised) return;
836
837         digi_reset_digi_sounds();
838
839 //        for (i=0; i<MAX_SOUND_OBJECTS; i++ )    {
840 //                if (digi_sounds_initialized) {
841 //                        if ( SoundObjects[i].flags & SOF_PLAYING )      {
842 //                                SoundSlots[SoundObjects[i].handle].playing=0;
843 //                        }
844 //                }
845 //                SoundObjects[i].flags = 0;      // Mark as dead, so some other sound can use this sound
846 //        }
847         digi_stop_soundobjects();
848
849         digi_sounds_initialized = 1;
850 }
851
852 //added on 980905 by adb from original source to make sfx volume work
853 void digi_set_digi_volume( int dvolume )
854 {
855         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
856         if ( dvolume > SOUND_MAX_VOLUME )
857                 digi_volume = SOUND_MAX_VOLUME;
858         else if ( dvolume < 0 )
859                 digi_volume = 0;
860         else
861                 digi_volume = dvolume;
862
863         if ( !digi_initialised ) return;
864
865         digi_sync_sounds();
866 }
867 //end edit by adb
868
869 //void digi_set_volume( int dvolume, int mvolume ) {}
870 void digi_set_volume( int dvolume, int mvolume )
871 {
872  digi_set_midi_volume(mvolume);
873  digi_set_digi_volume(dvolume);
874 }
875
876
877 int digi_is_sound_playing(int soundno)
878 {
879         int i;
880
881         soundno = digi_xlat_sound(soundno);
882
883         for (i = 0; i < MAX_SOUND_SLOTS; i++)
884                   //changed on 980905 by adb: added SoundSlots[i].playing &&
885                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
886                   //end changes by adb
887                         return 1;
888         return 0;
889 }
890
891
892 //void digi_pause_all() { }
893 //void digi_resume_all() { }
894 //void digi_stop_all() { }
895
896  //added on 980905 by adb to make sound channel setting work
897 void digi_set_max_channels(int n) { 
898         digi_max_channels       = n;
899
900         if ( digi_max_channels < 1 ) 
901                 digi_max_channels = 1;
902         if ( digi_max_channels > (MAX_SOUND_SLOTS-MAX_SOUND_OBJECTS) ) 
903                 digi_max_channels = (MAX_SOUND_SLOTS-MAX_SOUND_OBJECTS);
904
905         if ( !digi_initialised ) return;
906
907         digi_reset_digi_sounds();
908 }
909
910 int digi_get_max_channels() { 
911         return digi_max_channels; 
912 }
913 // end edit by adb
914
915 void digi_reset_digi_sounds()
916 {
917  int i;
918
919  for (i=0; i< MAX_SOUND_SLOTS; i++)
920   SoundSlots[i].playing=0;
921  
922  //added on 980905 by adb to reset sound kill system
923  memset(SampleHandles, 255, sizeof(SampleHandles));
924  next_handle = 0;
925  //end edit by adb
926 }
927
928 int sound_paused = 0;
929
930 void digi_pause_all()
931 {
932        if (!digi_initialised) return;
933        if (sound_paused==0)   {
934                digi_midi_pause();
935                digi_stop_soundobjects();
936        }
937        sound_paused++;
938 }
939
940 void digi_resume_all()
941 {
942        if (!digi_initialised) return;
943
944        Assert( sound_paused > 0 );
945
946        if (sound_paused==1)    {
947                digi_midi_resume();
948        }
949        sound_paused--;
950 }
951
952 void digi_stop_all()
953 {
954        if (!digi_initialised) return;
955
956        digi_midi_stop();
957
958        digi_stop_soundobjects();
959 }
960
961 // mikmod stubs...
962 BOOL    VC_Init(void) { return 1; }
963 void    VC_Exit(void) { }
964 BOOL    VC_SetNumVoices(void) { return 0; }
965 ULONG   VC_SampleSpace(int type) { return 0; }
966 ULONG   VC_SampleLength(int type, SAMPLE *s) { return 0; }
967
968 BOOL    VC_PlayStart(void) { return 0; }
969 void    VC_PlayStop(void) { }
970
971 #if 0
972 SWORD   VC_SampleLoad(SAMPLOAD *sload, int type, FILE *fp) { return 0; }
973 #else
974 SWORD   VC_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags) { return 0; }
975 #endif
976 void    VC_SampleUnload(SWORD handle) { }
977
978 void    VC_WriteSamples(SBYTE *buf,ULONG todo) { }
979 void    VC_SilenceBytes(SBYTE *buf,ULONG todo) { }
980
981 #if 0
982 void    VC_VoiceSetVolume(UBYTE voice, UWORD vol) { }
983 void    VC_VoiceSetPanning(UBYTE voice, ULONG pan) { }
984 #else
985 void    VC_VoiceSetVolume(UBYTE voice, UBYTE vol) { }
986 void    VC_VoiceSetPanning(UBYTE voice, UBYTE pan) { }
987 #endif
988 void    VC_VoiceSetFrequency(UBYTE voice, ULONG frq) { }
989 void    VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags) { }
990
991 void    VC_VoiceStop(UBYTE voice) { }
992 BOOL    VC_VoiceStopped(UBYTE voice) { return 0; }
993 void    VC_VoiceReleaseSustain(UBYTE voice) { }
994 SLONG   VC_VoiceGetPosition(UBYTE voice) { return 0; }
995 ULONG   VC_VoiceRealVolume(UBYTE voice) { return 0; }
996 char *myerr;