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.

1369 lines
45KB

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