source: golgotha/src/i4/sound/dsound/direct_sound.cc @ 608

Last change on this file since 608 was 80, checked in by Sam Hocevar, 15 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 18.1 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "error/error.hh"
10#include "error/alert.hh"
11
12#include <windows.h>
13#include "sound/dsound/direct_sound.hh"
14#include "sound/dsound/ds_error.hh"
15#include "sound/dsound/a3d.h"
16
17#include "loaders/wav_load.hh"
18#include "string/string.hh"
19#include "file/file.hh"
20#include "main/win_main.hh"
21#include "time/profile.hh"
22#include "main/main.hh"
23
24#include <windows.h>
25#include <process.h>
26
27sw32 play_count = 0;
28sw32 stop_count = 0;
29sw32 total_sounds = 0;
30
31//global class declaration
32direct_sound_class i4_direct_sound_class_instance;
33
34static sw16 i4_direct_sound_volume_table[I4_SOUND_VOLUME_LEVELS] =
35{
36  // Volume ramp
37  //{{{ Note:
38  //  Generated with:
39  //
40  // perl -e 'printf "  %6d, ", -10000; for ($i=1; $i<64; $i++)
41  //   { printf( "%6d, ", 1000*log($i/63)); if ($i%10 == 9) { print "\n  "; }}; print "\n"'
42  //}}}
43
44  -10000,  -4143,  -3449,  -3044,  -2756,  -2533,  -2351,  -2197,  -2063,  -1945,
45   -1840,  -1745,  -1658,  -1578,  -1504,  -1435,  -1370,  -1309,  -1252,  -1198,
46   -1147,  -1098,  -1052,  -1007,   -965,   -924,   -885,   -847,   -810,   -775,
47    -741,   -709,   -677,   -646,   -616,   -587,   -559,   -532,   -505,   -479,
48    -454,   -429,   -405,   -381,   -358,   -336,   -314,   -292,   -271,   -251,
49    -231,   -211,   -191,   -172,   -154,   -135,   -117,   -100,    -82,    -65,
50     -48,    -32,    -16,      0
51};
52
53
54//}}}
55
56dsound_buffer_class::dsound_buffer_class(IDirectSoundBuffer *_pDSB,
57                                         DWORD _flags, w32 _buffer_size)
58{
59  pDSB         = _pDSB;
60  p3DSB        = 0;
61  pNotify      = 0;
62  flags        = _flags;
63  sound_length = _buffer_size;
64  stream_man   = 0;
65
66  hearable_distance = 20;
67
68  default_frequency = get_frequency();
69  set_sound_position(0);
70 
71  total_sounds++;
72}
73
74dsound_buffer_class::~dsound_buffer_class()
75
76  if (is_playing()) stop();
77
78  if (p3DSB)
79  {
80    p3DSB->Release();
81    p3DSB = 0;
82  }
83 
84  if (pDSB)
85  {
86    pDSB->Release();
87    pDSB = 0;
88  }
89 
90  if (pNotify)
91  {
92    pNotify->Release();
93    pNotify = 0;
94  }
95
96  total_sounds--;
97}
98
99
100void direct_sound_class::init()
101{
102  initialized=i4_F;
103 
104  // this assigns the global i4_sound_class pointer to us
105  i4_sound_manager_class::init();
106 
107  lpDirectSound = 0;
108  lpA3D         = 0;
109  lpListener    = 0;
110  lpPrimary     = 0;
111}
112
113void direct_sound_class::uninit()
114{
115  if (lpListener)
116  {
117    lpListener->Release();
118    lpListener = 0;
119  }
120 
121  if (lpPrimary)
122  {
123    lpPrimary->Release();
124    lpPrimary = 0;
125  }
126
127  if (lpA3D)
128  {
129    lpA3D->Release();
130    lpA3D = 0;
131  }
132
133  if (lpDirectSound)
134  {
135    lpDirectSound->Release();
136    lpDirectSound = 0;
137  }
138 
139  CoUninitialize();
140}
141
142void dsound_buffer_class::lock(w32 start_position, w32 size,
143                               void *&block1, w32 &block1_size,
144                               void *&block2, w32 &block2_size)
145{
146  if (!pDSB)
147    return;
148
149  DWORD b1s, b2s;
150
151  HRESULT r=pDSB->Lock(start_position, size,
152                       &block1, &b1s,
153                       &block2, &b2s,
154                       0);
155
156  if (!i4_dsound_check(r))
157    i4_warning("dsound_buffer_class::lock() failed");
158 
159 
160  block1_size=b1s;
161  block2_size=b2s;
162}
163
164void dsound_buffer_class::unlock(void *block1, w32 block1_size,
165                                void *block2, w32 block2_size)
166{
167  if (!pDSB)
168    return;
169
170  pDSB->Unlock(block1, block1_size,
171               block2, block2_size);
172}
173
174void dsound_buffer_class::set_sound_position(w32 pos)
175{
176  if (!pDSB)
177    return;
178 
179  pDSB->SetCurrentPosition(pos); 
180}
181
182w32 dsound_buffer_class::get_sound_position()
183{
184  if (!pDSB)
185    return 0;
186
187  w32 play_cursor,write_cursor;
188   
189  pDSB->GetCurrentPosition(&play_cursor,&write_cursor);
190 
191  return play_cursor;
192}
193
194i4_profile_class pf_dsound_play("dsound::play()");
195
196void dsound_buffer_class::play()
197{
198  //play_count++;
199  if (!pDSB) return;
200
201  pf_dsound_play.start();
202   
203  HRESULT res = pDSB->Play(0,0,flags);
204  if (!i4_dsound_check(res))
205    i4_warning("dsound_buffer_class::play() failed");
206
207  pf_dsound_play.stop();
208 
209  return;
210}
211
212void dsound_buffer_class::stop()
213{
214  //stop_count++;
215  if (!pDSB)
216    return;
217 
218  HRESULT res = pDSB->Stop();
219  if (!i4_dsound_check(res))
220    i4_warning("dsound_buffer_class::stop() failed");
221}
222
223
224void dsound_buffer_class::set_frequency(i4_frequency freq)
225{
226  if (!pDSB)
227    return;
228 
229  HRESULT res = pDSB->SetFrequency(freq);
230 
231  if (!i4_dsound_check(res))
232    i4_warning("dsound_buffer_class::set_frequency() failed");
233}
234
235i4_frequency dsound_buffer_class::get_frequency()
236{
237  if (!pDSB)
238    return 0;
239 
240  DWORD f;
241  pDSB->GetFrequency(&f);
242 
243  return f;
244}
245
246
247void dsound_buffer_class::set_volume(i4_volume vol)
248{
249  if (!pDSB)
250    return;
251
252  if (vol < 0)
253    vol = 0;
254  else
255  if (vol >= I4_SOUND_VOLUME_LEVELS)
256    vol = I4_SOUND_VOLUME_LEVELS-1;
257 
258  HRESULT res = pDSB->SetVolume(i4_direct_sound_volume_table[vol]);
259  if (!i4_dsound_check(res))
260    i4_warning("dsound_buffer_class::set_volume() failed");
261}
262
263i4_volume dsound_buffer_class::get_volume()
264{
265  if (!pDSB)
266    return 0;
267 
268  //returns a direct_sound volume level, should return an i4_volume level
269  LONG v;
270  pDSB->GetVolume(&v);
271 
272  return v;
273}
274
275
276void dsound_buffer_class::set_pan(i4_pan pan)
277{
278  if (!pDSB || p3DSB) //dont call set_pan on 3d sounds, dummy
279    return; 
280
281  HRESULT res = pDSB->SetPan(pan);
282  if (!i4_dsound_check(res))
283    i4_warning("dsound_buffer_class::set_pan() failed");
284}
285
286i4_pan dsound_buffer_class::get_pan()
287{
288  if (!pDSB)
289    return 0;
290
291  LONG p;
292  pDSB->GetPan(&p);
293
294  return p;
295}
296
297
298void dsound_buffer_class::set_looping(i4_bool loop)
299{
300  if (loop)
301    flags |= DSBPLAY_LOOPING;
302  else
303    flags &= (~DSBPLAY_LOOPING);
304}
305
306i4_bool dsound_buffer_class::is_playing()
307{
308  if (!pDSB)
309    return i4_F;
310 
311  DWORD returned_status=0;
312
313  pDSB->GetStatus(&returned_status);
314
315  if (returned_status & DSBSTATUS_PLAYING)
316    return i4_T;
317
318  return i4_F;
319}
320
321i4_voice_class *direct_sound_class::duplicate_2d(i4_voice_class *voice)
322{
323  if (!voice)
324    return 0;
325
326  dsound_buffer_class *v = (dsound_buffer_class *)voice;
327
328  if (!v->pDSB)
329    return 0;
330
331  IDirectSoundBuffer *new_pDSB=0;
332
333  HRESULT res = lpDirectSound->DuplicateSoundBuffer(v->pDSB, &new_pDSB);
334
335  if (!i4_dsound_check(res))
336    return 0;
337
338  dsound_buffer_class *new_voice = new dsound_buffer_class(new_pDSB, v->flags, v->sound_length);
339 
340  return new_voice;
341}
342
343i4_voice_class *direct_sound_class::duplicate_3d(i4_voice_class *voice)
344{
345  i4_voice_class *new_voice = duplicate_2d(voice);
346 
347  //if 3d sound is not active just return a new 2d buffer
348  if (!use_3d_sound || !new_voice)
349    return new_voice;
350   
351  dsound_buffer_class *v = (dsound_buffer_class *)new_voice;
352
353  HRESULT res = v->pDSB->QueryInterface(IID_IDirectSound3DBuffer,(void **)&v->p3DSB);
354
355  if (!i4_dsound_check(res))
356  {
357    i4_warning("query for 3d sound buffer failed");
358    delete v;
359    return 0;
360  }
361   
362  res = v->p3DSB->SetMode(DS3DMODE_NORMAL,DS3D_DEFERRED);
363
364  if (!i4_dsound_check(res))
365  {
366    i4_warning("DS3D sound buffer setup failed");
367    delete v;
368    return 0;
369  }       
370 
371  return v;
372}
373
374void direct_sound_class::free_voice(i4_voice_class *voice)
375{
376  if (!voice)
377    return;
378
379  delete (dsound_buffer_class *)voice;
380}
381
382
383i4_bool direct_sound_class::setup()
384
385  if (initialized) return i4_T; 
386   
387  CoInitialize(0); 
388
389  HRESULT res;
390
391  use_3d_sound=i4_F;
392
393  for (int i=1; i<i4_global_argc; i++)
394  {
395    if (i4_global_argv[i]=="-3dsound")
396      use_3d_sound=i4_T;
397  }
398
399
400  if (use_3d_sound)
401  {
402    res = CoCreateInstance(CLSID_A3d, NULL, CLSCTX_INPROC_SERVER, 
403                                     IID_IDirectSound, (VOID **)&lpDirectSound);
404               
405    if (i4_dsound_check(res))
406    {
407      res = lpDirectSound->Initialize((LPGUID)&(GUID_NULL));
408   
409      if (i4_dsound_check(res))
410      {                 
411        res = lpDirectSound->QueryInterface(IID_IA3d,(void **)&lpA3D);
412
413        if (i4_dsound_check(res))
414        {
415          res = lpA3D->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC);
416          if (i4_dsound_check(res))
417          {
418            i4_warning("A3d Sound Manager setup successful");
419          }
420          else
421          {
422            i4_warning("A3d::SetResourceManagerMode Failed, using normal sound");
423            use_3d_sound = i4_F;
424          }
425        }
426        else
427        {
428          i4_warning("QueryInterface::A3d Failed, using normal sound");
429          use_3d_sound = i4_F;
430        }
431      }
432      else
433      {
434        i4_warning("lpDirectSound::Initialize Failed, using normal sound");
435        use_3d_sound = i4_F;
436      }     
437    }
438    else
439    {
440      i4_warning("CoCreateInstance::CLSID_A3d Failed, using normal sound");
441      use_3d_sound = i4_F;
442    }   
443  }
444 
445  if (!use_3d_sound)
446  {   
447    res = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, 
448                                     IID_IDirectSound, (VOID **)&lpDirectSound);
449
450    if (i4_dsound_check(res))
451    {
452      res = lpDirectSound->Initialize( (LPGUID)&(GUID_NULL) );   
453      if (i4_dsound_check(res))
454      {
455        i4_warning("DirectSound Sound (2d) Manager setup succesful");
456      }
457      else
458      {
459        i4_warning("CoCreateInstance::CLSID_DirectSound Failed, no sound");
460        return i4_F;
461      }     
462    }
463    else
464    {
465      i4_warning("lpDirectSound::Initialize Failed, no sound");
466      return i4_F;
467    }
468  }
469
470  if (!i4_dsound_check(lpDirectSound->SetCooperativeLevel(i4_win32_window_handle, DSSCL_EXCLUSIVE)))
471  {
472    i4_warning("i4_sound_manager_class::setup() - couldn't get exclusive sound");
473    return i4_F;
474  }
475 
476  //get the primary buffer
477  DSBUFFERDESC dsBD;
478  ZeroMemory(&dsBD, sizeof(DSBUFFERDESC));
479  dsBD.dwSize = sizeof(DSBUFFERDESC);
480 
481  dsBD.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE;
482  if (use_3d_sound) dsBD.dwFlags |= DSBCAPS_CTRL3D;
483   
484  if (!i4_dsound_check(lpDirectSound->CreateSoundBuffer(&dsBD, &lpPrimary, 0)))
485  {
486    i4_warning("DirectSound Setup - couldn't create primary buffer in hardware");
487    dsBD.dwFlags &= (~DSBCAPS_LOCHARDWARE);
488   
489    if (!i4_dsound_check(lpDirectSound->CreateSoundBuffer( &dsBD, &lpPrimary, 0)))
490    {     
491      if (use_3d_sound)
492      {
493        i4_warning("Direct Sound Setup - couldn't create primary buffer as 3D");
494           
495        use_3d_sound = i4_F;
496        dsBD.dwFlags &= (~DSBCAPS_CTRL3D);
497     
498        if (!i4_dsound_check(lpDirectSound->CreateSoundBuffer( &dsBD, &lpPrimary, 0)))
499        {
500          i4_warning("Direct Sound Setup - couldn't create primary buffer");
501          return i4_F;
502        }
503      }
504      else
505      {
506        i4_warning("Direct Sound Setup - couldn't create primary buffer");
507        return i4_F;
508      }
509    }     
510  }
511     
512  //set the output format (22khz 16bit stereo)
513  PCMWAVEFORMAT pcmwf;
514  DWORD blah; 
515  ZeroMemory(&pcmwf, sizeof(PCMWAVEFORMAT));
516  pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
517  pcmwf.wf.nChannels  = 2;
518  pcmwf.wf.nSamplesPerSec = 22050;
519  pcmwf.wf.nBlockAlign = 4;
520  pcmwf.wf.nAvgBytesPerSec = 22050*4;
521  pcmwf.wBitsPerSample = 16;
522 
523  if (!i4_dsound_check(lpPrimary->SetFormat((LPWAVEFORMATEX)&pcmwf)))
524  {
525    i4_warning("Unable to set the Primary Buffer Output Format");   
526  } 
527 
528  //create a listener object
529  if (use_3d_sound)
530  {   
531    if (!i4_dsound_check(lpPrimary->QueryInterface(IID_IDirectSound3DListener,(void **)&lpListener)))
532    {
533      i4_warning("listener create failed");
534      return i4_F;
535    }
536
537    if (!i4_dsound_check(lpListener->SetPosition(0,0,0,DS3D_IMMEDIATE)))
538    {
539      i4_warning("listener position set failed");
540    }
541
542    if (!i4_dsound_check(lpListener->SetVelocity(0,0,0,DS3D_IMMEDIATE)))
543    {
544      i4_warning("listener velocity set failed");
545    }
546
547    if (!i4_dsound_check(lpListener->SetOrientation(0,0,1,0,1,0,DS3D_IMMEDIATE)))
548    {
549      i4_warning("listener orientation set failed");
550    }
551   
552    if  (!i4_dsound_check(lpListener->SetDistanceFactor(3,DS3D_IMMEDIATE)))
553    {
554      i4_warning("listener distance factor set failed");
555    }
556   
557    if (!i4_dsound_check(lpListener->SetDopplerFactor(5,DS3D_IMMEDIATE)))
558    {
559     i4_warning("listener doppler factor set failed");
560    }   
561  } 
562 
563  initialized = i4_T;
564  return i4_T;
565}
566
567void direct_sound_class::commit_3d_changes()
568{
569  if (!use_3d_sound)
570    return;
571
572  //i4_warning("num play() calls: %d",play_count);
573  //i4_warning("num stop() calls: %d",stop_count);
574  //i4_warning("total sounds:     %d",total_sounds);
575  play_count=0;
576  stop_count=0;
577 
578  if (!lpListener)
579    return;
580
581  if (!i4_dsound_check(lpListener->CommitDeferredSettings()))
582  {
583    i4_warning("unable to commit 3d changes");
584  }
585}
586
587const i4_float distance_scale = 1.f;
588
589i4_profile_class pf_d3d_set_position("d3d_set_position");
590
591void dsound_buffer_class::set_3d_position(i4_float x, i4_float y, i4_float z, i4_bool immediately)
592{
593  if (p3DSB)
594  {
595    DWORD apply_time;
596 
597    if (immediately) apply_time = DS3D_IMMEDIATE;
598    else             apply_time = DS3D_DEFERRED;
599
600    pf_d3d_set_position.start();
601    HRESULT res = p3DSB->SetPosition(x*distance_scale,y*distance_scale,z*distance_scale,apply_time);
602    pf_d3d_set_position.stop();
603   
604    if (!i4_dsound_check(res))
605    {
606      i4_warning("3d setPosition failed");
607    }
608   
609    set_volume(I4_SOUND_VOLUME_LEVELS-1);
610
611
612  }
613  else
614  {
615    i4_3d_vector cam = i4_direct_sound_class_instance.listener_position;
616    i4_transform_class *trans = &(i4_direct_sound_class_instance.listener_transform);
617   
618    i4_3d_vector delta = i4_3d_vector(x - cam.x, y - cam.y, z - cam.z);
619   
620    i4_float dist    = sqrt(delta.x*delta.x + delta.y*delta.y + delta.z*delta.z);
621    if (dist>hearable_distance)
622      set_volume(0);
623    else
624      set_volume((hearable_distance - dist)*(I4_SOUND_VOLUME_LEVELS-1)
625                 /hearable_distance);
626   
627    delta.normalize();
628    delta *= 0.1;
629
630    i4_float pan = (float)DSBPAN_RIGHT*(trans->x.dot(delta));
631
632    if (pan > DSBPAN_RIGHT)
633      pan = DSBPAN_RIGHT;
634    else
635    if (pan < DSBPAN_LEFT)
636      pan = DSBPAN_LEFT;
637   
638    set_pan(pan);       
639  }
640}
641 
642void dsound_buffer_class::set_3d_velocity(i4_float x, i4_float y, i4_float z,i4_bool immediately)
643{
644  if (!p3DSB)
645    return;
646 
647  DWORD apply_time;
648 
649  if (immediately) apply_time = DS3D_IMMEDIATE;
650  else             apply_time = DS3D_DEFERRED;
651 
652  if (!i4_dsound_check(p3DSB->SetVelocity(x,y,z,apply_time)))
653  {
654    i4_warning("3d setPosition failed");
655  }
656}
657
658void direct_sound_class::set_listener_position(i4_float x,i4_float y,i4_float z)
659{
660  listener_position = i4_3d_vector(x,y,z);
661 
662  if (use_3d_sound && lpListener)
663  {
664    if (!i4_dsound_check(lpListener->SetPosition(x*distance_scale,y*distance_scale,z*distance_scale,DS3D_DEFERRED)))
665    {
666      i4_warning("listener Position set failed");
667    }   
668  } 
669}
670
671void direct_sound_class::set_listener_velocity(i4_float x,i4_float y,i4_float z)
672{
673  if (!lpListener)
674    return;
675
676  if (!i4_dsound_check(lpListener->SetVelocity(x,y,z,DS3D_DEFERRED)))
677  {
678    i4_warning("listener velocity set failed");
679  }
680}
681
682void direct_sound_class::set_listener_orientation(i4_float f_x,i4_float f_y,i4_float f_z,
683                                                  i4_float u_x,i4_float u_y,i4_float u_z)
684{
685  if (use_3d_sound)
686  {
687    if (!lpListener)
688      return;
689
690    if (!i4_dsound_check(lpListener->SetOrientation(f_x,f_y,f_z,u_x,u_y,u_z,DS3D_DEFERRED)))
691    {   
692      i4_warning("listener Orientation set failed");
693    }
694  }
695  else
696  {
697    i4_3d_vector front = i4_3d_vector(f_x,f_y,f_z);
698    i4_3d_vector up    = i4_3d_vector(u_x,u_y,u_z);
699    i4_3d_vector side;
700    side.cross(up,front);
701    side.normalize();
702   
703    listener_transform.identity();
704    listener_transform.x = side;
705    listener_transform.y = up;
706    listener_transform.z = front;
707  }
708}
709
710i4_voice_class *direct_sound_class::alloc(w32 buffer_size, sound_parameters &desc)
711{
712  if (!initialized)
713  {
714    if (!setup())
715      return 0;
716  }
717
718  IDirectSoundBuffer *pDSB=NULL;
719  LPDIRECTSOUND3DBUFFER *p3DSB=NULL;
720 
721  DSBUFFERDESC dsBD;
722  PCMWAVEFORMAT pcmwf;
723     
724  ZeroMemory(&pcmwf, sizeof(PCMWAVEFORMAT));
725  pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
726  pcmwf.wf.nChannels = desc.channels;
727  pcmwf.wf.nSamplesPerSec = desc.frequency;
728
729  pcmwf.wf.nBlockAlign = desc.sample_size * desc.channels;
730  pcmwf.wf.nAvgBytesPerSec = desc.frequency * pcmwf.wf.nBlockAlign;
731  pcmwf.wBitsPerSample = desc.sample_size*8;
732     
733  ZeroMemory(&dsBD,sizeof(DSBUFFERDESC));
734  dsBD.dwSize = sizeof(DSBUFFERDESC); 
735  dsBD.dwBufferBytes = buffer_size;
736  dsBD.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
737
738  dsBD.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
739
740  if (use_3d_sound && desc.capable_3d)
741    dsBD.dwFlags |= DSBCAPS_CTRL3D;
742  else
743    dsBD.dwFlags |= DSBCAPS_CTRLPAN;
744
745  if (!desc.streaming)
746    dsBD.dwFlags |= DSBCAPS_STATIC;
747
748  if (!i4_dsound_check(lpDirectSound->CreateSoundBuffer(&dsBD, &pDSB, 0)))
749  {
750    i4_warning("direct_sound_class:: couldnt alloc sound buffer");
751    return 0; 
752  }
753 
754  w32 play_flags=0;
755 
756  if (desc.looping)
757    play_flags |= DSBPLAY_LOOPING;
758
759  dsound_buffer_class *new_voice = new dsound_buffer_class(pDSB, play_flags, buffer_size);
760 
761  if (use_3d_sound && desc.capable_3d && desc.streaming)
762  {
763    HRESULT res = pDSB->QueryInterface(IID_IDirectSound3DBuffer,(void **)&new_voice->p3DSB);
764   
765    res = new_voice->p3DSB->SetMode(DS3DMODE_NORMAL,DS3D_DEFERRED);
766  }
767
768  return new_voice;
769}
770
771
772
Note: See TracBrowser for help on using the repository browser.