]> icculus.org git repositories - btb/d2x.git/blob - arch/win32/digi.c
Rename include/error.h to include/dxxerror.h
[btb/d2x.git] / arch / win32 / digi.c
1 #define DIGI_SOUND
2 #define MIDI_SOUND
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #define WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9 #include <mmsystem.h>
10 #include <dsound.h>
11
12 #include <math.h>
13
14 #include "dxxerror.h"
15 #include "mono.h"
16 #include "fix.h"
17 #include "gr.h" // needed for piggy.h
18 #include "inferno.h"
19 #include "hmpfile.h"
20
21 #include "altsound.h"
22
23
24 hmp_file *hmp = NULL;
25
26 #ifdef DIGI_SOUND
27 #define MAX_SOUND_SLOTS 32
28 #define MIN_VOLUME 10
29
30
31 //added/changed on 980905 by adb to make sfx volume work
32 #define SOUND_MAX_VOLUME F1_0
33 int digi_volume = SOUND_MAX_VOLUME;
34 //end edit by adb
35
36 LPDIRECTSOUND lpds;
37 WAVEFORMATEX waveformat;
38 DSBUFFERDESC dsbd;
39
40 extern HWND g_hWnd;
41
42 struct sound_slot {
43  int soundno;
44  int playing;   // Is there a sample playing on this channel?
45  int looped;    // Play this sample looped?
46  fix pan;       // 0 = far left, 1 = far right
47  fix volume;    // 0 = nothing, 1 = fully on
48  //changed on 980905 by adb from char * to unsigned char * 
49  unsigned char *samples;
50  //end changes by adb
51  unsigned int length; // Length of the sample
52  unsigned int position; // Position we are at at the moment.
53  LPDIRECTSOUNDBUFFER lpsb;
54 } SoundSlots[MAX_SOUND_SLOTS];
55
56
57 int midi_volume = 255;
58 int digi_midi_song_playing = 0;
59 int digi_last_midi_song = 0;
60 int digi_last_midi_song_loop = 0;
61
62 static int Digi_initialized = 0;
63 static int digi_atexit_initialised=0;
64
65 //added on 980905 by adb to add rotating/volume based sound kill system
66 static int digi_max_channels = 16;
67 static int next_handle = 0;
68 int SampleHandles[32];
69 void reset_sounds_on_channel(int channel);
70 //end edit by adb
71
72 void digi_reset_digi_sounds(void);
73
74 void digi_reset() { }
75
76 void digi_close(void)
77 {
78         if(Digi_initialized)
79         {
80                 digi_reset_digi_sounds();
81                 IDirectSound_Release(lpds);
82         }
83         Digi_initialized = 0;
84 }
85
86 /* Initialise audio devices. */
87 int digi_init()
88 {
89  HRESULT hr;
90  
91  if (!Digi_initialized && g_hWnd){
92
93          memset(&waveformat, 0, sizeof(waveformat));
94          waveformat.wFormatTag=WAVE_FORMAT_PCM;
95          waveformat.wBitsPerSample=8;
96          waveformat.nChannels = 1;
97          waveformat.nSamplesPerSec = digi_sample_rate; //11025;
98          waveformat.nBlockAlign = waveformat.nChannels * (waveformat.wBitsPerSample / 8);
99          waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;
100
101           if ((hr = DirectSoundCreate(NULL, &lpds, NULL)) != DS_OK)
102            return -1;
103
104           if ((hr = IDirectSound_SetCooperativeLevel(lpds, g_hWnd, DSSCL_PRIORITY)) //hWndMain
105                != DS_OK)
106            {
107             IDirectSound_Release(lpds);
108             return -1;
109            }
110         
111          memset(&dsbd, 0, sizeof(dsbd));
112          dsbd.dwSize = sizeof(dsbd);
113          dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2;
114          dsbd.dwBufferBytes = 8192;
115          dsbd.dwReserved=0;
116          dsbd.lpwfxFormat = &waveformat;
117
118          Digi_initialized = 1;
119 }
120
121         if (!digi_atexit_initialised){
122                 atexit(digi_close);
123                 digi_atexit_initialised=1;
124         }
125  return 0;
126 }
127
128 // added 2000/01/15 Matt Mueller -- remove some duplication (and fix a big memory leak, in the kill=0 one case)
129 static int DS_release_slot(int slot, int kill)
130 {
131         if (SoundSlots[slot].lpsb)
132         {
133                 DWORD s;
134
135                 IDirectSoundBuffer_GetStatus(SoundSlots[slot].lpsb, &s);
136                 if (s & DSBSTATUS_PLAYING)
137                 {
138                         if (kill)
139                                 IDirectSoundBuffer_Stop(SoundSlots[slot].lpsb);
140                         else
141                                 return 0;
142                 }
143                 IDirectSoundBuffer_Release(SoundSlots[slot].lpsb);
144                 SoundSlots[slot].lpsb = NULL;
145         }
146         SoundSlots[slot].playing = 0;
147         return 1;
148 }
149
150 void digi_stop_all_channels()
151 {
152         int i;
153
154         for (i = 0; i < MAX_SOUND_SLOTS; i++)
155                 digi_stop_sound(i);
156 }
157
158
159 static int get_free_slot()
160 {
161  int i;
162
163  for (i=0; i<MAX_SOUND_SLOTS; i++)
164  {
165                 if (DS_release_slot(i, 0))
166                         return i;
167  }
168  return -1;
169 }
170
171 int D1vol2DSvol(fix d1v){
172 //multiplying by 1.5 doesn't help.  DirectSound uses dB for volume, rather than a linear scale like d1 wants.
173 //I had to pull out a math book, but here is the code to fix it :)  -Matt Mueller
174 //log x=y  <==>  x=a^y  
175 //   a
176          if (d1v<=0)
177                  return -10000;
178          else
179 //               return log2(f2fl(d1v))*1000;//no log2? hm.
180                  return log(f2fl(d1v))/log(2)*1000.0;
181 }
182
183 // Volume 0-F1_0
184 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
185 {
186  int ntries;
187  int slot;
188  HRESULT hr;
189
190         if (!Digi_initialized)
191                 return -1;
192
193         // added on 980905 by adb from original source to add sound kill system
194         // play at most digi_max_channel samples, if possible kill sample with low volume
195         ntries = 0;
196
197 TryNextChannel:
198         if ((SampleHandles[next_handle] >= 0) && (SoundSlots[SampleHandles[next_handle]].playing))
199         {
200                 if ((SoundSlots[SampleHandles[next_handle]].volume > digi_volume) && (ntries < digi_max_channels))
201                 {
202                         //mprintf((0, "Not stopping loud sound %d.\n", next_handle));
203                         next_handle++;
204                         if (next_handle >= digi_max_channels)
205                                 next_handle = 0;
206                         ntries++;
207                         goto TryNextChannel;
208                 }
209                 //mprintf((0, "[SS:%d]", next_handle));
210                 SampleHandles[next_handle] = -1;
211         }
212         // end edit by adb
213
214         slot = get_free_slot();
215         if (slot < 0)
216                 return -1;
217
218         SoundSlots[slot].soundno = soundnum;
219         SoundSlots[slot].samples = Sounddat(soundnum)->data;
220         SoundSlots[slot].length = Sounddat(soundnum)->length;
221         SoundSlots[slot].volume = fixmul(digi_volume, volume);
222         SoundSlots[slot].pan = pan;
223         SoundSlots[slot].position = 0;
224         SoundSlots[slot].looped = 0;
225         SoundSlots[slot].playing = 1;
226
227         memset(&waveformat, 0, sizeof(waveformat));
228         waveformat.wFormatTag = WAVE_FORMAT_PCM;
229         waveformat.wBitsPerSample = Sounddat(soundnum)->bits;
230         waveformat.nChannels = 1;
231         waveformat.nSamplesPerSec = Sounddat(soundnum)->freq; //digi_sample_rate;
232         waveformat.nBlockAlign = waveformat.nChannels * (waveformat.wBitsPerSample / 8);
233         waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;
234
235         memset(&dsbd, 0, sizeof(dsbd));
236         dsbd.dwSize = sizeof(dsbd);
237         dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2;
238         dsbd.dwReserved=0;
239         dsbd.dwBufferBytes = SoundSlots[slot].length;
240         dsbd.lpwfxFormat = &waveformat;
241
242         hr = IDirectSound_CreateSoundBuffer(lpds, &dsbd, &SoundSlots[slot].lpsb, NULL);
243         if (hr != DS_OK)
244         {
245                 printf("Createsoundbuffer failed! hr=0x%X\n", (int)hr);
246                 abort();
247         }
248
249         {
250                 void *ptr1, *ptr2;
251                 DWORD len1, len2;
252
253                 IDirectSoundBuffer_Lock(SoundSlots[slot].lpsb, 0, Sounddat(soundnum)->length,
254                                         &ptr1, &len1, &ptr2, &len2, 0);
255                 memcpy(ptr1, Sounddat(soundnum)->data, MIN(len1, Sounddat(soundnum)->length));
256                 IDirectSoundBuffer_Unlock(SoundSlots[slot].lpsb, ptr1, len1, ptr2, len2);
257         }
258
259         IDirectSoundBuffer_SetPan(SoundSlots[slot].lpsb, ((int)(f2fl(pan) * 20000.0)) - 10000);
260         IDirectSoundBuffer_SetVolume(SoundSlots[slot].lpsb, D1vol2DSvol(SoundSlots[slot].volume));
261         IDirectSoundBuffer_Play(SoundSlots[slot].lpsb, 0, 0, 0);
262
263         // added on 980905 by adb to add sound kill system from original sos digi.c
264         reset_sounds_on_channel(slot);
265         SampleHandles[next_handle] = slot;
266         next_handle++;
267         if (next_handle >= digi_max_channels)
268                 next_handle = 0;
269         // end edit by adb
270
271         return slot;
272 }
273
274 // Returns the channel a sound number is playing on, or
275 // -1 if none.
276 int digi_find_channel(int soundno)
277 {
278         if (!Digi_initialized)
279                 return -1;
280
281         if (soundno < 0 )
282                 return -1;
283
284         if (GameSounds[soundno].data == NULL)
285         {
286                 Int3();
287                 return -1;
288         }
289
290         //FIXME: not implemented
291         return -1;
292 }
293
294  //added on 980905 by adb to add sound kill system from original sos digi.c
295 void reset_sounds_on_channel( int channel )
296 {
297  int i;
298
299  for (i=0; i<digi_max_channels; i++)
300   if (SampleHandles[i] == channel)
301    SampleHandles[i] = -1;
302 }
303 //end edit by adb
304
305 //added on 980905 by adb from original source to make sfx volume work
306 void digi_set_digi_volume( int dvolume )
307 {
308         dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
309         if ( dvolume > SOUND_MAX_VOLUME )
310                 digi_volume = SOUND_MAX_VOLUME;
311         else if ( dvolume < 0 )
312                 digi_volume = 0;
313         else
314                 digi_volume = dvolume;
315
316         if ( !Digi_initialized ) return;
317
318         digi_sync_sounds();
319 }
320 //end edit by adb
321
322 void digi_set_volume( int dvolume, int mvolume ) 
323
324         digi_set_digi_volume(dvolume);
325         digi_set_midi_volume(mvolume);
326 }
327
328 int digi_is_sound_playing(int soundno)
329 {
330         int i;
331
332         soundno = digi_xlat_sound(soundno);
333
334         for (i = 0; i < MAX_SOUND_SLOTS; i++)
335                   //changed on 980905 by adb: added SoundSlots[i].playing &&
336                   if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
337                   //end changes by adb
338                         return 1;
339         return 0;
340 }
341
342
343  //added on 980905 by adb to make sound channel setting work
344 void digi_set_max_channels(int n) { 
345         digi_max_channels       = n;
346
347         if ( digi_max_channels < 1 ) 
348                 digi_max_channels = 1;
349         if (digi_max_channels > MAX_SOUND_SLOTS)
350                 digi_max_channels = MAX_SOUND_SLOTS;
351
352         if ( !Digi_initialized ) return;
353
354         digi_reset_digi_sounds();
355 }
356
357 int digi_get_max_channels() { 
358         return digi_max_channels; 
359 }
360 // end edit by adb
361
362 void digi_reset_digi_sounds() {
363  int i;
364
365  for (i=0; i< MAX_SOUND_SLOTS; i++) {
366                 DS_release_slot(i, 1);
367  }
368  
369  //added on 980905 by adb to reset sound kill system
370  memset(SampleHandles, 255, sizeof(SampleHandles));
371  next_handle = 0;
372  //end edit by adb
373 }
374
375 int digi_is_channel_playing(int channel)
376 {
377         if (!Digi_initialized)
378                 return 0;
379
380         return SoundSlots[channel].playing;
381 }
382
383 void digi_set_channel_volume(int channel, int volume)
384 {
385         if (!Digi_initialized)
386                 return;
387
388         if (!SoundSlots[channel].playing)
389                 return;
390
391         SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
392 }
393
394 void digi_set_channel_pan(int channel, int pan)
395 {
396         if (!Digi_initialized)
397                 return;
398
399         if (!SoundSlots[channel].playing)
400                 return;
401
402         SoundSlots[channel].pan = pan;
403 }
404
405 void digi_stop_sound(int channel)
406 {
407         SoundSlots[channel].playing=0;
408         SoundSlots[channel].soundobj = -1;
409         SoundSlots[channel].persistent = 0;
410 }
411
412 void digi_end_sound(int channel)
413 {
414         if (!Digi_initialized)
415                 return;
416
417         if (!SoundSlots[channel].playing)
418                 return;
419
420         SoundSlots[channel].soundobj = -1;
421         SoundSlots[channel].persistent = 0;
422 }
423
424 #else
425 int digi_midi_song_playing = 0;
426 static int Digi_initialized = 0;
427 int midi_volume = 255;
428
429 int digi_get_settings() { return 0; }
430 int digi_init() { Digi_initialized = 1; return 0; }
431 void digi_reset() {}
432 void digi_close() {}
433
434 void digi_set_digi_volume( int dvolume ) {}
435 void digi_set_volume( int dvolume, int mvolume ) {}
436
437 int digi_is_sound_playing(int soundno) { return 0; }
438
439 void digi_set_max_channels(int n) {}
440 int digi_get_max_channels() { return 0; }
441
442 #endif
443
444 #ifdef MIDI_SOUND
445 // MIDI stuff follows.
446
447 void digi_stop_current_song()
448 {
449         if ( digi_midi_song_playing ) {
450             hmp_close(hmp);
451             hmp = NULL;
452             digi_midi_song_playing = 0;
453         }
454 }
455
456 void digi_set_midi_volume( int n )
457 {
458         int mm_volume;
459
460         if (n < 0)
461                 midi_volume = 0;
462         else if (n > 127)
463                 midi_volume = 127;
464         else
465                 midi_volume = n;
466
467         // scale up from 0-127 to 0-0xffff
468         mm_volume = (midi_volume << 1) | (midi_volume & 1);
469         mm_volume |= (mm_volume << 8);
470
471         if (hmp)
472                 midiOutSetVolume((HMIDIOUT)hmp->hmidi, mm_volume | mm_volume << 16);
473 }
474
475 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop )
476 {       
477         if (!Digi_initialized) return;
478
479         digi_stop_current_song();
480
481        //added on 5/20/99 by Victor Rachels to fix crash/etc
482         if(filename == NULL) return;
483         if(midi_volume < 1) return;
484        //end this section addition - VR
485
486         if ((hmp = hmp_open(filename))) {
487             hmp_play(hmp);
488             digi_midi_song_playing = 1;
489             digi_set_midi_volume(midi_volume);
490         }
491         else
492                 printf("hmp_open failed\n");
493 }
494 void digi_pause_midi() {}
495 void digi_resume_midi() {}
496
497 #else
498 void digi_stop_current_song() {}
499 void digi_set_midi_volume( int n ) {}
500 void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
501 void digi_pause_midi() {}
502 void digi_resume_midi() {}
503 #endif
504
505 #ifndef NDEBUG
506 void digi_debug()
507 {
508         int i;
509         int n_voices = 0;
510
511         if (!Digi_initialized)
512                 return;
513
514         for (i = 0; i < digi_max_channels; i++)
515         {
516                 if (digi_is_channel_playing(i))
517                         n_voices++;
518         }
519
520         mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32)      ", n_voices, digi_max_channels, -1));
521         //mprintf_at((0, 3, 0, "DIGI: Number locked sounds:  %d                          ", digi_total_locks ));
522 }
523 #endif