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