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.

1728 lines
52KB

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