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.

1680 lines
51KB

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