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.

1659 lines
50KB

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