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