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.

1720 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(), 2 /* DSSCL_PRIORITY */);
  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 == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
  434. {
  435. pOutputBuffer->Restore();
  436. hr = pOutputBuffer->Lock (writeOffset,
  437. bytesPerBuffer,
  438. (void**) &lpbuf1, &dwSize1,
  439. (void**) &lpbuf2, &dwSize2, 0);
  440. }
  441. if (hr == S_OK)
  442. {
  443. if (bitDepth == 16)
  444. {
  445. const float gainL = 32767.0f;
  446. const float gainR = 32767.0f;
  447. int* dest = (int*)lpbuf1;
  448. const float* left = leftBuffer;
  449. const float* right = rightBuffer;
  450. int samples1 = dwSize1 >> 2;
  451. int samples2 = dwSize2 >> 2;
  452. if (left == 0)
  453. {
  454. while (--samples1 >= 0)
  455. {
  456. int r = roundFloatToInt (gainR * *right++);
  457. if (r < -32768)
  458. r = -32768;
  459. else if (r > 32767)
  460. r = 32767;
  461. *dest++ = (r << 16);
  462. }
  463. dest = (int*)lpbuf2;
  464. while (--samples2 >= 0)
  465. {
  466. int r = roundFloatToInt (gainR * *right++);
  467. if (r < -32768)
  468. r = -32768;
  469. else if (r > 32767)
  470. r = 32767;
  471. *dest++ = (r << 16);
  472. }
  473. }
  474. else if (right == 0)
  475. {
  476. while (--samples1 >= 0)
  477. {
  478. int l = roundFloatToInt (gainL * *left++);
  479. if (l < -32768)
  480. l = -32768;
  481. else if (l > 32767)
  482. l = 32767;
  483. l &= 0xffff;
  484. *dest++ = l;
  485. }
  486. dest = (int*)lpbuf2;
  487. while (--samples2 >= 0)
  488. {
  489. int l = roundFloatToInt (gainL * *left++);
  490. if (l < -32768)
  491. l = -32768;
  492. else if (l > 32767)
  493. l = 32767;
  494. l &= 0xffff;
  495. *dest++ = l;
  496. }
  497. }
  498. else
  499. {
  500. while (--samples1 >= 0)
  501. {
  502. int l = roundFloatToInt (gainL * *left++);
  503. if (l < -32768)
  504. l = -32768;
  505. else if (l > 32767)
  506. l = 32767;
  507. l &= 0xffff;
  508. int r = roundFloatToInt (gainR * *right++);
  509. if (r < -32768)
  510. r = -32768;
  511. else if (r > 32767)
  512. r = 32767;
  513. *dest++ = (r << 16) | l;
  514. }
  515. dest = (int*)lpbuf2;
  516. while (--samples2 >= 0)
  517. {
  518. int l = roundFloatToInt (gainL * *left++);
  519. if (l < -32768)
  520. l = -32768;
  521. else if (l > 32767)
  522. l = 32767;
  523. l &= 0xffff;
  524. int r = roundFloatToInt (gainR * *right++);
  525. if (r < -32768)
  526. r = -32768;
  527. else if (r > 32767)
  528. r = 32767;
  529. *dest++ = (r << 16) | l;
  530. }
  531. }
  532. }
  533. else
  534. {
  535. jassertfalse
  536. }
  537. writeOffset = (writeOffset + dwSize1 + dwSize2) % totalBytesPerBuffer;
  538. pOutputBuffer->Unlock (lpbuf1, dwSize1, lpbuf2, dwSize2);
  539. }
  540. else
  541. {
  542. jassertfalse
  543. logError (hr);
  544. }
  545. bytesEmpty -= bytesPerBuffer;
  546. return true;
  547. }
  548. else
  549. {
  550. return false;
  551. }
  552. }
  553. };
  554. //==============================================================================
  555. struct DSoundInternalInChannel
  556. {
  557. String name;
  558. LPGUID guid;
  559. int sampleRate, bufferSizeSamples;
  560. float* leftBuffer;
  561. float* rightBuffer;
  562. IDirectSound* pDirectSound;
  563. IDirectSoundCapture* pDirectSoundCapture;
  564. IDirectSoundCaptureBuffer* pInputBuffer;
  565. public:
  566. unsigned int readOffset;
  567. int bytesPerBuffer, totalBytesPerBuffer;
  568. int bitDepth;
  569. bool doneFlag;
  570. DSoundInternalInChannel (const String& name_,
  571. LPGUID guid_,
  572. int rate,
  573. int bufferSize,
  574. float* left,
  575. float* right)
  576. : name (name_),
  577. guid (guid_),
  578. sampleRate (rate),
  579. bufferSizeSamples (bufferSize),
  580. leftBuffer (left),
  581. rightBuffer (right),
  582. pDirectSound (0),
  583. pDirectSoundCapture (0),
  584. pInputBuffer (0),
  585. bitDepth (16)
  586. {
  587. }
  588. ~DSoundInternalInChannel()
  589. {
  590. close();
  591. }
  592. void close()
  593. {
  594. HRESULT hr;
  595. if (pInputBuffer != 0)
  596. {
  597. JUCE_TRY
  598. {
  599. log (T("closing dsound in: ") + name);
  600. hr = pInputBuffer->Stop();
  601. logError (hr);
  602. }
  603. CATCH
  604. JUCE_TRY
  605. {
  606. hr = pInputBuffer->Release();
  607. logError (hr);
  608. }
  609. CATCH
  610. pInputBuffer = 0;
  611. }
  612. if (pDirectSoundCapture != 0)
  613. {
  614. JUCE_TRY
  615. {
  616. hr = pDirectSoundCapture->Release();
  617. logError (hr);
  618. }
  619. CATCH
  620. pDirectSoundCapture = 0;
  621. }
  622. if (pDirectSound != 0)
  623. {
  624. JUCE_TRY
  625. {
  626. hr = pDirectSound->Release();
  627. logError (hr);
  628. }
  629. CATCH
  630. pDirectSound = 0;
  631. }
  632. }
  633. const String open()
  634. {
  635. log (T("opening dsound in device: ") + name
  636. + T(" rate=") + String (sampleRate) + T(" bits=") + String (bitDepth) + T(" buf=") + String (bufferSizeSamples));
  637. pDirectSound = 0;
  638. pDirectSoundCapture = 0;
  639. pInputBuffer = 0;
  640. readOffset = 0;
  641. totalBytesPerBuffer = 0;
  642. String error;
  643. HRESULT hr = E_NOINTERFACE;
  644. if (dsDirectSoundCaptureCreate != 0)
  645. hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0);
  646. logError (hr);
  647. if (hr == S_OK)
  648. {
  649. const int numChannels = 2;
  650. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  651. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  652. WAVEFORMATEX wfFormat;
  653. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  654. wfFormat.nChannels = (unsigned short)numChannels;
  655. wfFormat.nSamplesPerSec = sampleRate;
  656. wfFormat.wBitsPerSample = (unsigned short)bitDepth;
  657. wfFormat.nBlockAlign = (unsigned short)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
  658. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  659. wfFormat.cbSize = 0;
  660. DSCBUFFERDESC captureDesc;
  661. zerostruct (captureDesc);
  662. captureDesc.dwSize = sizeof (DSCBUFFERDESC);
  663. captureDesc.dwFlags = 0;
  664. captureDesc.dwBufferBytes = totalBytesPerBuffer;
  665. captureDesc.lpwfxFormat = &wfFormat;
  666. log (T("opening dsound in step 2"));
  667. hr = pDirectSoundCapture->CreateCaptureBuffer (&captureDesc, &pInputBuffer, 0);
  668. logError (hr);
  669. if (hr == S_OK)
  670. {
  671. hr = pInputBuffer->Start (1 /* DSCBSTART_LOOPING */);
  672. logError (hr);
  673. if (hr == S_OK)
  674. return String::empty;
  675. }
  676. }
  677. error = getDSErrorMessage (hr);
  678. close();
  679. return error;
  680. }
  681. void synchronisePosition()
  682. {
  683. if (pInputBuffer != 0)
  684. {
  685. DWORD capturePos;
  686. pInputBuffer->GetCurrentPosition (&capturePos, (DWORD*)&readOffset);
  687. }
  688. }
  689. bool service()
  690. {
  691. if (pInputBuffer == 0)
  692. return true;
  693. DWORD capturePos, readPos;
  694. HRESULT hr = pInputBuffer->GetCurrentPosition (&capturePos, &readPos);
  695. logError (hr);
  696. if (hr != S_OK)
  697. return true;
  698. int bytesFilled = readPos - readOffset;
  699. if (bytesFilled < 0)
  700. bytesFilled += totalBytesPerBuffer;
  701. if (bytesFilled >= bytesPerBuffer)
  702. {
  703. LPBYTE lpbuf1 = 0;
  704. LPBYTE lpbuf2 = 0;
  705. DWORD dwsize1 = 0;
  706. DWORD dwsize2 = 0;
  707. HRESULT hr = pInputBuffer->Lock (readOffset,
  708. bytesPerBuffer,
  709. (void**) &lpbuf1, &dwsize1,
  710. (void**) &lpbuf2, &dwsize2, 0);
  711. if (hr == S_OK)
  712. {
  713. if (bitDepth == 16)
  714. {
  715. const float g = 1.0f / 32768.0f;
  716. float* destL = leftBuffer;
  717. float* destR = rightBuffer;
  718. int samples1 = dwsize1 >> 2;
  719. int samples2 = dwsize2 >> 2;
  720. const short* src = (const short*)lpbuf1;
  721. if (destL == 0)
  722. {
  723. while (--samples1 >= 0)
  724. {
  725. ++src;
  726. *destR++ = *src++ * g;
  727. }
  728. src = (const short*)lpbuf2;
  729. while (--samples2 >= 0)
  730. {
  731. ++src;
  732. *destR++ = *src++ * g;
  733. }
  734. }
  735. else if (destR == 0)
  736. {
  737. while (--samples1 >= 0)
  738. {
  739. *destL++ = *src++ * g;
  740. ++src;
  741. }
  742. src = (const short*)lpbuf2;
  743. while (--samples2 >= 0)
  744. {
  745. *destL++ = *src++ * g;
  746. ++src;
  747. }
  748. }
  749. else
  750. {
  751. while (--samples1 >= 0)
  752. {
  753. *destL++ = *src++ * g;
  754. *destR++ = *src++ * g;
  755. }
  756. src = (const short*)lpbuf2;
  757. while (--samples2 >= 0)
  758. {
  759. *destL++ = *src++ * g;
  760. *destR++ = *src++ * g;
  761. }
  762. }
  763. }
  764. else
  765. {
  766. jassertfalse
  767. }
  768. readOffset = (readOffset + dwsize1 + dwsize2) % totalBytesPerBuffer;
  769. pInputBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
  770. }
  771. else
  772. {
  773. logError (hr);
  774. jassertfalse
  775. }
  776. bytesFilled -= bytesPerBuffer;
  777. return true;
  778. }
  779. else
  780. {
  781. return false;
  782. }
  783. }
  784. };
  785. //==============================================================================
  786. static int findBestMatchForName (const String& name, const StringArray& names)
  787. {
  788. int i = names.indexOf (name);
  789. if (i >= 0)
  790. return i;
  791. StringArray tokens1;
  792. tokens1.addTokens (name, T(" :-"), 0);
  793. int bestResult = -1;
  794. int bestNumMatches = 1;
  795. for (i = 0; i < names.size(); ++i)
  796. {
  797. StringArray tokens2;
  798. tokens2.addTokens (names[i], T(" :-"), 0);
  799. int matches = 0;
  800. for (int j = tokens1.size(); --j >= 0;)
  801. if (tokens2.contains (tokens1 [j]))
  802. ++matches;
  803. if (matches > bestNumMatches)
  804. bestResult = i;
  805. }
  806. return bestResult;
  807. }
  808. class DSoundAudioIODevice : public AudioIODevice,
  809. public Thread
  810. {
  811. public:
  812. DSoundAudioIODevice (const String& deviceName,
  813. const int index,
  814. const int inputIndex_)
  815. : AudioIODevice (deviceName, "DirectSound"),
  816. Thread ("Juce DSound"),
  817. isOpen_ (false),
  818. isStarted (false),
  819. deviceIndex (index),
  820. inputIndex (inputIndex_),
  821. inChans (4),
  822. outChans (4),
  823. numInputBuffers (0),
  824. numOutputBuffers (0),
  825. totalSamplesOut (0),
  826. sampleRate (0.0),
  827. inputBuffers (0),
  828. outputBuffers (0),
  829. callback (0),
  830. bufferSizeSamples (0)
  831. {
  832. }
  833. ~DSoundAudioIODevice()
  834. {
  835. close();
  836. }
  837. const StringArray getOutputChannelNames()
  838. {
  839. return outChannels;
  840. }
  841. const StringArray getInputChannelNames()
  842. {
  843. return inChannels;
  844. }
  845. int getNumSampleRates()
  846. {
  847. return 4;
  848. }
  849. double getSampleRate (int index)
  850. {
  851. const double samps[] = { 44100.0, 48000.0, 88200.0, 96000.0 };
  852. return samps [jlimit (0, 3, index)];
  853. }
  854. int getNumBufferSizesAvailable()
  855. {
  856. return 50;
  857. }
  858. int getBufferSizeSamples (int index)
  859. {
  860. int n = 64;
  861. for (int i = 0; i < index; ++i)
  862. n += (n < 512) ? 32
  863. : ((n < 1024) ? 64
  864. : ((n < 2048) ? 128 : 256));
  865. return n;
  866. }
  867. int getDefaultBufferSize()
  868. {
  869. return 2560;
  870. }
  871. const String open (const BitArray& inputChannels,
  872. const BitArray& outputChannels,
  873. double sampleRate,
  874. int bufferSizeSamples)
  875. {
  876. lastError = openDevice (inputChannels, outputChannels, sampleRate, bufferSizeSamples);
  877. isOpen_ = lastError.isEmpty();
  878. return lastError;
  879. }
  880. void close()
  881. {
  882. stop();
  883. if (isOpen_)
  884. {
  885. closeDevice();
  886. isOpen_ = false;
  887. }
  888. }
  889. bool isOpen()
  890. {
  891. return isOpen_ && isThreadRunning();
  892. }
  893. int getCurrentBufferSizeSamples()
  894. {
  895. return bufferSizeSamples;
  896. }
  897. double getCurrentSampleRate()
  898. {
  899. return sampleRate;
  900. }
  901. int getCurrentBitDepth()
  902. {
  903. int i, bits = 256;
  904. for (i = inChans.size(); --i >= 0;)
  905. bits = jmin (bits, inChans[i]->bitDepth);
  906. for (i = outChans.size(); --i >= 0;)
  907. bits = jmin (bits, outChans[i]->bitDepth);
  908. if (bits > 32)
  909. bits = 16;
  910. return bits;
  911. }
  912. const BitArray getActiveOutputChannels() const
  913. {
  914. return enabledOutputs;
  915. }
  916. const BitArray getActiveInputChannels() const
  917. {
  918. return enabledInputs;
  919. }
  920. int getOutputLatencyInSamples()
  921. {
  922. return (int) (getCurrentBufferSizeSamples() * 1.5);
  923. }
  924. int getInputLatencyInSamples()
  925. {
  926. return getOutputLatencyInSamples();
  927. }
  928. void start (AudioIODeviceCallback* call)
  929. {
  930. if (isOpen_ && call != 0 && ! isStarted)
  931. {
  932. if (! isThreadRunning())
  933. {
  934. // something gone wrong and the thread's stopped..
  935. isOpen_ = false;
  936. return;
  937. }
  938. call->audioDeviceAboutToStart (this);
  939. const ScopedLock sl (startStopLock);
  940. callback = call;
  941. isStarted = true;
  942. }
  943. }
  944. void stop()
  945. {
  946. if (isStarted)
  947. {
  948. AudioIODeviceCallback* const callbackLocal = callback;
  949. {
  950. const ScopedLock sl (startStopLock);
  951. isStarted = false;
  952. }
  953. if (callbackLocal != 0)
  954. callbackLocal->audioDeviceStopped();
  955. }
  956. }
  957. bool isPlaying()
  958. {
  959. return isStarted && isOpen_ && isThreadRunning();
  960. }
  961. const String getLastError()
  962. {
  963. return lastError;
  964. }
  965. //==============================================================================
  966. juce_UseDebuggingNewOperator
  967. StringArray inChannels, outChannels;
  968. private:
  969. bool isOpen_;
  970. bool isStarted;
  971. String lastError;
  972. int deviceIndex, inputIndex;
  973. OwnedArray <DSoundInternalInChannel> inChans;
  974. OwnedArray <DSoundInternalOutChannel> outChans;
  975. WaitableEvent startEvent;
  976. int numInputBuffers, numOutputBuffers, bufferSizeSamples;
  977. int volatile totalSamplesOut;
  978. int64 volatile lastBlockTime;
  979. double sampleRate;
  980. BitArray enabledInputs, enabledOutputs;
  981. float** inputBuffers;
  982. float** outputBuffers;
  983. AudioIODeviceCallback* callback;
  984. CriticalSection startStopLock;
  985. DSoundAudioIODevice (const DSoundAudioIODevice&);
  986. const DSoundAudioIODevice& operator= (const DSoundAudioIODevice&);
  987. const String openDevice (const BitArray& inputChannels,
  988. const BitArray& outputChannels,
  989. double sampleRate_,
  990. int bufferSizeSamples_);
  991. void closeDevice()
  992. {
  993. isStarted = false;
  994. stopThread (5000);
  995. inChans.clear();
  996. outChans.clear();
  997. int i;
  998. for (i = 0; i < numInputBuffers; ++i)
  999. juce_free (inputBuffers[i]);
  1000. delete[] inputBuffers;
  1001. inputBuffers = 0;
  1002. numInputBuffers = 0;
  1003. for (i = 0; i < numOutputBuffers; ++i)
  1004. juce_free (outputBuffers[i]);
  1005. delete[] outputBuffers;
  1006. outputBuffers = 0;
  1007. numOutputBuffers = 0;
  1008. }
  1009. void resync()
  1010. {
  1011. int i;
  1012. for (i = outChans.size(); --i >= 0;)
  1013. outChans.getUnchecked(i)->close();
  1014. for (i = inChans.size(); --i >= 0;)
  1015. inChans.getUnchecked(i)->close();
  1016. if (threadShouldExit())
  1017. return;
  1018. // boost our priority while opening the devices to try to get better sync between them
  1019. const int oldThreadPri = GetThreadPriority (GetCurrentThread());
  1020. const int oldProcPri = GetPriorityClass (GetCurrentProcess());
  1021. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1022. SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  1023. for (i = outChans.size(); --i >= 0;)
  1024. outChans.getUnchecked(i)->open();
  1025. for (i = inChans.size(); --i >= 0;)
  1026. inChans.getUnchecked(i)->open();
  1027. if (! threadShouldExit())
  1028. {
  1029. sleep (5);
  1030. for (i = 0; i < outChans.size(); ++i)
  1031. outChans.getUnchecked(i)->synchronisePosition();
  1032. for (i = 0; i < inChans.size(); ++i)
  1033. inChans.getUnchecked(i)->synchronisePosition();
  1034. }
  1035. SetThreadPriority (GetCurrentThread(), oldThreadPri);
  1036. SetPriorityClass (GetCurrentProcess(), oldProcPri);
  1037. }
  1038. public:
  1039. void run()
  1040. {
  1041. while (! threadShouldExit())
  1042. {
  1043. if (wait (100))
  1044. break;
  1045. }
  1046. const int latencyMs = (int) (bufferSizeSamples * 1000.0 / sampleRate);
  1047. const int maxTimeMS = jmax (5, 3 * latencyMs);
  1048. while (! threadShouldExit())
  1049. {
  1050. int numToDo = 0;
  1051. uint32 startTime = Time::getMillisecondCounter();
  1052. int i;
  1053. for (i = inChans.size(); --i >= 0;)
  1054. {
  1055. inChans.getUnchecked(i)->doneFlag = false;
  1056. ++numToDo;
  1057. }
  1058. for (i = outChans.size(); --i >= 0;)
  1059. {
  1060. outChans.getUnchecked(i)->doneFlag = false;
  1061. ++numToDo;
  1062. }
  1063. if (numToDo > 0)
  1064. {
  1065. const int maxCount = 3;
  1066. int count = maxCount;
  1067. for (;;)
  1068. {
  1069. for (i = inChans.size(); --i >= 0;)
  1070. {
  1071. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1072. if ((! in->doneFlag) && in->service())
  1073. {
  1074. in->doneFlag = true;
  1075. --numToDo;
  1076. }
  1077. }
  1078. for (i = outChans.size(); --i >= 0;)
  1079. {
  1080. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1081. if ((! out->doneFlag) && out->service())
  1082. {
  1083. out->doneFlag = true;
  1084. --numToDo;
  1085. }
  1086. }
  1087. if (numToDo <= 0)
  1088. break;
  1089. if (Time::getMillisecondCounter() > startTime + maxTimeMS)
  1090. {
  1091. resync();
  1092. break;
  1093. }
  1094. if (--count <= 0)
  1095. {
  1096. Sleep (1);
  1097. count = maxCount;
  1098. }
  1099. if (threadShouldExit())
  1100. return;
  1101. }
  1102. }
  1103. else
  1104. {
  1105. sleep (1);
  1106. }
  1107. const ScopedLock sl (startStopLock);
  1108. if (isStarted)
  1109. {
  1110. JUCE_TRY
  1111. {
  1112. callback->audioDeviceIOCallback ((const float**) inputBuffers,
  1113. numInputBuffers,
  1114. outputBuffers,
  1115. numOutputBuffers,
  1116. bufferSizeSamples);
  1117. }
  1118. JUCE_CATCH_EXCEPTION
  1119. totalSamplesOut += bufferSizeSamples;
  1120. }
  1121. else
  1122. {
  1123. for (i = 0; i < numOutputBuffers; ++i)
  1124. if (outputBuffers[i] != 0)
  1125. zeromem (outputBuffers[i], bufferSizeSamples * sizeof (float));
  1126. totalSamplesOut = 0;
  1127. sleep (1);
  1128. }
  1129. }
  1130. }
  1131. };
  1132. //==============================================================================
  1133. class DSoundAudioIODeviceType : public AudioIODeviceType
  1134. {
  1135. public:
  1136. DSoundAudioIODeviceType()
  1137. : AudioIODeviceType (T("DirectSound")),
  1138. hasScanned (false)
  1139. {
  1140. initialiseDSoundFunctions();
  1141. }
  1142. ~DSoundAudioIODeviceType()
  1143. {
  1144. }
  1145. //==============================================================================
  1146. void scanForDevices()
  1147. {
  1148. hasScanned = true;
  1149. outputDeviceNames.clear();
  1150. outputGuids.clear();
  1151. inputDeviceNames.clear();
  1152. inputGuids.clear();
  1153. if (dsDirectSoundEnumerateW != 0)
  1154. {
  1155. dsDirectSoundEnumerateW (outputEnumProcW, this);
  1156. dsDirectSoundCaptureEnumerateW (inputEnumProcW, this);
  1157. }
  1158. }
  1159. const StringArray getDeviceNames (const bool preferInputNames) const
  1160. {
  1161. jassert (hasScanned); // need to call scanForDevices() before doing this
  1162. return preferInputNames ? inputDeviceNames
  1163. : outputDeviceNames;
  1164. }
  1165. const String getDefaultDeviceName (const bool preferInputNames,
  1166. const int /*numInputChannelsNeeded*/,
  1167. const int /*numOutputChannelsNeeded*/) const
  1168. {
  1169. jassert (hasScanned); // need to call scanForDevices() before doing this
  1170. return getDeviceNames (preferInputNames) [0];
  1171. }
  1172. AudioIODevice* createDevice (const String& deviceName)
  1173. {
  1174. jassert (hasScanned); // need to call scanForDevices() before doing this
  1175. if (deviceName.isEmpty() || deviceName.equalsIgnoreCase (T("DirectSound")))
  1176. {
  1177. DSoundAudioIODevice* device = new DSoundAudioIODevice (deviceName, -1, -1);
  1178. int i;
  1179. for (i = 0; i < outputDeviceNames.size(); ++i)
  1180. {
  1181. device->outChannels.add (outputDeviceNames[i] + TRANS(" (left)"));
  1182. device->outChannels.add (outputDeviceNames[i] + TRANS(" (right)"));
  1183. }
  1184. for (i = 0; i < inputDeviceNames.size(); ++i)
  1185. {
  1186. device->inChannels.add (inputDeviceNames[i] + TRANS(" (left)"));
  1187. device->inChannels.add (inputDeviceNames[i] + TRANS(" (right)"));
  1188. }
  1189. return device;
  1190. }
  1191. else if (outputDeviceNames.contains (deviceName)
  1192. || inputDeviceNames.contains (deviceName))
  1193. {
  1194. int outputIndex = outputDeviceNames.indexOf (deviceName);
  1195. int inputIndex = findBestMatchForName (deviceName, inputDeviceNames);
  1196. if (outputIndex < 0)
  1197. {
  1198. // using an input device name instead..
  1199. inputIndex = inputDeviceNames.indexOf (deviceName);
  1200. outputIndex = jmax (0, findBestMatchForName (deviceName, outputDeviceNames));
  1201. }
  1202. DSoundAudioIODevice* device = new DSoundAudioIODevice (deviceName, outputIndex, inputIndex);
  1203. device->outChannels.add (TRANS("Left"));
  1204. device->outChannels.add (TRANS("Right"));
  1205. if (inputIndex >= 0)
  1206. {
  1207. device->inChannels.add (TRANS("Left"));
  1208. device->inChannels.add (TRANS("Right"));
  1209. }
  1210. return device;
  1211. }
  1212. return 0;
  1213. }
  1214. //==============================================================================
  1215. juce_UseDebuggingNewOperator
  1216. StringArray outputDeviceNames;
  1217. OwnedArray <GUID> outputGuids;
  1218. StringArray inputDeviceNames;
  1219. OwnedArray <GUID> inputGuids;
  1220. private:
  1221. bool hasScanned;
  1222. //==============================================================================
  1223. BOOL outputEnumProc (LPGUID lpGUID, String desc)
  1224. {
  1225. desc = desc.trim();
  1226. if (desc.isNotEmpty())
  1227. {
  1228. const String origDesc (desc);
  1229. int n = 2;
  1230. while (outputDeviceNames.contains (desc))
  1231. desc = origDesc + T(" (") + String (n++) + T(")");
  1232. outputDeviceNames.add (desc);
  1233. if (lpGUID != 0)
  1234. outputGuids.add (new GUID (*lpGUID));
  1235. else
  1236. outputGuids.add (0);
  1237. }
  1238. return TRUE;
  1239. }
  1240. static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1241. {
  1242. return ((DSoundAudioIODeviceType*) object)
  1243. ->outputEnumProc (lpGUID, String (description));
  1244. }
  1245. static BOOL CALLBACK outputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1246. {
  1247. return ((DSoundAudioIODeviceType*) object)
  1248. ->outputEnumProc (lpGUID, String (description));
  1249. }
  1250. //==============================================================================
  1251. BOOL CALLBACK inputEnumProc (LPGUID lpGUID, String desc)
  1252. {
  1253. desc = desc.trim();
  1254. if (desc.isNotEmpty())
  1255. {
  1256. const String origDesc (desc);
  1257. int n = 2;
  1258. while (inputDeviceNames.contains (desc))
  1259. desc = origDesc + T(" (") + String (n++) + T(")");
  1260. inputDeviceNames.add (desc);
  1261. if (lpGUID != 0)
  1262. inputGuids.add (new GUID (*lpGUID));
  1263. else
  1264. inputGuids.add (0);
  1265. }
  1266. return TRUE;
  1267. }
  1268. static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1269. {
  1270. return ((DSoundAudioIODeviceType*) object)
  1271. ->inputEnumProc (lpGUID, String (description));
  1272. }
  1273. static BOOL CALLBACK inputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1274. {
  1275. return ((DSoundAudioIODeviceType*) object)
  1276. ->inputEnumProc (lpGUID, String (description));
  1277. }
  1278. //==============================================================================
  1279. DSoundAudioIODeviceType (const DSoundAudioIODeviceType&);
  1280. const DSoundAudioIODeviceType& operator= (const DSoundAudioIODeviceType&);
  1281. };
  1282. //==============================================================================
  1283. AudioIODeviceType* juce_createDefaultAudioIODeviceType()
  1284. {
  1285. return new DSoundAudioIODeviceType();
  1286. }
  1287. //==============================================================================
  1288. const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
  1289. const BitArray& outputChannels,
  1290. double sampleRate_,
  1291. int bufferSizeSamples_)
  1292. {
  1293. closeDevice();
  1294. totalSamplesOut = 0;
  1295. sampleRate = sampleRate_;
  1296. if (bufferSizeSamples_ <= 0)
  1297. bufferSizeSamples_ = 960; // use as a default size if none is set.
  1298. bufferSizeSamples = bufferSizeSamples_ & ~7;
  1299. DSoundAudioIODeviceType dlh;
  1300. dlh.scanForDevices();
  1301. enabledInputs = inputChannels;
  1302. enabledInputs.setRange (inChannels.size(),
  1303. enabledInputs.getHighestBit() + 1 - inChannels.size(),
  1304. false);
  1305. numInputBuffers = enabledInputs.countNumberOfSetBits();
  1306. inputBuffers = new float* [numInputBuffers + 2];
  1307. zeromem (inputBuffers, sizeof (float*) * numInputBuffers + 2);
  1308. int i, numIns = 0;
  1309. for (i = 0; i <= enabledInputs.getHighestBit(); i += 2)
  1310. {
  1311. float* left = 0;
  1312. float* right = 0;
  1313. if (enabledInputs[i])
  1314. left = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1315. if (enabledInputs[i + 1])
  1316. right = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1317. if (left != 0 || right != 0)
  1318. inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [i / 2],
  1319. dlh.inputGuids [i / 2],
  1320. (int) sampleRate, bufferSizeSamples,
  1321. left, right));
  1322. }
  1323. enabledOutputs = outputChannels;
  1324. enabledOutputs.setRange (outChannels.size(),
  1325. enabledOutputs.getHighestBit() + 1 - outChannels.size(),
  1326. false);
  1327. numOutputBuffers = enabledOutputs.countNumberOfSetBits();
  1328. outputBuffers = new float* [numOutputBuffers + 2];
  1329. zeromem (outputBuffers, sizeof (float*) * numOutputBuffers + 2);
  1330. int numOuts = 0;
  1331. for (i = 0; i <= enabledOutputs.getHighestBit(); i += 2)
  1332. {
  1333. float* left = 0;
  1334. float* right = 0;
  1335. if (enabledOutputs[i])
  1336. left = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1337. if (enabledOutputs[i + 1])
  1338. right = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1339. if (left != 0 || right != 0)
  1340. outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[i / 2],
  1341. dlh.outputGuids [i / 2],
  1342. (int) sampleRate, bufferSizeSamples,
  1343. left, right));
  1344. }
  1345. String error;
  1346. // boost our priority while opening the devices to try to get better sync between them
  1347. const int oldThreadPri = GetThreadPriority (GetCurrentThread());
  1348. const int oldProcPri = GetPriorityClass (GetCurrentProcess());
  1349. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1350. SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  1351. for (i = 0; i < outChans.size(); ++i)
  1352. {
  1353. error = outChans[i]->open();
  1354. if (error.isNotEmpty())
  1355. {
  1356. error = T("Error opening ") + dlh.outputDeviceNames[i]
  1357. + T(": \"") + error + T("\"");
  1358. break;
  1359. }
  1360. }
  1361. if (error.isEmpty())
  1362. {
  1363. for (i = 0; i < inChans.size(); ++i)
  1364. {
  1365. error = inChans[i]->open();
  1366. if (error.isNotEmpty())
  1367. {
  1368. error = T("Error opening ") + dlh.inputDeviceNames[i]
  1369. + T(": \"") + error + T("\"");
  1370. break;
  1371. }
  1372. }
  1373. }
  1374. if (error.isEmpty())
  1375. {
  1376. totalSamplesOut = 0;
  1377. for (i = 0; i < outChans.size(); ++i)
  1378. outChans.getUnchecked(i)->synchronisePosition();
  1379. for (i = 0; i < inChans.size(); ++i)
  1380. inChans.getUnchecked(i)->synchronisePosition();
  1381. startThread (9);
  1382. sleep (10);
  1383. notify();
  1384. }
  1385. else
  1386. {
  1387. log (error);
  1388. }
  1389. SetThreadPriority (GetCurrentThread(), oldThreadPri);
  1390. SetPriorityClass (GetCurrentProcess(), oldProcPri);
  1391. return error;
  1392. }
  1393. #undef log
  1394. END_JUCE_NAMESPACE