Audio plugin host https://kx.studio/carla
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.

1282 lines
44KB

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