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.

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