The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1643 lines
49KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE && JUCE_DIRECTSOUND
  21. //==============================================================================
  22. END_JUCE_NAMESPACE
  23. extern "C"
  24. {
  25. // Declare just the minimum number of interfaces for the DSound objects that we need..
  26. typedef struct typeDSBUFFERDESC
  27. {
  28. DWORD dwSize;
  29. DWORD dwFlags;
  30. DWORD dwBufferBytes;
  31. DWORD dwReserved;
  32. LPWAVEFORMATEX lpwfxFormat;
  33. GUID guid3DAlgorithm;
  34. } DSBUFFERDESC;
  35. struct IDirectSoundBuffer;
  36. #undef INTERFACE
  37. #define INTERFACE IDirectSound
  38. DECLARE_INTERFACE_(IDirectSound, IUnknown)
  39. {
  40. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  41. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  42. STDMETHOD_(ULONG,Release) (THIS) PURE;
  43. STDMETHOD(CreateSoundBuffer) (THIS_ DSBUFFERDESC*, IDirectSoundBuffer**, LPUNKNOWN) PURE;
  44. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  45. STDMETHOD(DuplicateSoundBuffer) (THIS_ IDirectSoundBuffer*, IDirectSoundBuffer**) PURE;
  46. STDMETHOD(SetCooperativeLevel) (THIS_ HWND, DWORD) PURE;
  47. STDMETHOD(Compact) (THIS) PURE;
  48. STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD) PURE;
  49. STDMETHOD(SetSpeakerConfig) (THIS_ DWORD) PURE;
  50. STDMETHOD(Initialize) (THIS_ const GUID*) PURE;
  51. };
  52. #undef INTERFACE
  53. #define INTERFACE IDirectSoundBuffer
  54. DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown)
  55. {
  56. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  57. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  58. STDMETHOD_(ULONG,Release) (THIS) PURE;
  59. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  60. STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD) PURE;
  61. STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
  62. STDMETHOD(GetVolume) (THIS_ LPLONG) PURE;
  63. STDMETHOD(GetPan) (THIS_ LPLONG) PURE;
  64. STDMETHOD(GetFrequency) (THIS_ LPDWORD) PURE;
  65. STDMETHOD(GetStatus) (THIS_ LPDWORD) PURE;
  66. STDMETHOD(Initialize) (THIS_ IDirectSound*, DSBUFFERDESC*) PURE;
  67. STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
  68. STDMETHOD(Play) (THIS_ DWORD, DWORD, DWORD) PURE;
  69. STDMETHOD(SetCurrentPosition) (THIS_ DWORD) PURE;
  70. STDMETHOD(SetFormat) (THIS_ const WAVEFORMATEX*) PURE;
  71. STDMETHOD(SetVolume) (THIS_ LONG) PURE;
  72. STDMETHOD(SetPan) (THIS_ LONG) PURE;
  73. STDMETHOD(SetFrequency) (THIS_ DWORD) PURE;
  74. STDMETHOD(Stop) (THIS) PURE;
  75. STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
  76. STDMETHOD(Restore) (THIS) PURE;
  77. };
  78. //==============================================================================
  79. typedef struct typeDSCBUFFERDESC
  80. {
  81. DWORD dwSize;
  82. DWORD dwFlags;
  83. DWORD dwBufferBytes;
  84. DWORD dwReserved;
  85. LPWAVEFORMATEX lpwfxFormat;
  86. } DSCBUFFERDESC;
  87. struct IDirectSoundCaptureBuffer;
  88. #undef INTERFACE
  89. #define INTERFACE IDirectSoundCapture
  90. DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown)
  91. {
  92. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  93. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  94. STDMETHOD_(ULONG,Release) (THIS) PURE;
  95. STDMETHOD(CreateCaptureBuffer) (THIS_ DSCBUFFERDESC*, IDirectSoundCaptureBuffer**, LPUNKNOWN) PURE;
  96. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  97. STDMETHOD(Initialize) (THIS_ const GUID*) PURE;
  98. };
  99. #undef INTERFACE
  100. #define INTERFACE IDirectSoundCaptureBuffer
  101. DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown)
  102. {
  103. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  104. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  105. STDMETHOD_(ULONG,Release) (THIS) PURE;
  106. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  107. STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD) PURE;
  108. STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
  109. STDMETHOD(GetStatus) (THIS_ LPDWORD) PURE;
  110. STDMETHOD(Initialize) (THIS_ IDirectSoundCapture*, DSCBUFFERDESC*) PURE;
  111. STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
  112. STDMETHOD(Start) (THIS_ DWORD) PURE;
  113. STDMETHOD(Stop) (THIS) PURE;
  114. STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
  115. };
  116. };
  117. //==============================================================================
  118. BEGIN_JUCE_NAMESPACE
  119. static const String getDSErrorMessage (HRESULT hr)
  120. {
  121. const char* result = 0;
  122. switch (hr)
  123. {
  124. case MAKE_HRESULT(1, 0x878, 10):
  125. result = "Device already allocated";
  126. break;
  127. case MAKE_HRESULT(1, 0x878, 30):
  128. result = "Control unavailable";
  129. break;
  130. case E_INVALIDARG:
  131. result = "Invalid parameter";
  132. break;
  133. case MAKE_HRESULT(1, 0x878, 50):
  134. result = "Invalid call";
  135. break;
  136. case E_FAIL:
  137. result = "Generic error";
  138. break;
  139. case MAKE_HRESULT(1, 0x878, 70):
  140. result = "Priority level error";
  141. break;
  142. case E_OUTOFMEMORY:
  143. result = "Out of memory";
  144. break;
  145. case MAKE_HRESULT(1, 0x878, 100):
  146. result = "Bad format";
  147. break;
  148. case E_NOTIMPL:
  149. result = "Unsupported function";
  150. break;
  151. case MAKE_HRESULT(1, 0x878, 120):
  152. result = "No driver";
  153. break;
  154. case MAKE_HRESULT(1, 0x878, 130):
  155. result = "Already initialised";
  156. break;
  157. case CLASS_E_NOAGGREGATION:
  158. result = "No aggregation";
  159. break;
  160. case MAKE_HRESULT(1, 0x878, 150):
  161. result = "Buffer lost";
  162. break;
  163. case MAKE_HRESULT(1, 0x878, 160):
  164. result = "Another app has priority";
  165. break;
  166. case MAKE_HRESULT(1, 0x878, 170):
  167. result = "Uninitialised";
  168. break;
  169. case E_NOINTERFACE:
  170. result = "No interface";
  171. break;
  172. case S_OK:
  173. result = "No error";
  174. break;
  175. default:
  176. return "Unknown error: " + String ((int) hr);
  177. }
  178. return result;
  179. }
  180. //==============================================================================
  181. #define DS_DEBUGGING 1
  182. #ifdef DS_DEBUGGING
  183. #define CATCH JUCE_CATCH_EXCEPTION
  184. #undef log
  185. #define log(a) Logger::writeToLog(a);
  186. #undef logError
  187. #define logError(a) logDSError(a, __LINE__);
  188. static void logDSError (HRESULT hr, int lineNum)
  189. {
  190. if (hr != S_OK)
  191. {
  192. String error ("DS error at line ");
  193. error << lineNum << T(" - ") << getDSErrorMessage (hr);
  194. log (error);
  195. }
  196. }
  197. #else
  198. #define CATCH JUCE_CATCH_ALL
  199. #define log(a)
  200. #define logError(a)
  201. #endif
  202. //==============================================================================
  203. #define DSOUND_FUNCTION(functionName, params) \
  204. typedef HRESULT (WINAPI *type##functionName) params; \
  205. static type##functionName ds##functionName = 0;
  206. #define DSOUND_FUNCTION_LOAD(functionName) \
  207. ds##functionName = (type##functionName) GetProcAddress (h, #functionName); \
  208. jassert (ds##functionName != 0);
  209. typedef BOOL (CALLBACK *LPDSENUMCALLBACKW) (LPGUID, LPCWSTR, LPCWSTR, LPVOID);
  210. typedef BOOL (CALLBACK *LPDSENUMCALLBACKA) (LPGUID, LPCSTR, LPCSTR, LPVOID);
  211. DSOUND_FUNCTION (DirectSoundCreate, (const GUID*, IDirectSound**, LPUNKNOWN))
  212. DSOUND_FUNCTION (DirectSoundCaptureCreate, (const GUID*, IDirectSoundCapture**, LPUNKNOWN))
  213. DSOUND_FUNCTION (DirectSoundEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  214. DSOUND_FUNCTION (DirectSoundCaptureEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  215. static void initialiseDSoundFunctions()
  216. {
  217. if (dsDirectSoundCreate == 0)
  218. {
  219. HMODULE h = LoadLibraryA ("dsound.dll");
  220. DSOUND_FUNCTION_LOAD (DirectSoundCreate)
  221. DSOUND_FUNCTION_LOAD (DirectSoundCaptureCreate)
  222. DSOUND_FUNCTION_LOAD (DirectSoundEnumerateW)
  223. DSOUND_FUNCTION_LOAD (DirectSoundCaptureEnumerateW)
  224. }
  225. }
  226. //==============================================================================
  227. class DSoundInternalOutChannel
  228. {
  229. String name;
  230. LPGUID guid;
  231. int sampleRate, bufferSizeSamples;
  232. float* leftBuffer;
  233. float* rightBuffer;
  234. IDirectSound* pDirectSound;
  235. IDirectSoundBuffer* pOutputBuffer;
  236. DWORD writeOffset;
  237. int totalBytesPerBuffer;
  238. int bytesPerBuffer;
  239. unsigned int lastPlayCursor;
  240. public:
  241. int bitDepth;
  242. bool doneFlag;
  243. DSoundInternalOutChannel (const String& name_,
  244. LPGUID guid_,
  245. int rate,
  246. int bufferSize,
  247. float* left,
  248. float* right)
  249. : name (name_),
  250. guid (guid_),
  251. sampleRate (rate),
  252. bufferSizeSamples (bufferSize),
  253. leftBuffer (left),
  254. rightBuffer (right),
  255. pDirectSound (0),
  256. pOutputBuffer (0),
  257. bitDepth (16)
  258. {
  259. }
  260. ~DSoundInternalOutChannel()
  261. {
  262. close();
  263. }
  264. void close()
  265. {
  266. HRESULT hr;
  267. if (pOutputBuffer != 0)
  268. {
  269. JUCE_TRY
  270. {
  271. log (T("closing dsound out: ") + name);
  272. hr = pOutputBuffer->Stop();
  273. logError (hr);
  274. }
  275. CATCH
  276. JUCE_TRY
  277. {
  278. hr = pOutputBuffer->Release();
  279. logError (hr);
  280. }
  281. CATCH
  282. pOutputBuffer = 0;
  283. }
  284. if (pDirectSound != 0)
  285. {
  286. JUCE_TRY
  287. {
  288. hr = pDirectSound->Release();
  289. logError (hr);
  290. }
  291. CATCH
  292. pDirectSound = 0;
  293. }
  294. }
  295. const String open()
  296. {
  297. log (T("opening dsound out device: ") + name
  298. + T(" rate=") + String (sampleRate)
  299. + T(" bits=") + String (bitDepth)
  300. + T(" buf=") + String (bufferSizeSamples));
  301. pDirectSound = 0;
  302. pOutputBuffer = 0;
  303. writeOffset = 0;
  304. String error;
  305. HRESULT hr = E_NOINTERFACE;
  306. if (dsDirectSoundCreate != 0)
  307. hr = dsDirectSoundCreate (guid, &pDirectSound, 0);
  308. if (hr == S_OK)
  309. {
  310. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  311. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  312. const int numChannels = 2;
  313. hr = pDirectSound->SetCooperativeLevel (GetDesktopWindow(), 2 /* DSSCL_PRIORITY */);
  314. logError (hr);
  315. if (hr == S_OK)
  316. {
  317. IDirectSoundBuffer* pPrimaryBuffer;
  318. DSBUFFERDESC primaryDesc;
  319. zerostruct (primaryDesc);
  320. primaryDesc.dwSize = sizeof (DSBUFFERDESC);
  321. primaryDesc.dwFlags = 1 /* DSBCAPS_PRIMARYBUFFER */;
  322. primaryDesc.dwBufferBytes = 0;
  323. primaryDesc.lpwfxFormat = 0;
  324. log ("opening dsound out step 2");
  325. hr = pDirectSound->CreateSoundBuffer (&primaryDesc, &pPrimaryBuffer, 0);
  326. logError (hr);
  327. if (hr == S_OK)
  328. {
  329. WAVEFORMATEX wfFormat;
  330. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  331. wfFormat.nChannels = (unsigned short) numChannels;
  332. wfFormat.nSamplesPerSec = sampleRate;
  333. wfFormat.wBitsPerSample = (unsigned short) bitDepth;
  334. wfFormat.nBlockAlign = (unsigned short) (wfFormat.nChannels * wfFormat.wBitsPerSample / 8);
  335. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  336. wfFormat.cbSize = 0;
  337. hr = pPrimaryBuffer->SetFormat (&wfFormat);
  338. logError (hr);
  339. if (hr == S_OK)
  340. {
  341. DSBUFFERDESC secondaryDesc;
  342. zerostruct (secondaryDesc);
  343. secondaryDesc.dwSize = sizeof (DSBUFFERDESC);
  344. secondaryDesc.dwFlags = 0x8000 /* DSBCAPS_GLOBALFOCUS */
  345. | 0x10000 /* DSBCAPS_GETCURRENTPOSITION2 */;
  346. secondaryDesc.dwBufferBytes = totalBytesPerBuffer;
  347. secondaryDesc.lpwfxFormat = &wfFormat;
  348. hr = pDirectSound->CreateSoundBuffer (&secondaryDesc, &pOutputBuffer, 0);
  349. logError (hr);
  350. if (hr == S_OK)
  351. {
  352. log ("opening dsound out step 3");
  353. DWORD dwDataLen;
  354. unsigned char* pDSBuffData;
  355. hr = pOutputBuffer->Lock (0, totalBytesPerBuffer,
  356. (LPVOID*) &pDSBuffData, &dwDataLen, 0, 0, 0);
  357. logError (hr);
  358. if (hr == S_OK)
  359. {
  360. zeromem (pDSBuffData, dwDataLen);
  361. hr = pOutputBuffer->Unlock (pDSBuffData, dwDataLen, 0, 0);
  362. if (hr == S_OK)
  363. {
  364. hr = pOutputBuffer->SetCurrentPosition (0);
  365. if (hr == S_OK)
  366. {
  367. hr = pOutputBuffer->Play (0, 0, 1 /* DSBPLAY_LOOPING */);
  368. if (hr == S_OK)
  369. return String::empty;
  370. }
  371. }
  372. }
  373. }
  374. }
  375. }
  376. }
  377. }
  378. error = getDSErrorMessage (hr);
  379. close();
  380. return error;
  381. }
  382. void synchronisePosition()
  383. {
  384. if (pOutputBuffer != 0)
  385. {
  386. DWORD playCursor;
  387. pOutputBuffer->GetCurrentPosition (&playCursor, &writeOffset);
  388. }
  389. }
  390. bool service()
  391. {
  392. if (pOutputBuffer == 0)
  393. return true;
  394. DWORD playCursor, writeCursor;
  395. for (;;)
  396. {
  397. HRESULT hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
  398. if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
  399. {
  400. pOutputBuffer->Restore();
  401. continue;
  402. }
  403. if (hr == S_OK)
  404. break;
  405. logError (hr);
  406. jassertfalse
  407. return true;
  408. }
  409. int playWriteGap = writeCursor - playCursor;
  410. if (playWriteGap < 0)
  411. playWriteGap += totalBytesPerBuffer;
  412. int bytesEmpty = playCursor - writeOffset;
  413. if (bytesEmpty < 0)
  414. bytesEmpty += totalBytesPerBuffer;
  415. if (bytesEmpty > (totalBytesPerBuffer - playWriteGap))
  416. {
  417. writeOffset = writeCursor;
  418. bytesEmpty = totalBytesPerBuffer - playWriteGap;
  419. }
  420. if (bytesEmpty >= bytesPerBuffer)
  421. {
  422. LPBYTE lpbuf1 = 0;
  423. LPBYTE lpbuf2 = 0;
  424. DWORD dwSize1 = 0;
  425. DWORD dwSize2 = 0;
  426. HRESULT hr = pOutputBuffer->Lock (writeOffset,
  427. bytesPerBuffer,
  428. (void**) &lpbuf1, &dwSize1,
  429. (void**) &lpbuf2, &dwSize2, 0);
  430. if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
  431. {
  432. pOutputBuffer->Restore();
  433. hr = pOutputBuffer->Lock (writeOffset,
  434. bytesPerBuffer,
  435. (void**) &lpbuf1, &dwSize1,
  436. (void**) &lpbuf2, &dwSize2, 0);
  437. }
  438. if (hr == S_OK)
  439. {
  440. if (bitDepth == 16)
  441. {
  442. const float gainL = 32767.0f;
  443. const float gainR = 32767.0f;
  444. int* dest = (int*)lpbuf1;
  445. const float* left = leftBuffer;
  446. const float* right = rightBuffer;
  447. int samples1 = dwSize1 >> 2;
  448. int samples2 = dwSize2 >> 2;
  449. if (left == 0)
  450. {
  451. while (--samples1 >= 0)
  452. {
  453. int r = roundFloatToInt (gainR * *right++);
  454. if (r < -32768)
  455. r = -32768;
  456. else if (r > 32767)
  457. r = 32767;
  458. *dest++ = (r << 16);
  459. }
  460. dest = (int*)lpbuf2;
  461. while (--samples2 >= 0)
  462. {
  463. int r = roundFloatToInt (gainR * *right++);
  464. if (r < -32768)
  465. r = -32768;
  466. else if (r > 32767)
  467. r = 32767;
  468. *dest++ = (r << 16);
  469. }
  470. }
  471. else if (right == 0)
  472. {
  473. while (--samples1 >= 0)
  474. {
  475. int l = roundFloatToInt (gainL * *left++);
  476. if (l < -32768)
  477. l = -32768;
  478. else if (l > 32767)
  479. l = 32767;
  480. l &= 0xffff;
  481. *dest++ = l;
  482. }
  483. dest = (int*)lpbuf2;
  484. while (--samples2 >= 0)
  485. {
  486. int l = roundFloatToInt (gainL * *left++);
  487. if (l < -32768)
  488. l = -32768;
  489. else if (l > 32767)
  490. l = 32767;
  491. l &= 0xffff;
  492. *dest++ = l;
  493. }
  494. }
  495. else
  496. {
  497. while (--samples1 >= 0)
  498. {
  499. int l = roundFloatToInt (gainL * *left++);
  500. if (l < -32768)
  501. l = -32768;
  502. else if (l > 32767)
  503. l = 32767;
  504. l &= 0xffff;
  505. int r = roundFloatToInt (gainR * *right++);
  506. if (r < -32768)
  507. r = -32768;
  508. else if (r > 32767)
  509. r = 32767;
  510. *dest++ = (r << 16) | l;
  511. }
  512. dest = (int*)lpbuf2;
  513. while (--samples2 >= 0)
  514. {
  515. int l = roundFloatToInt (gainL * *left++);
  516. if (l < -32768)
  517. l = -32768;
  518. else if (l > 32767)
  519. l = 32767;
  520. l &= 0xffff;
  521. int r = roundFloatToInt (gainR * *right++);
  522. if (r < -32768)
  523. r = -32768;
  524. else if (r > 32767)
  525. r = 32767;
  526. *dest++ = (r << 16) | l;
  527. }
  528. }
  529. }
  530. else
  531. {
  532. jassertfalse
  533. }
  534. writeOffset = (writeOffset + dwSize1 + dwSize2) % totalBytesPerBuffer;
  535. pOutputBuffer->Unlock (lpbuf1, dwSize1, lpbuf2, dwSize2);
  536. }
  537. else
  538. {
  539. jassertfalse
  540. logError (hr);
  541. }
  542. bytesEmpty -= bytesPerBuffer;
  543. return true;
  544. }
  545. else
  546. {
  547. return false;
  548. }
  549. }
  550. };
  551. //==============================================================================
  552. struct DSoundInternalInChannel
  553. {
  554. String name;
  555. LPGUID guid;
  556. int sampleRate, bufferSizeSamples;
  557. float* leftBuffer;
  558. float* rightBuffer;
  559. IDirectSound* pDirectSound;
  560. IDirectSoundCapture* pDirectSoundCapture;
  561. IDirectSoundCaptureBuffer* pInputBuffer;
  562. public:
  563. unsigned int readOffset;
  564. int bytesPerBuffer, totalBytesPerBuffer;
  565. int bitDepth;
  566. bool doneFlag;
  567. DSoundInternalInChannel (const String& name_,
  568. LPGUID guid_,
  569. int rate,
  570. int bufferSize,
  571. float* left,
  572. float* right)
  573. : name (name_),
  574. guid (guid_),
  575. sampleRate (rate),
  576. bufferSizeSamples (bufferSize),
  577. leftBuffer (left),
  578. rightBuffer (right),
  579. pDirectSound (0),
  580. pDirectSoundCapture (0),
  581. pInputBuffer (0),
  582. bitDepth (16)
  583. {
  584. }
  585. ~DSoundInternalInChannel()
  586. {
  587. close();
  588. }
  589. void close()
  590. {
  591. HRESULT hr;
  592. if (pInputBuffer != 0)
  593. {
  594. JUCE_TRY
  595. {
  596. log (T("closing dsound in: ") + name);
  597. hr = pInputBuffer->Stop();
  598. logError (hr);
  599. }
  600. CATCH
  601. JUCE_TRY
  602. {
  603. hr = pInputBuffer->Release();
  604. logError (hr);
  605. }
  606. CATCH
  607. pInputBuffer = 0;
  608. }
  609. if (pDirectSoundCapture != 0)
  610. {
  611. JUCE_TRY
  612. {
  613. hr = pDirectSoundCapture->Release();
  614. logError (hr);
  615. }
  616. CATCH
  617. pDirectSoundCapture = 0;
  618. }
  619. if (pDirectSound != 0)
  620. {
  621. JUCE_TRY
  622. {
  623. hr = pDirectSound->Release();
  624. logError (hr);
  625. }
  626. CATCH
  627. pDirectSound = 0;
  628. }
  629. }
  630. const String open()
  631. {
  632. log (T("opening dsound in device: ") + name
  633. + T(" rate=") + String (sampleRate) + T(" bits=") + String (bitDepth) + T(" buf=") + String (bufferSizeSamples));
  634. pDirectSound = 0;
  635. pDirectSoundCapture = 0;
  636. pInputBuffer = 0;
  637. readOffset = 0;
  638. totalBytesPerBuffer = 0;
  639. String error;
  640. HRESULT hr = E_NOINTERFACE;
  641. if (dsDirectSoundCaptureCreate != 0)
  642. hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0);
  643. logError (hr);
  644. if (hr == S_OK)
  645. {
  646. const int numChannels = 2;
  647. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  648. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  649. WAVEFORMATEX wfFormat;
  650. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  651. wfFormat.nChannels = (unsigned short)numChannels;
  652. wfFormat.nSamplesPerSec = sampleRate;
  653. wfFormat.wBitsPerSample = (unsigned short)bitDepth;
  654. wfFormat.nBlockAlign = (unsigned short)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
  655. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  656. wfFormat.cbSize = 0;
  657. DSCBUFFERDESC captureDesc;
  658. zerostruct (captureDesc);
  659. captureDesc.dwSize = sizeof (DSCBUFFERDESC);
  660. captureDesc.dwFlags = 0;
  661. captureDesc.dwBufferBytes = totalBytesPerBuffer;
  662. captureDesc.lpwfxFormat = &wfFormat;
  663. log (T("opening dsound in step 2"));
  664. hr = pDirectSoundCapture->CreateCaptureBuffer (&captureDesc, &pInputBuffer, 0);
  665. logError (hr);
  666. if (hr == S_OK)
  667. {
  668. hr = pInputBuffer->Start (1 /* DSCBSTART_LOOPING */);
  669. logError (hr);
  670. if (hr == S_OK)
  671. return String::empty;
  672. }
  673. }
  674. error = getDSErrorMessage (hr);
  675. close();
  676. return error;
  677. }
  678. void synchronisePosition()
  679. {
  680. if (pInputBuffer != 0)
  681. {
  682. DWORD capturePos;
  683. pInputBuffer->GetCurrentPosition (&capturePos, (DWORD*)&readOffset);
  684. }
  685. }
  686. bool service()
  687. {
  688. if (pInputBuffer == 0)
  689. return true;
  690. DWORD capturePos, readPos;
  691. HRESULT hr = pInputBuffer->GetCurrentPosition (&capturePos, &readPos);
  692. logError (hr);
  693. if (hr != S_OK)
  694. return true;
  695. int bytesFilled = readPos - readOffset;
  696. if (bytesFilled < 0)
  697. bytesFilled += totalBytesPerBuffer;
  698. if (bytesFilled >= bytesPerBuffer)
  699. {
  700. LPBYTE lpbuf1 = 0;
  701. LPBYTE lpbuf2 = 0;
  702. DWORD dwsize1 = 0;
  703. DWORD dwsize2 = 0;
  704. HRESULT hr = pInputBuffer->Lock (readOffset,
  705. bytesPerBuffer,
  706. (void**) &lpbuf1, &dwsize1,
  707. (void**) &lpbuf2, &dwsize2, 0);
  708. if (hr == S_OK)
  709. {
  710. if (bitDepth == 16)
  711. {
  712. const float g = 1.0f / 32768.0f;
  713. float* destL = leftBuffer;
  714. float* destR = rightBuffer;
  715. int samples1 = dwsize1 >> 2;
  716. int samples2 = dwsize2 >> 2;
  717. const short* src = (const short*)lpbuf1;
  718. if (destL == 0)
  719. {
  720. while (--samples1 >= 0)
  721. {
  722. ++src;
  723. *destR++ = *src++ * g;
  724. }
  725. src = (const short*)lpbuf2;
  726. while (--samples2 >= 0)
  727. {
  728. ++src;
  729. *destR++ = *src++ * g;
  730. }
  731. }
  732. else if (destR == 0)
  733. {
  734. while (--samples1 >= 0)
  735. {
  736. *destL++ = *src++ * g;
  737. ++src;
  738. }
  739. src = (const short*)lpbuf2;
  740. while (--samples2 >= 0)
  741. {
  742. *destL++ = *src++ * g;
  743. ++src;
  744. }
  745. }
  746. else
  747. {
  748. while (--samples1 >= 0)
  749. {
  750. *destL++ = *src++ * g;
  751. *destR++ = *src++ * g;
  752. }
  753. src = (const short*)lpbuf2;
  754. while (--samples2 >= 0)
  755. {
  756. *destL++ = *src++ * g;
  757. *destR++ = *src++ * g;
  758. }
  759. }
  760. }
  761. else
  762. {
  763. jassertfalse
  764. }
  765. readOffset = (readOffset + dwsize1 + dwsize2) % totalBytesPerBuffer;
  766. pInputBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
  767. }
  768. else
  769. {
  770. logError (hr);
  771. jassertfalse
  772. }
  773. bytesFilled -= bytesPerBuffer;
  774. return true;
  775. }
  776. else
  777. {
  778. return false;
  779. }
  780. }
  781. };
  782. //==============================================================================
  783. class DSoundAudioIODevice : public AudioIODevice,
  784. public Thread
  785. {
  786. public:
  787. DSoundAudioIODevice (const String& deviceName,
  788. const int outputDeviceIndex_,
  789. const int inputDeviceIndex_)
  790. : AudioIODevice (deviceName, "DirectSound"),
  791. Thread ("Juce DSound"),
  792. isOpen_ (false),
  793. isStarted (false),
  794. outputDeviceIndex (outputDeviceIndex_),
  795. inputDeviceIndex (inputDeviceIndex_),
  796. numInputBuffers (0),
  797. numOutputBuffers (0),
  798. totalSamplesOut (0),
  799. sampleRate (0.0),
  800. inputBuffers (0),
  801. outputBuffers (0),
  802. callback (0),
  803. bufferSizeSamples (0)
  804. {
  805. if (outputDeviceIndex_ >= 0)
  806. {
  807. outChannels.add (TRANS("Left"));
  808. outChannels.add (TRANS("Right"));
  809. }
  810. if (inputDeviceIndex_ >= 0)
  811. {
  812. inChannels.add (TRANS("Left"));
  813. inChannels.add (TRANS("Right"));
  814. }
  815. }
  816. ~DSoundAudioIODevice()
  817. {
  818. close();
  819. }
  820. const StringArray getOutputChannelNames()
  821. {
  822. return outChannels;
  823. }
  824. const StringArray getInputChannelNames()
  825. {
  826. return inChannels;
  827. }
  828. int getNumSampleRates()
  829. {
  830. return 4;
  831. }
  832. double getSampleRate (int index)
  833. {
  834. const double samps[] = { 44100.0, 48000.0, 88200.0, 96000.0 };
  835. return samps [jlimit (0, 3, index)];
  836. }
  837. int getNumBufferSizesAvailable()
  838. {
  839. return 50;
  840. }
  841. int getBufferSizeSamples (int index)
  842. {
  843. int n = 64;
  844. for (int i = 0; i < index; ++i)
  845. n += (n < 512) ? 32
  846. : ((n < 1024) ? 64
  847. : ((n < 2048) ? 128 : 256));
  848. return n;
  849. }
  850. int getDefaultBufferSize()
  851. {
  852. return 2560;
  853. }
  854. const String open (const BitArray& inputChannels,
  855. const BitArray& outputChannels,
  856. double sampleRate,
  857. int bufferSizeSamples)
  858. {
  859. lastError = openDevice (inputChannels, outputChannels, sampleRate, bufferSizeSamples);
  860. isOpen_ = lastError.isEmpty();
  861. return lastError;
  862. }
  863. void close()
  864. {
  865. stop();
  866. if (isOpen_)
  867. {
  868. closeDevice();
  869. isOpen_ = false;
  870. }
  871. }
  872. bool isOpen()
  873. {
  874. return isOpen_ && isThreadRunning();
  875. }
  876. int getCurrentBufferSizeSamples()
  877. {
  878. return bufferSizeSamples;
  879. }
  880. double getCurrentSampleRate()
  881. {
  882. return sampleRate;
  883. }
  884. int getCurrentBitDepth()
  885. {
  886. int i, bits = 256;
  887. for (i = inChans.size(); --i >= 0;)
  888. bits = jmin (bits, inChans[i]->bitDepth);
  889. for (i = outChans.size(); --i >= 0;)
  890. bits = jmin (bits, outChans[i]->bitDepth);
  891. if (bits > 32)
  892. bits = 16;
  893. return bits;
  894. }
  895. const BitArray getActiveOutputChannels() const
  896. {
  897. return enabledOutputs;
  898. }
  899. const BitArray getActiveInputChannels() const
  900. {
  901. return enabledInputs;
  902. }
  903. int getOutputLatencyInSamples()
  904. {
  905. return (int) (getCurrentBufferSizeSamples() * 1.5);
  906. }
  907. int getInputLatencyInSamples()
  908. {
  909. return getOutputLatencyInSamples();
  910. }
  911. void start (AudioIODeviceCallback* call)
  912. {
  913. if (isOpen_ && call != 0 && ! isStarted)
  914. {
  915. if (! isThreadRunning())
  916. {
  917. // something gone wrong and the thread's stopped..
  918. isOpen_ = false;
  919. return;
  920. }
  921. call->audioDeviceAboutToStart (this);
  922. const ScopedLock sl (startStopLock);
  923. callback = call;
  924. isStarted = true;
  925. }
  926. }
  927. void stop()
  928. {
  929. if (isStarted)
  930. {
  931. AudioIODeviceCallback* const callbackLocal = callback;
  932. {
  933. const ScopedLock sl (startStopLock);
  934. isStarted = false;
  935. }
  936. if (callbackLocal != 0)
  937. callbackLocal->audioDeviceStopped();
  938. }
  939. }
  940. bool isPlaying()
  941. {
  942. return isStarted && isOpen_ && isThreadRunning();
  943. }
  944. const String getLastError()
  945. {
  946. return lastError;
  947. }
  948. //==============================================================================
  949. juce_UseDebuggingNewOperator
  950. StringArray inChannels, outChannels;
  951. int outputDeviceIndex, inputDeviceIndex;
  952. private:
  953. bool isOpen_;
  954. bool isStarted;
  955. String lastError;
  956. OwnedArray <DSoundInternalInChannel> inChans;
  957. OwnedArray <DSoundInternalOutChannel> outChans;
  958. WaitableEvent startEvent;
  959. int numInputBuffers, numOutputBuffers, bufferSizeSamples;
  960. int volatile totalSamplesOut;
  961. int64 volatile lastBlockTime;
  962. double sampleRate;
  963. BitArray enabledInputs, enabledOutputs;
  964. HeapBlock <float*> inputBuffers, outputBuffers;
  965. AudioIODeviceCallback* callback;
  966. CriticalSection startStopLock;
  967. DSoundAudioIODevice (const DSoundAudioIODevice&);
  968. const DSoundAudioIODevice& operator= (const DSoundAudioIODevice&);
  969. const String openDevice (const BitArray& inputChannels,
  970. const BitArray& outputChannels,
  971. double sampleRate_,
  972. int bufferSizeSamples_);
  973. void closeDevice()
  974. {
  975. isStarted = false;
  976. stopThread (5000);
  977. inChans.clear();
  978. outChans.clear();
  979. int i;
  980. for (i = 0; i < numInputBuffers; ++i)
  981. juce_free (inputBuffers[i]);
  982. inputBuffers.free();
  983. numInputBuffers = 0;
  984. for (i = 0; i < numOutputBuffers; ++i)
  985. juce_free (outputBuffers[i]);
  986. outputBuffers.free();
  987. numOutputBuffers = 0;
  988. }
  989. void resync()
  990. {
  991. if (! threadShouldExit())
  992. {
  993. sleep (5);
  994. int i;
  995. for (i = 0; i < outChans.size(); ++i)
  996. outChans.getUnchecked(i)->synchronisePosition();
  997. for (i = 0; i < inChans.size(); ++i)
  998. inChans.getUnchecked(i)->synchronisePosition();
  999. }
  1000. }
  1001. public:
  1002. void run()
  1003. {
  1004. while (! threadShouldExit())
  1005. {
  1006. if (wait (100))
  1007. break;
  1008. }
  1009. const int latencyMs = (int) (bufferSizeSamples * 1000.0 / sampleRate);
  1010. const int maxTimeMS = jmax (5, 3 * latencyMs);
  1011. while (! threadShouldExit())
  1012. {
  1013. int numToDo = 0;
  1014. uint32 startTime = Time::getMillisecondCounter();
  1015. int i;
  1016. for (i = inChans.size(); --i >= 0;)
  1017. {
  1018. inChans.getUnchecked(i)->doneFlag = false;
  1019. ++numToDo;
  1020. }
  1021. for (i = outChans.size(); --i >= 0;)
  1022. {
  1023. outChans.getUnchecked(i)->doneFlag = false;
  1024. ++numToDo;
  1025. }
  1026. if (numToDo > 0)
  1027. {
  1028. const int maxCount = 3;
  1029. int count = maxCount;
  1030. for (;;)
  1031. {
  1032. for (i = inChans.size(); --i >= 0;)
  1033. {
  1034. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1035. if ((! in->doneFlag) && in->service())
  1036. {
  1037. in->doneFlag = true;
  1038. --numToDo;
  1039. }
  1040. }
  1041. for (i = outChans.size(); --i >= 0;)
  1042. {
  1043. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1044. if ((! out->doneFlag) && out->service())
  1045. {
  1046. out->doneFlag = true;
  1047. --numToDo;
  1048. }
  1049. }
  1050. if (numToDo <= 0)
  1051. break;
  1052. if (Time::getMillisecondCounter() > startTime + maxTimeMS)
  1053. {
  1054. resync();
  1055. break;
  1056. }
  1057. if (--count <= 0)
  1058. {
  1059. Sleep (1);
  1060. count = maxCount;
  1061. }
  1062. if (threadShouldExit())
  1063. return;
  1064. }
  1065. }
  1066. else
  1067. {
  1068. sleep (1);
  1069. }
  1070. const ScopedLock sl (startStopLock);
  1071. if (isStarted)
  1072. {
  1073. JUCE_TRY
  1074. {
  1075. callback->audioDeviceIOCallback ((const float**) inputBuffers,
  1076. numInputBuffers,
  1077. outputBuffers,
  1078. numOutputBuffers,
  1079. bufferSizeSamples);
  1080. }
  1081. JUCE_CATCH_EXCEPTION
  1082. totalSamplesOut += bufferSizeSamples;
  1083. }
  1084. else
  1085. {
  1086. for (i = 0; i < numOutputBuffers; ++i)
  1087. if (outputBuffers[i] != 0)
  1088. zeromem (outputBuffers[i], bufferSizeSamples * sizeof (float));
  1089. totalSamplesOut = 0;
  1090. sleep (1);
  1091. }
  1092. }
  1093. }
  1094. };
  1095. //==============================================================================
  1096. class DSoundAudioIODeviceType : public AudioIODeviceType
  1097. {
  1098. public:
  1099. DSoundAudioIODeviceType()
  1100. : AudioIODeviceType (T("DirectSound")),
  1101. hasScanned (false)
  1102. {
  1103. initialiseDSoundFunctions();
  1104. }
  1105. ~DSoundAudioIODeviceType()
  1106. {
  1107. }
  1108. //==============================================================================
  1109. void scanForDevices()
  1110. {
  1111. hasScanned = true;
  1112. outputDeviceNames.clear();
  1113. outputGuids.clear();
  1114. inputDeviceNames.clear();
  1115. inputGuids.clear();
  1116. if (dsDirectSoundEnumerateW != 0)
  1117. {
  1118. dsDirectSoundEnumerateW (outputEnumProcW, this);
  1119. dsDirectSoundCaptureEnumerateW (inputEnumProcW, this);
  1120. }
  1121. }
  1122. const StringArray getDeviceNames (const bool wantInputNames) const
  1123. {
  1124. jassert (hasScanned); // need to call scanForDevices() before doing this
  1125. return wantInputNames ? inputDeviceNames
  1126. : outputDeviceNames;
  1127. }
  1128. int getDefaultDeviceIndex (const bool /*forInput*/) const
  1129. {
  1130. jassert (hasScanned); // need to call scanForDevices() before doing this
  1131. return 0;
  1132. }
  1133. int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
  1134. {
  1135. jassert (hasScanned); // need to call scanForDevices() before doing this
  1136. DSoundAudioIODevice* const d = dynamic_cast <DSoundAudioIODevice*> (device);
  1137. if (d == 0)
  1138. return -1;
  1139. return asInput ? d->inputDeviceIndex
  1140. : d->outputDeviceIndex;
  1141. }
  1142. bool hasSeparateInputsAndOutputs() const { return true; }
  1143. AudioIODevice* createDevice (const String& outputDeviceName,
  1144. const String& inputDeviceName)
  1145. {
  1146. jassert (hasScanned); // need to call scanForDevices() before doing this
  1147. const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
  1148. const int inputIndex = inputDeviceNames.indexOf (inputDeviceName);
  1149. if (outputIndex >= 0 || inputIndex >= 0)
  1150. return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
  1151. : inputDeviceName,
  1152. outputIndex, inputIndex);
  1153. return 0;
  1154. }
  1155. //==============================================================================
  1156. juce_UseDebuggingNewOperator
  1157. StringArray outputDeviceNames;
  1158. OwnedArray <GUID> outputGuids;
  1159. StringArray inputDeviceNames;
  1160. OwnedArray <GUID> inputGuids;
  1161. private:
  1162. bool hasScanned;
  1163. //==============================================================================
  1164. BOOL outputEnumProc (LPGUID lpGUID, String desc)
  1165. {
  1166. desc = desc.trim();
  1167. if (desc.isNotEmpty())
  1168. {
  1169. const String origDesc (desc);
  1170. int n = 2;
  1171. while (outputDeviceNames.contains (desc))
  1172. desc = origDesc + T(" (") + String (n++) + T(")");
  1173. outputDeviceNames.add (desc);
  1174. if (lpGUID != 0)
  1175. outputGuids.add (new GUID (*lpGUID));
  1176. else
  1177. outputGuids.add (0);
  1178. }
  1179. return TRUE;
  1180. }
  1181. static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1182. {
  1183. return ((DSoundAudioIODeviceType*) object)
  1184. ->outputEnumProc (lpGUID, String (description));
  1185. }
  1186. static BOOL CALLBACK outputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1187. {
  1188. return ((DSoundAudioIODeviceType*) object)
  1189. ->outputEnumProc (lpGUID, String (description));
  1190. }
  1191. //==============================================================================
  1192. BOOL CALLBACK inputEnumProc (LPGUID lpGUID, String desc)
  1193. {
  1194. desc = desc.trim();
  1195. if (desc.isNotEmpty())
  1196. {
  1197. const String origDesc (desc);
  1198. int n = 2;
  1199. while (inputDeviceNames.contains (desc))
  1200. desc = origDesc + T(" (") + String (n++) + T(")");
  1201. inputDeviceNames.add (desc);
  1202. if (lpGUID != 0)
  1203. inputGuids.add (new GUID (*lpGUID));
  1204. else
  1205. inputGuids.add (0);
  1206. }
  1207. return TRUE;
  1208. }
  1209. static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1210. {
  1211. return ((DSoundAudioIODeviceType*) object)
  1212. ->inputEnumProc (lpGUID, String (description));
  1213. }
  1214. static BOOL CALLBACK inputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1215. {
  1216. return ((DSoundAudioIODeviceType*) object)
  1217. ->inputEnumProc (lpGUID, String (description));
  1218. }
  1219. //==============================================================================
  1220. DSoundAudioIODeviceType (const DSoundAudioIODeviceType&);
  1221. const DSoundAudioIODeviceType& operator= (const DSoundAudioIODeviceType&);
  1222. };
  1223. //==============================================================================
  1224. const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
  1225. const BitArray& outputChannels,
  1226. double sampleRate_,
  1227. int bufferSizeSamples_)
  1228. {
  1229. closeDevice();
  1230. totalSamplesOut = 0;
  1231. sampleRate = sampleRate_;
  1232. if (bufferSizeSamples_ <= 0)
  1233. bufferSizeSamples_ = 960; // use as a default size if none is set.
  1234. bufferSizeSamples = bufferSizeSamples_ & ~7;
  1235. DSoundAudioIODeviceType dlh;
  1236. dlh.scanForDevices();
  1237. enabledInputs = inputChannels;
  1238. enabledInputs.setRange (inChannels.size(),
  1239. enabledInputs.getHighestBit() + 1 - inChannels.size(),
  1240. false);
  1241. numInputBuffers = enabledInputs.countNumberOfSetBits();
  1242. inputBuffers.calloc (numInputBuffers + 2);
  1243. int i, numIns = 0;
  1244. for (i = 0; i <= enabledInputs.getHighestBit(); i += 2)
  1245. {
  1246. float* left = 0;
  1247. float* right = 0;
  1248. if (enabledInputs[i])
  1249. left = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1250. if (enabledInputs[i + 1])
  1251. right = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1252. if (left != 0 || right != 0)
  1253. inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [inputDeviceIndex],
  1254. dlh.inputGuids [inputDeviceIndex],
  1255. (int) sampleRate, bufferSizeSamples,
  1256. left, right));
  1257. }
  1258. enabledOutputs = outputChannels;
  1259. enabledOutputs.setRange (outChannels.size(),
  1260. enabledOutputs.getHighestBit() + 1 - outChannels.size(),
  1261. false);
  1262. numOutputBuffers = enabledOutputs.countNumberOfSetBits();
  1263. outputBuffers.calloc (numOutputBuffers + 2);
  1264. int numOuts = 0;
  1265. for (i = 0; i <= enabledOutputs.getHighestBit(); i += 2)
  1266. {
  1267. float* left = 0;
  1268. float* right = 0;
  1269. if (enabledOutputs[i])
  1270. left = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1271. if (enabledOutputs[i + 1])
  1272. right = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1273. if (left != 0 || right != 0)
  1274. outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[outputDeviceIndex],
  1275. dlh.outputGuids [outputDeviceIndex],
  1276. (int) sampleRate, bufferSizeSamples,
  1277. left, right));
  1278. }
  1279. String error;
  1280. // boost our priority while opening the devices to try to get better sync between them
  1281. const int oldThreadPri = GetThreadPriority (GetCurrentThread());
  1282. const int oldProcPri = GetPriorityClass (GetCurrentProcess());
  1283. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1284. SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  1285. for (i = 0; i < outChans.size(); ++i)
  1286. {
  1287. error = outChans[i]->open();
  1288. if (error.isNotEmpty())
  1289. {
  1290. error = T("Error opening ") + dlh.outputDeviceNames[i]
  1291. + T(": \"") + error + T("\"");
  1292. break;
  1293. }
  1294. }
  1295. if (error.isEmpty())
  1296. {
  1297. for (i = 0; i < inChans.size(); ++i)
  1298. {
  1299. error = inChans[i]->open();
  1300. if (error.isNotEmpty())
  1301. {
  1302. error = T("Error opening ") + dlh.inputDeviceNames[i]
  1303. + T(": \"") + error + T("\"");
  1304. break;
  1305. }
  1306. }
  1307. }
  1308. if (error.isEmpty())
  1309. {
  1310. totalSamplesOut = 0;
  1311. for (i = 0; i < outChans.size(); ++i)
  1312. outChans.getUnchecked(i)->synchronisePosition();
  1313. for (i = 0; i < inChans.size(); ++i)
  1314. inChans.getUnchecked(i)->synchronisePosition();
  1315. startThread (9);
  1316. sleep (10);
  1317. notify();
  1318. }
  1319. else
  1320. {
  1321. log (error);
  1322. }
  1323. SetThreadPriority (GetCurrentThread(), oldThreadPri);
  1324. SetPriorityClass (GetCurrentProcess(), oldProcPri);
  1325. return error;
  1326. }
  1327. //==============================================================================
  1328. AudioIODeviceType* juce_createAudioIODeviceType_DirectSound()
  1329. {
  1330. return new DSoundAudioIODeviceType();
  1331. }
  1332. #undef log
  1333. #endif