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.

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