ds3dengine.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. //
  2. // ds3dengine.cpp
  3. //
  4. // Classes representing a DirectSound3D implementation of a sound engine
  5. //
  6. #include "pch.h"
  7. #include "soundbase.h"
  8. #include "ds3dutil.h"
  9. #include "ds3dbuffer.h"
  10. #include "ds3dvirtualbuffer.h"
  11. #include "ds3dengine.h"
  12. #include "soundutil.h"
  13. namespace SoundEngine {
  14. /////////////////////////////////////////////////////////////////////////////
  15. //
  16. // DefaultListener
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. // a listener who simply sits at the origin
  20. class DefaultListener : public ISoundListener
  21. {
  22. public:
  23. //
  24. // ISoundPositionSource
  25. //
  26. // Gets the position of the sound in space
  27. HRESULT GetPosition(Vector& vectPosition)
  28. {
  29. vectPosition = Vector(0, 0, 0);
  30. return S_OK;
  31. };
  32. // Gets the velocity of the sound in space
  33. HRESULT GetVelocity(Vector& vectVelocity)
  34. {
  35. vectVelocity = Vector(0, 0, 0);
  36. return S_OK;
  37. };
  38. // Gets the orientation of the sound in space, used for sound cones.
  39. virtual HRESULT GetOrientation(Vector& vectOrientation)
  40. {
  41. vectOrientation = Vector(0, 0, 1);
  42. return S_OK;
  43. };
  44. // Returns S_OK if the position, velocity and orientation reported are
  45. // relative to the listener, S_FALSE otherwise.
  46. virtual HRESULT IsListenerRelative()
  47. {
  48. return S_FALSE; // it would be useless if it was "listener relative"
  49. };
  50. // Returns S_OK if this source is still playing the sound, S_FALSE
  51. // otherwise. This might be false if a sound emitter is destroyed, for
  52. // example, in which case the sound might fade out. Once it returns
  53. // S_FALSE once, it should never return S_OK again.
  54. virtual HRESULT IsPlaying()
  55. {
  56. return S_OK;
  57. };
  58. //
  59. // ISoundListener
  60. //
  61. // get the "up" vector for the listener
  62. virtual HRESULT GetUpDirection(Vector& vectUp)
  63. {
  64. vectUp = Vector(0, 1, 0);
  65. return S_OK;
  66. }
  67. };
  68. /////////////////////////////////////////////////////////////////////////////
  69. //
  70. // DS3DSoundEngine
  71. //
  72. /////////////////////////////////////////////////////////////////////////////
  73. // dumps the capablilites of this DirectSound implementation to the
  74. // debug output.
  75. void DS3DSoundEngine::DumpCaps()
  76. {
  77. debugf(
  78. "Directsound driver is %scertified by Microsoft "
  79. "and is %semulated.\n",
  80. (m_dscaps.dwFlags & DSCAPS_CERTIFIED) ? "" : "not ",
  81. (m_dscaps.dwFlags & DSCAPS_EMULDRIVER) ? "" : "not "
  82. );
  83. debugf(
  84. " The primary buffer can be%s%s%s%s.\n",
  85. (m_dscaps.dwFlags & DSCAPS_PRIMARY8BIT) ? " 8 bit" : "",
  86. (m_dscaps.dwFlags & DSCAPS_PRIMARY16BIT) ? " 16 bit" : "",
  87. (m_dscaps.dwFlags & DSCAPS_PRIMARYMONO) ? " mono" : "",
  88. (m_dscaps.dwFlags & DSCAPS_PRIMARYSTEREO) ? " stereo" : ""
  89. );
  90. debugf(
  91. " The secondary buffers can range %s from %d Hz to %d Hz, and can be %s%s%s%s.\n",
  92. (m_dscaps.dwFlags & DSCAPS_CONTINUOUSRATE) ? "continuously" : "in steps",
  93. m_dscaps.dwMinSecondarySampleRate,
  94. m_dscaps.dwMaxSecondarySampleRate,
  95. (m_dscaps.dwFlags & DSCAPS_SECONDARY8BIT) ? " 8 bit" : "",
  96. (m_dscaps.dwFlags & DSCAPS_SECONDARY16BIT) ? " 16 bit" : "",
  97. (m_dscaps.dwFlags & DSCAPS_SECONDARYMONO) ? " mono" : "",
  98. (m_dscaps.dwFlags & DSCAPS_SECONDARYSTEREO) ? " stereo" : ""
  99. );
  100. debugf(
  101. " There is hardware support for mixing %d buffers, including %d static and %d streaming buffers.\n",
  102. m_dscaps.dwMaxHwMixingAllBuffers,
  103. m_dscaps.dwMaxHwMixingStaticBuffers,
  104. m_dscaps.dwMaxHwMixingStreamingBuffers
  105. );
  106. debugf(
  107. " There is hardware support for %d 3D buffers, including %d static 3D and %d streaming 3D buffers.\n",
  108. m_dscaps.dwMaxHw3DAllBuffers,
  109. m_dscaps.dwMaxHw3DStaticBuffers,
  110. m_dscaps.dwMaxHw3DStreamingBuffers
  111. );
  112. };
  113. // Sets the format of the primary buffer to the given sample rate, number
  114. // of bits, and number of channels
  115. HRESULT DS3DSoundEngine::SetPrimaryBufferFormat(int nSampleRate, int nNumberOfBits, int nChannels)
  116. {
  117. HRESULT hr;
  118. WAVEFORMATEX waveformatex;
  119. waveformatex.cbSize = sizeof(WAVEFORMATEX);
  120. waveformatex.wFormatTag = WAVE_FORMAT_PCM;
  121. waveformatex.nChannels = nChannels;
  122. waveformatex.nSamplesPerSec = nSampleRate;
  123. waveformatex.wBitsPerSample = nNumberOfBits;
  124. waveformatex.nBlockAlign = waveformatex.wBitsPerSample / 8 * waveformatex.nChannels;
  125. waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign;
  126. hr = m_pPrimaryBuffer->SetFormat(&waveformatex);
  127. if (ZFailed(hr)) return hr;
  128. #ifdef _DEBUG
  129. m_pPrimaryBuffer->GetFormat(&waveformatex, sizeof(waveformatex), NULL);
  130. // print the new format in the debug window
  131. debugf(
  132. "Primary buffer set to %d Hz, %d bits, %d channels (attempted %d Hz, %d bits, %d channels)\n",
  133. waveformatex.nSamplesPerSec, waveformatex.wBitsPerSample, waveformatex.nChannels,
  134. nSampleRate, nNumberOfBits, nChannels
  135. );
  136. #endif
  137. return S_OK;
  138. };
  139. // updates the listener position, orientation, etc. for direct sound 3D.
  140. HRESULT DS3DSoundEngine::UpdateListener()
  141. {
  142. HRESULT hr;
  143. DS3DLISTENER listenerdata;
  144. listenerdata.dwSize = sizeof(listenerdata);
  145. listenerdata.flDistanceFactor = m_fDistanceFactor;
  146. listenerdata.flDopplerFactor = m_fDopplerFactor;
  147. listenerdata.flRolloffFactor = m_fRolloffFactor;
  148. Vector vectPosition;
  149. hr = m_plistener->GetPosition(vectPosition);
  150. if (ZFailed(hr)) return hr;
  151. ConvertVector(listenerdata.vPosition, vectPosition);
  152. Vector vectVelocity;
  153. hr = m_plistener->GetVelocity(vectVelocity);
  154. if (ZFailed(hr)) return hr;
  155. ConvertVector(listenerdata.vVelocity, vectVelocity);
  156. Vector vectOrientation;
  157. hr = m_plistener->GetOrientation(vectOrientation);
  158. if (ZFailed(hr)) return hr;
  159. ZAssertIsUnitVector(vectOrientation);
  160. ConvertVector(listenerdata.vOrientFront, vectOrientation);
  161. Vector vectUp;
  162. hr = m_plistener->GetUpDirection(vectUp);
  163. if (ZFailed(hr)) return hr;
  164. ZAssertIsUnitVector(vectUp);
  165. ConvertVector(listenerdata.vOrientTop, vectUp);
  166. return m_pDSListener->SetAllParameters(&listenerdata, DS3D_DEFERRED);
  167. };
  168. // Is this an error worth killing a virtual sound for, or just something
  169. // transitory? For example, we may lose a sound buffer when being swapped
  170. // to the background, but we want the sound to continue playing when we
  171. // are swapped back in.
  172. bool DS3DSoundEngine::IsSeriousError(HRESULT hr)
  173. {
  174. switch (hr)
  175. {
  176. case S_OK:
  177. case S_FALSE:
  178. return false;
  179. case DSERR_BUFFERLOST:
  180. debugf("Sound buffer lost.\n");
  181. return false;
  182. case DSERR_OUTOFMEMORY:
  183. debugf("Out of sound memory.\n");
  184. return false;
  185. default:
  186. return FAILED(hr);
  187. }
  188. }
  189. // Constructor - the real initialization is done in init.
  190. DS3DSoundEngine::DS3DSoundEngine() :
  191. m_quality(midQuality),
  192. m_bAllowHardware(true),
  193. m_fRolloffFactor(1.0f),
  194. m_fDopplerFactor(1.0f),
  195. m_fDistanceFactor(1.0f)
  196. {
  197. m_plistener = new DefaultListener();
  198. m_peventsourceUpdate = new IntegerEventSourceImpl();
  199. m_dwLastUpdateTime = timeGetTime();
  200. m_pBufferSourceDelegate = new SoundBufferSourceDelegate(this);
  201. }
  202. DS3DSoundEngine::~DS3DSoundEngine()
  203. {
  204. HRESULT hr;
  205. m_peventsourceUpdate = NULL;
  206. // stop the primary buffer from playing continuously
  207. if (m_pPrimaryBuffer)
  208. {
  209. hr = m_pPrimaryBuffer->Stop();
  210. ZFailed(hr);
  211. }
  212. // release all dsound buffers
  213. m_pPrimaryBuffer = NULL;
  214. m_pDSListener = NULL;
  215. }
  216. // Basic initialization. This was pulled out of the constructor so that we
  217. // can return error values.
  218. HRESULT DS3DSoundEngine::Init(HWND hwnd)
  219. {
  220. HRESULT hr;
  221. // Create the device
  222. hr = DirectSoundCreate(NULL, &m_pDirectSound, NULL);
  223. if (hr == DSERR_NODRIVER || hr == DSERR_ALLOCATED || ZFailed(hr)) return hr;
  224. hr = m_pDirectSound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY);
  225. if (hr == DSERR_ALLOCATED)
  226. {
  227. debugf("Failure: unable to get DSSCL_PRIORITY access to DSound. Failing over to DSSCL_NORMAL.\n");
  228. hr = m_pDirectSound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
  229. }
  230. if (ZFailed(hr)) return hr;
  231. // go ahead and try compacting the memory; it's not neccessary but may
  232. // give us better hardware utilization on some sound cards.
  233. m_pDirectSound->Compact(); // if it fails, who cares.
  234. // get the primary buffer
  235. DSBUFFERDESC dsbufferdesc;
  236. memset(&dsbufferdesc, 0, sizeof(dsbufferdesc));
  237. dsbufferdesc.dwSize = sizeof(dsbufferdesc);
  238. dsbufferdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
  239. hr = m_pDirectSound->CreateSoundBuffer(&dsbufferdesc, &m_pPrimaryBuffer, NULL);
  240. if (ZFailed(hr)) return hr;
  241. // get the DirectSound listener
  242. hr = m_pPrimaryBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID *)&m_pDSListener);
  243. if (ZFailed(hr)) return hr;
  244. // get the capabilities of the hardware
  245. memset(&m_dscaps, 0, sizeof(m_dscaps));
  246. m_dscaps.dwSize = sizeof(m_dscaps);
  247. hr = m_pDirectSound->GetCaps(&m_dscaps);
  248. if (ZFailed(hr)) return hr;
  249. DumpCaps();
  250. // Set the quality-related settings
  251. hr = SetQuality(midQuality);
  252. if (ZFailed(hr)) return hr;
  253. // start the primary buffer playing continuously
  254. hr = m_pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
  255. if ((hr != DSERR_PRIOLEVELNEEDED) && ZFailed(hr)) return hr;
  256. return S_OK;
  257. }
  258. // Rebuild the sound stage to reflect any recent changes in sound
  259. HRESULT DS3DSoundEngine::Update()
  260. {
  261. HRESULT hr;
  262. Vector vectListenerPosition;
  263. DWORD dwUpdateTime = timeGetTime();
  264. DWORD dwUpdatePeriod = dwUpdateTime - m_dwLastUpdateTime;
  265. // fire the update event.
  266. m_peventsourceUpdate->Trigger(dwUpdatePeriod);
  267. typedef std::vector<DSVirtualSoundBuffer*> TempSoundList;
  268. // get the current position of the listener, to use for future
  269. // calculations.
  270. hr = m_plistener->GetPosition(vectListenerPosition);
  271. if (ZFailed(hr)) return hr;
  272. // Walk the list of active sounds and call update for each one,
  273. // removing the sounds which have ended, keeping track of which sounds
  274. // have playing buffers
  275. TempSoundList listPrevSounds;
  276. listPrevSounds.reserve(m_nNumBuffersMax);
  277. VirtualSoundList::iterator iterSound;
  278. for (iterSound = m_listActiveSounds.begin();
  279. iterSound != m_listActiveSounds.end();)
  280. {
  281. hr = (*iterSound)->Update(dwUpdatePeriod, vectListenerPosition,
  282. m_fRolloffFactor);
  283. if (ZFailed(hr)) return hr;
  284. // if this is no longer playing, remove it from the list.
  285. if ((*iterSound)->IsStopped())
  286. {
  287. iterSound = m_listActiveSounds.erase(iterSound);
  288. }
  289. else
  290. {
  291. // if the sound has an active buffer, keep track of it.
  292. if ((*iterSound)->HasPlayingBuffer())
  293. listPrevSounds.push_back(
  294. (TRef<DSVirtualSoundBuffer>)(*iterSound)
  295. );
  296. ++iterSound;
  297. }
  298. }
  299. // get the n most important sounds that we wish to play
  300. TempSoundList listNewSounds;
  301. if (!m_listActiveSounds.empty())
  302. {
  303. // create a list of all of the sounds
  304. TempSoundList listAllSounds(m_listActiveSounds.size());
  305. std::transform(m_listActiveSounds.begin(), m_listActiveSounds.end(),
  306. listAllSounds.begin(), RefToPtr<DSVirtualSoundBuffer>());
  307. // turn it into a priority queue
  308. std::make_heap(listAllSounds.begin(), listAllSounds.end(), std::not2(SoundPriorityCompare()));
  309. // get the m_nNumBuffersDesired most important sounds by popping
  310. // them off of the queue
  311. listNewSounds.reserve(m_nNumBuffersDesired);
  312. for (int nSound = 0; nSound < min(m_nNumBuffersDesired, listAllSounds.size()); nSound++)
  313. {
  314. std::pop_heap(listAllSounds.begin(), listAllSounds.end() - nSound,
  315. std::not2(SoundPriorityCompare()));
  316. DSVirtualSoundBuffer* pbuffer = (*(listAllSounds.end() - nSound - 1));
  317. if (pbuffer->IsAudible())
  318. listNewSounds.push_back(pbuffer);
  319. }
  320. }
  321. // Compare the previously playing sounds and the list of new sounds we
  322. // want to play, and start and stop the sound buffers as needed to
  323. // achieve this.
  324. {
  325. // sort the old list by priority
  326. std::sort(listPrevSounds.begin(), listPrevSounds.end(), SoundPriorityCompare());
  327. // find the first sound which is not in the new list
  328. TempSoundList::iterator iterDead =
  329. (listNewSounds.empty()) ? listPrevSounds.begin() :
  330. std::find_if(listPrevSounds.begin(), listPrevSounds.end(),
  331. std::bind1st(SoundPriorityCompare(), *(listNewSounds.end() - 1)));
  332. // stop all of the old buffers
  333. // REVIEW: should fade out, if we have buffers.
  334. for (; iterDead != listPrevSounds.end(); iterDead++)
  335. {
  336. hr = (*iterDead)->StopBuffer();
  337. if (ZFailed(hr)) return hr;
  338. }
  339. // Start any new sounds
  340. for (TempSoundList::iterator iterNew = listNewSounds.begin();
  341. iterNew != listNewSounds.end(); ++iterNew)
  342. {
  343. if (!(*iterNew)->HasPlayingBuffer())
  344. {
  345. hr = (*iterNew)->StartBuffer(m_pDirectSound, m_quality, m_bAllowHardware);
  346. if (IsSeriousError(hr))
  347. {
  348. // Silently fail
  349. debugf("Serious error during update while starting sound: %X\n", hr);
  350. }
  351. }
  352. };
  353. }
  354. // update the listener's position, velocity, etc.,
  355. hr = UpdateListener();
  356. if (ZFailed(hr)) return hr;
  357. // Commit any and all deferred changes.
  358. hr = m_pDSListener->CommitDeferredSettings();
  359. if (ZFailed(hr)) return hr;
  360. m_dwLastUpdateTime = dwUpdateTime;
  361. return S_OK;
  362. }
  363. // Gets the number of virtual sound buffers that are playing at a given
  364. // moment. (no guarantees on how this number changes - it's just a perf.
  365. // number to use.)
  366. HRESULT DS3DSoundEngine::GetNumPlayingVirtualBuffers(int& nBuffers)
  367. {
  368. nBuffers = m_listActiveSounds.size();
  369. return S_OK;
  370. }
  371. // Sets a general quality of playback (CPU time vs. fidelity)
  372. HRESULT DS3DSoundEngine::SetQuality(Quality quality)
  373. {
  374. HRESULT hr;
  375. // stop all playing sound buffers
  376. VirtualSoundList::iterator iterSound;
  377. for (iterSound = m_listActiveSounds.begin();
  378. iterSound != m_listActiveSounds.end(); ++iterSound)
  379. {
  380. if ((*iterSound)->HasPlayingBuffer())
  381. {
  382. hr = (*iterSound)->StopBuffer();
  383. if (ZFailed(hr)) return hr;
  384. }
  385. }
  386. switch (quality)
  387. {
  388. case minQuality:
  389. hr = SetPrimaryBufferFormat(22050, 8, 1);
  390. if ((hr != DSERR_PRIOLEVELNEEDED) && ZFailed(hr)) return hr;
  391. m_nNumBuffersDesired = 8;
  392. m_nNumBuffersMax = 8;
  393. break;
  394. case midQuality:
  395. default:
  396. hr = SetPrimaryBufferFormat(22050, 16, 2);
  397. if ((hr != DSERR_PRIOLEVELNEEDED) && ZFailed(hr)) return hr;
  398. if (m_bAllowHardware)
  399. {
  400. m_nNumBuffersDesired = max(16, (int)m_dscaps.dwMaxHwMixingStreamingBuffers * 2 / 3);
  401. m_nNumBuffersMax = max(24, (int)m_dscaps.dwMaxHwMixingStreamingBuffers);
  402. }
  403. else
  404. {
  405. m_nNumBuffersDesired = 16;
  406. m_nNumBuffersMax = 24;
  407. }
  408. break;
  409. case maxQuality:
  410. hr = SetPrimaryBufferFormat(44100, 16, 2);
  411. if ((hr != DSERR_PRIOLEVELNEEDED) && ZFailed(hr)) return hr;
  412. if (m_bAllowHardware)
  413. {
  414. m_nNumBuffersDesired = max(24, (int)m_dscaps.dwMaxHwMixingStreamingBuffers - 8);
  415. m_nNumBuffersMax = max(32, (int)m_dscaps.dwMaxHwMixingStreamingBuffers);
  416. }
  417. else
  418. {
  419. m_nNumBuffersDesired = 24;
  420. m_nNumBuffersMax = 32;
  421. }
  422. break;
  423. }
  424. m_quality = quality;
  425. return S_OK;
  426. };
  427. // Allows/disallows hardware acceleration.
  428. HRESULT DS3DSoundEngine::EnableHardware(bool bEnable)
  429. {
  430. if (m_bAllowHardware != bEnable)
  431. {
  432. m_bAllowHardware = bEnable;
  433. // force the re-creation of all playing sounds, and adjust the
  434. // voice limits.
  435. return SetQuality(m_quality);
  436. }
  437. else
  438. {
  439. return S_OK;
  440. }
  441. }
  442. // Sets the listener to use for the current sounds
  443. HRESULT DS3DSoundEngine::SetListener(ISoundListener* plistener)
  444. {
  445. if (plistener == NULL)
  446. {
  447. ZAssert(false);
  448. return E_POINTER;
  449. }
  450. m_plistener = plistener;
  451. return S_OK;
  452. }
  453. // Sets the conversion from game units to meters
  454. HRESULT DS3DSoundEngine::SetDistanceFactor(float fMetersPerUnit)
  455. {
  456. if (fMetersPerUnit <= 0)
  457. {
  458. ZAssert(false);
  459. return E_INVALIDARG;
  460. };
  461. m_fDistanceFactor = fMetersPerUnit;
  462. return S_OK;
  463. }
  464. // Sets the rolloff factor, where 1.0 is the real world attenuation with
  465. // distance, 2.0 is twice the attenuation of the real world, etc..
  466. HRESULT DS3DSoundEngine::SetRolloffFactor(float fRolloffFactor)
  467. {
  468. if (fRolloffFactor < DS3D_MINROLLOFFFACTOR
  469. || fRolloffFactor > DS3D_MAXROLLOFFFACTOR)
  470. {
  471. ZAssert(false);
  472. return E_INVALIDARG;
  473. };
  474. m_fRolloffFactor = fRolloffFactor;
  475. return S_OK;
  476. }
  477. // Sets the doppler factor, where 1.0 is real-world doppler
  478. HRESULT DS3DSoundEngine::SetDopplerFactor(float fDopplerFactor)
  479. {
  480. if (fDopplerFactor < DS3D_MINDOPPLERFACTOR
  481. || fDopplerFactor > DS3D_MAXDOPPLERFACTOR)
  482. {
  483. ZAssert(false);
  484. return E_INVALIDARG;
  485. };
  486. m_fDopplerFactor = fDopplerFactor;
  487. return S_OK;
  488. }
  489. // Gets a buffer source for this object (not guarenteed to keep the sound
  490. // engine alive due to circular reference problems)
  491. ISoundBufferSource* DS3DSoundEngine::GetBufferSource()
  492. {
  493. return m_pBufferSourceDelegate;
  494. };
  495. // Creates a static sound buffer of the given wave file. If bLooping is
  496. // true, the sound will loop until stopped.
  497. HRESULT DS3DSoundEngine::CreateStaticBuffer(TRef<ISoundInstance>& psoundNew,
  498. ISoundPCMData* pcmdata, bool bLooping, ISoundPositionSource* psource)
  499. {
  500. TRef<DSVirtualSoundBuffer> pvirtualsound;
  501. if (psource != NULL)
  502. {
  503. pvirtualsound = new DS3DVirtualSoundBuffer(pcmdata, bLooping, psource);
  504. }
  505. else
  506. {
  507. pvirtualsound = new DSVirtualSoundBuffer(pcmdata, bLooping);
  508. }
  509. m_listActiveSounds.push_back(pvirtualsound);
  510. psoundNew = pvirtualsound;
  511. return S_OK;
  512. }
  513. // Creates a sound buffer with a loop in the middle. The sound will play
  514. // the start sound, play the loop sound until it gets a soft stop, then
  515. // play the rest of the sound.
  516. HRESULT DS3DSoundEngine::CreateASRBuffer(TRef<ISoundInstance>& psoundNew,
  517. ISoundPCMData* pcmdata, unsigned uLoopStart, unsigned uLoopLength,
  518. ISoundPositionSource* psource)
  519. {
  520. // check the parameters
  521. if (pcmdata == NULL)
  522. {
  523. ZAssert(false);
  524. return E_POINTER;
  525. }
  526. // make sure the loop is contained in the buffer
  527. if (uLoopStart + uLoopLength > pcmdata->GetSize())
  528. {
  529. ZAssert(false);
  530. return E_INVALIDARG;
  531. }
  532. TRef<DSVirtualSoundBuffer> pvirtualsound;
  533. if (psource != NULL)
  534. {
  535. pvirtualsound = new DS3DVirtualSoundBuffer(pcmdata, uLoopStart, uLoopLength, psource);
  536. }
  537. else
  538. {
  539. pvirtualsound = new DSVirtualSoundBuffer(pcmdata, uLoopStart, uLoopLength);
  540. }
  541. m_listActiveSounds.push_back(pvirtualsound);
  542. psoundNew = pvirtualsound;
  543. return S_OK;
  544. }
  545. // Gets an event which fires each time update is called. This can be used
  546. // for some of the trickier sounds that change with time.
  547. IIntegerEventSource* DS3DSoundEngine::GetUpdateEventSource()
  548. {
  549. return m_peventsourceUpdate;
  550. };
  551. #ifdef _DEBUG
  552. // return a human-readable description of the object, prepending
  553. // strIndent to the beginning of each line.
  554. ZString DS3DSoundEngine::DebugDump(const ZString& strIndent)
  555. {
  556. ZString strResult = strIndent + "DS3DSoundEngine: \n";
  557. // Walk the list of active sounds and dump each one
  558. VirtualSoundList::iterator iterSound;
  559. for (iterSound = m_listActiveSounds.begin();
  560. iterSound != m_listActiveSounds.end(); ++iterSound)
  561. {
  562. strResult += SoundDebugDump(
  563. (ISoundInstance*)(TRef<DSVirtualSoundBuffer>&)(*iterSound),
  564. strIndent + " ");
  565. }
  566. return strResult;
  567. }
  568. #endif
  569. };