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.

1769 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. #define log(a) Logger::writeToLog(a);
  195. #define logError(a) logDSError(a, __LINE__);
  196. static void logDSError (HRESULT hr, int lineNum)
  197. {
  198. if (hr != S_OK)
  199. {
  200. String error ("DS error at line ");
  201. error << lineNum << T(" - ") << getDSErrorMessage (hr);
  202. log (error);
  203. }
  204. }
  205. #else
  206. #define CATCH JUCE_CATCH_ALL
  207. #define log(a)
  208. #define logError(a)
  209. #endif
  210. //==============================================================================
  211. #define DSOUND_FUNCTION(functionName, params) \
  212. typedef HRESULT (WINAPI *type##functionName) params; \
  213. static type##functionName ds##functionName = 0;
  214. #define DSOUND_FUNCTION_LOAD(functionName) \
  215. ds##functionName = (type##functionName) GetProcAddress (h, #functionName); \
  216. jassert (ds##functionName != 0);
  217. typedef BOOL (CALLBACK *LPDSENUMCALLBACKW) (LPGUID, LPCWSTR, LPCWSTR, LPVOID);
  218. typedef BOOL (CALLBACK *LPDSENUMCALLBACKA) (LPGUID, LPCSTR, LPCSTR, LPVOID);
  219. DSOUND_FUNCTION (DirectSoundCreate, (const GUID*, IDirectSound**, LPUNKNOWN))
  220. DSOUND_FUNCTION (DirectSoundCaptureCreate, (const GUID*, IDirectSoundCapture**, LPUNKNOWN))
  221. DSOUND_FUNCTION (DirectSoundEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  222. DSOUND_FUNCTION (DirectSoundCaptureEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  223. static void initialiseDSoundFunctions()
  224. {
  225. if (dsDirectSoundCreate == 0)
  226. {
  227. HMODULE h = LoadLibraryA ("dsound.dll");
  228. DSOUND_FUNCTION_LOAD (DirectSoundCreate)
  229. DSOUND_FUNCTION_LOAD (DirectSoundCaptureCreate)
  230. DSOUND_FUNCTION_LOAD (DirectSoundEnumerateW)
  231. DSOUND_FUNCTION_LOAD (DirectSoundCaptureEnumerateW)
  232. }
  233. }
  234. //==============================================================================
  235. class DSoundInternalOutChannel
  236. {
  237. String name;
  238. LPGUID guid;
  239. int sampleRate, bufferSizeSamples;
  240. float* leftBuffer;
  241. float* rightBuffer;
  242. IDirectSound* pDirectSound;
  243. IDirectSoundBuffer* pOutputBuffer;
  244. DWORD writeOffset;
  245. int totalBytesPerBuffer;
  246. int bytesPerBuffer;
  247. unsigned int lastPlayCursor;
  248. public:
  249. int bitDepth;
  250. bool doneFlag;
  251. DSoundInternalOutChannel (const String& name_,
  252. LPGUID guid_,
  253. int rate,
  254. int bufferSize,
  255. float* left,
  256. float* right)
  257. : name (name_),
  258. guid (guid_),
  259. sampleRate (rate),
  260. bufferSizeSamples (bufferSize),
  261. leftBuffer (left),
  262. rightBuffer (right),
  263. pDirectSound (0),
  264. pOutputBuffer (0),
  265. bitDepth (16)
  266. {
  267. }
  268. ~DSoundInternalOutChannel()
  269. {
  270. close();
  271. }
  272. void close()
  273. {
  274. HRESULT hr;
  275. if (pOutputBuffer != 0)
  276. {
  277. JUCE_TRY
  278. {
  279. log (T("closing dsound out: ") + name);
  280. hr = pOutputBuffer->Stop();
  281. logError (hr);
  282. }
  283. CATCH
  284. JUCE_TRY
  285. {
  286. hr = pOutputBuffer->Release();
  287. logError (hr);
  288. }
  289. CATCH
  290. pOutputBuffer = 0;
  291. }
  292. if (pDirectSound != 0)
  293. {
  294. JUCE_TRY
  295. {
  296. hr = pDirectSound->Release();
  297. logError (hr);
  298. }
  299. CATCH
  300. pDirectSound = 0;
  301. }
  302. }
  303. const String open()
  304. {
  305. log (T("opening dsound out device: ") + name
  306. + T(" rate=") + String (sampleRate)
  307. + T(" bits=") + String (bitDepth)
  308. + T(" buf=") + String (bufferSizeSamples));
  309. pDirectSound = 0;
  310. pOutputBuffer = 0;
  311. writeOffset = 0;
  312. String error;
  313. HRESULT hr = E_NOINTERFACE;
  314. if (dsDirectSoundCreate != 0)
  315. hr = dsDirectSoundCreate (guid, &pDirectSound, 0);
  316. if (hr == S_OK)
  317. {
  318. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  319. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  320. const int numChannels = 2;
  321. hr = pDirectSound->SetCooperativeLevel (GetDesktopWindow(), 3 /* DSSCL_EXCLUSIVE */);
  322. logError (hr);
  323. if (hr == S_OK)
  324. {
  325. IDirectSoundBuffer* pPrimaryBuffer;
  326. DSBUFFERDESC primaryDesc;
  327. zerostruct (primaryDesc);
  328. primaryDesc.dwSize = sizeof (DSBUFFERDESC);
  329. primaryDesc.dwFlags = 1 /* DSBCAPS_PRIMARYBUFFER */;
  330. primaryDesc.dwBufferBytes = 0;
  331. primaryDesc.lpwfxFormat = 0;
  332. log ("opening dsound out step 2");
  333. hr = pDirectSound->CreateSoundBuffer (&primaryDesc, &pPrimaryBuffer, 0);
  334. logError (hr);
  335. if (hr == S_OK)
  336. {
  337. WAVEFORMATEX wfFormat;
  338. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  339. wfFormat.nChannels = (unsigned short) numChannels;
  340. wfFormat.nSamplesPerSec = sampleRate;
  341. wfFormat.wBitsPerSample = (unsigned short) bitDepth;
  342. wfFormat.nBlockAlign = (unsigned short) (wfFormat.nChannels * wfFormat.wBitsPerSample / 8);
  343. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  344. wfFormat.cbSize = 0;
  345. hr = pPrimaryBuffer->SetFormat (&wfFormat);
  346. logError (hr);
  347. if (hr == S_OK)
  348. {
  349. DSBUFFERDESC secondaryDesc;
  350. zerostruct (secondaryDesc);
  351. secondaryDesc.dwSize = sizeof (DSBUFFERDESC);
  352. secondaryDesc.dwFlags = 0x8000 /* DSBCAPS_GLOBALFOCUS */
  353. | 0x10000 /* DSBCAPS_GETCURRENTPOSITION2 */;
  354. secondaryDesc.dwBufferBytes = totalBytesPerBuffer;
  355. secondaryDesc.lpwfxFormat = &wfFormat;
  356. hr = pDirectSound->CreateSoundBuffer (&secondaryDesc, &pOutputBuffer, 0);
  357. logError (hr);
  358. if (hr == S_OK)
  359. {
  360. log ("opening dsound out step 3");
  361. DWORD dwDataLen;
  362. unsigned char* pDSBuffData;
  363. hr = pOutputBuffer->Lock (0, totalBytesPerBuffer,
  364. (LPVOID*) &pDSBuffData, &dwDataLen, 0, 0, 0);
  365. logError (hr);
  366. if (hr == S_OK)
  367. {
  368. zeromem (pDSBuffData, dwDataLen);
  369. hr = pOutputBuffer->Unlock (pDSBuffData, dwDataLen, 0, 0);
  370. if (hr == S_OK)
  371. {
  372. hr = pOutputBuffer->SetCurrentPosition (0);
  373. if (hr == S_OK)
  374. {
  375. hr = pOutputBuffer->Play (0, 0, 1 /* DSBPLAY_LOOPING */);
  376. if (hr == S_OK)
  377. return String::empty;
  378. }
  379. }
  380. }
  381. }
  382. }
  383. }
  384. }
  385. }
  386. error = getDSErrorMessage (hr);
  387. close();
  388. return error;
  389. }
  390. void synchronisePosition()
  391. {
  392. if (pOutputBuffer != 0)
  393. {
  394. DWORD playCursor;
  395. pOutputBuffer->GetCurrentPosition (&playCursor, &writeOffset);
  396. }
  397. }
  398. bool service()
  399. {
  400. if (pOutputBuffer == 0)
  401. return true;
  402. DWORD playCursor, writeCursor;
  403. HRESULT hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
  404. if (hr != S_OK)
  405. {
  406. logError (hr);
  407. jassertfalse
  408. return true;
  409. }
  410. int playWriteGap = writeCursor - playCursor;
  411. if (playWriteGap < 0)
  412. playWriteGap += totalBytesPerBuffer;
  413. int bytesEmpty = playCursor - writeOffset;
  414. if (bytesEmpty < 0)
  415. bytesEmpty += totalBytesPerBuffer;
  416. if (bytesEmpty > (totalBytesPerBuffer - playWriteGap))
  417. {
  418. writeOffset = writeCursor;
  419. bytesEmpty = totalBytesPerBuffer - playWriteGap;
  420. }
  421. if (bytesEmpty >= bytesPerBuffer)
  422. {
  423. LPBYTE lpbuf1 = 0;
  424. LPBYTE lpbuf2 = 0;
  425. DWORD dwSize1 = 0;
  426. DWORD dwSize2 = 0;
  427. HRESULT hr = pOutputBuffer->Lock (writeOffset,
  428. bytesPerBuffer,
  429. (void**) &lpbuf1, &dwSize1,
  430. (void**) &lpbuf2, &dwSize2, 0);
  431. if (hr == S_OK)
  432. {
  433. if (bitDepth == 16)
  434. {
  435. const float gainL = 32767.0f;
  436. const float gainR = 32767.0f;
  437. int* dest = (int*)lpbuf1;
  438. const float* left = leftBuffer;
  439. const float* right = rightBuffer;
  440. int samples1 = dwSize1 >> 2;
  441. int samples2 = dwSize2 >> 2;
  442. if (left == 0)
  443. {
  444. while (--samples1 >= 0)
  445. {
  446. int r = roundFloatToInt (gainR * *right++);
  447. if (r < -32768)
  448. r = -32768;
  449. else if (r > 32767)
  450. r = 32767;
  451. *dest++ = (r << 16);
  452. }
  453. dest = (int*)lpbuf2;
  454. while (--samples2 >= 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. }
  464. else if (right == 0)
  465. {
  466. while (--samples1 >= 0)
  467. {
  468. int l = roundFloatToInt (gainL * *left++);
  469. if (l < -32768)
  470. l = -32768;
  471. else if (l > 32767)
  472. l = 32767;
  473. l &= 0xffff;
  474. *dest++ = l;
  475. }
  476. dest = (int*)lpbuf2;
  477. while (--samples2 >= 0)
  478. {
  479. int l = roundFloatToInt (gainL * *left++);
  480. if (l < -32768)
  481. l = -32768;
  482. else if (l > 32767)
  483. l = 32767;
  484. l &= 0xffff;
  485. *dest++ = l;
  486. }
  487. }
  488. else
  489. {
  490. while (--samples1 >= 0)
  491. {
  492. int l = roundFloatToInt (gainL * *left++);
  493. if (l < -32768)
  494. l = -32768;
  495. else if (l > 32767)
  496. l = 32767;
  497. l &= 0xffff;
  498. int r = roundFloatToInt (gainR * *right++);
  499. if (r < -32768)
  500. r = -32768;
  501. else if (r > 32767)
  502. r = 32767;
  503. *dest++ = (r << 16) | l;
  504. }
  505. dest = (int*)lpbuf2;
  506. while (--samples2 >= 0)
  507. {
  508. int l = roundFloatToInt (gainL * *left++);
  509. if (l < -32768)
  510. l = -32768;
  511. else if (l > 32767)
  512. l = 32767;
  513. l &= 0xffff;
  514. int r = roundFloatToInt (gainR * *right++);
  515. if (r < -32768)
  516. r = -32768;
  517. else if (r > 32767)
  518. r = 32767;
  519. *dest++ = (r << 16) | l;
  520. }
  521. }
  522. }
  523. else
  524. {
  525. jassertfalse
  526. }
  527. writeOffset = (writeOffset + dwSize1 + dwSize2) % totalBytesPerBuffer;
  528. pOutputBuffer->Unlock (lpbuf1, dwSize1, lpbuf2, dwSize2);
  529. }
  530. else
  531. {
  532. jassertfalse
  533. logError (hr);
  534. }
  535. bytesEmpty -= bytesPerBuffer;
  536. return true;
  537. }
  538. else
  539. {
  540. return false;
  541. }
  542. }
  543. };
  544. //==============================================================================
  545. struct DSoundInternalInChannel
  546. {
  547. String name;
  548. LPGUID guid;
  549. int sampleRate, bufferSizeSamples;
  550. float* leftBuffer;
  551. float* rightBuffer;
  552. IDirectSound* pDirectSound;
  553. IDirectSoundCapture* pDirectSoundCapture;
  554. IDirectSoundCaptureBuffer* pInputBuffer;
  555. public:
  556. unsigned int readOffset;
  557. int bytesPerBuffer, totalBytesPerBuffer;
  558. int bitDepth;
  559. bool doneFlag;
  560. DSoundInternalInChannel (const String& name_,
  561. LPGUID guid_,
  562. int rate,
  563. int bufferSize,
  564. float* left,
  565. float* right)
  566. : name (name_),
  567. guid (guid_),
  568. sampleRate (rate),
  569. bufferSizeSamples (bufferSize),
  570. leftBuffer (left),
  571. rightBuffer (right),
  572. pDirectSound (0),
  573. pDirectSoundCapture (0),
  574. pInputBuffer (0),
  575. bitDepth (16)
  576. {
  577. }
  578. ~DSoundInternalInChannel()
  579. {
  580. close();
  581. }
  582. void close()
  583. {
  584. HRESULT hr;
  585. if (pInputBuffer != 0)
  586. {
  587. JUCE_TRY
  588. {
  589. log (T("closing dsound in: ") + name);
  590. hr = pInputBuffer->Stop();
  591. logError (hr);
  592. }
  593. CATCH
  594. JUCE_TRY
  595. {
  596. hr = pInputBuffer->Release();
  597. logError (hr);
  598. }
  599. CATCH
  600. pInputBuffer = 0;
  601. }
  602. if (pDirectSoundCapture != 0)
  603. {
  604. JUCE_TRY
  605. {
  606. hr = pDirectSoundCapture->Release();
  607. logError (hr);
  608. }
  609. CATCH
  610. pDirectSoundCapture = 0;
  611. }
  612. if (pDirectSound != 0)
  613. {
  614. JUCE_TRY
  615. {
  616. hr = pDirectSound->Release();
  617. logError (hr);
  618. }
  619. CATCH
  620. pDirectSound = 0;
  621. }
  622. }
  623. const String open()
  624. {
  625. log (T("opening dsound in device: ") + name
  626. + T(" rate=") + String (sampleRate) + T(" bits=") + String (bitDepth) + T(" buf=") + String (bufferSizeSamples));
  627. pDirectSound = 0;
  628. pDirectSoundCapture = 0;
  629. pInputBuffer = 0;
  630. readOffset = 0;
  631. totalBytesPerBuffer = 0;
  632. String error;
  633. HRESULT hr = E_NOINTERFACE;
  634. if (dsDirectSoundCaptureCreate != 0)
  635. hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0);
  636. logError (hr);
  637. if (hr == S_OK)
  638. {
  639. const int numChannels = 2;
  640. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  641. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  642. WAVEFORMATEX wfFormat;
  643. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  644. wfFormat.nChannels = (unsigned short)numChannels;
  645. wfFormat.nSamplesPerSec = sampleRate;
  646. wfFormat.wBitsPerSample = (unsigned short)bitDepth;
  647. wfFormat.nBlockAlign = (unsigned short)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
  648. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  649. wfFormat.cbSize = 0;
  650. DSCBUFFERDESC captureDesc;
  651. zerostruct (captureDesc);
  652. captureDesc.dwSize = sizeof (DSCBUFFERDESC);
  653. captureDesc.dwFlags = 0;
  654. captureDesc.dwBufferBytes = totalBytesPerBuffer;
  655. captureDesc.lpwfxFormat = &wfFormat;
  656. log (T("opening dsound in step 2"));
  657. hr = pDirectSoundCapture->CreateCaptureBuffer (&captureDesc, &pInputBuffer, 0);
  658. logError (hr);
  659. if (hr == S_OK)
  660. {
  661. hr = pInputBuffer->Start (1 /* DSCBSTART_LOOPING */);
  662. logError (hr);
  663. if (hr == S_OK)
  664. return String::empty;
  665. }
  666. }
  667. error = getDSErrorMessage (hr);
  668. close();
  669. return error;
  670. }
  671. void synchronisePosition()
  672. {
  673. if (pInputBuffer != 0)
  674. {
  675. DWORD capturePos;
  676. pInputBuffer->GetCurrentPosition (&capturePos, (DWORD*)&readOffset);
  677. }
  678. }
  679. bool service()
  680. {
  681. if (pInputBuffer == 0)
  682. return true;
  683. DWORD capturePos, readPos;
  684. HRESULT hr = pInputBuffer->GetCurrentPosition (&capturePos, &readPos);
  685. logError (hr);
  686. if (hr != S_OK)
  687. return true;
  688. int bytesFilled = readPos - readOffset;
  689. if (bytesFilled < 0)
  690. bytesFilled += totalBytesPerBuffer;
  691. if (bytesFilled >= bytesPerBuffer)
  692. {
  693. LPBYTE lpbuf1 = 0;
  694. LPBYTE lpbuf2 = 0;
  695. DWORD dwsize1 = 0;
  696. DWORD dwsize2 = 0;
  697. HRESULT hr = pInputBuffer->Lock (readOffset,
  698. bytesPerBuffer,
  699. (void**) &lpbuf1, &dwsize1,
  700. (void**) &lpbuf2, &dwsize2, 0);
  701. if (hr == S_OK)
  702. {
  703. if (bitDepth == 16)
  704. {
  705. const float g = 1.0f / 32768.0f;
  706. float* destL = leftBuffer;
  707. float* destR = rightBuffer;
  708. int samples1 = dwsize1 >> 2;
  709. int samples2 = dwsize2 >> 2;
  710. const short* src = (const short*)lpbuf1;
  711. if (destL == 0)
  712. {
  713. while (--samples1 >= 0)
  714. {
  715. ++src;
  716. *destR++ = *src++ * g;
  717. }
  718. src = (const short*)lpbuf2;
  719. while (--samples2 >= 0)
  720. {
  721. ++src;
  722. *destR++ = *src++ * g;
  723. }
  724. }
  725. else if (destR == 0)
  726. {
  727. while (--samples1 >= 0)
  728. {
  729. *destL++ = *src++ * g;
  730. ++src;
  731. }
  732. src = (const short*)lpbuf2;
  733. while (--samples2 >= 0)
  734. {
  735. *destL++ = *src++ * g;
  736. ++src;
  737. }
  738. }
  739. else
  740. {
  741. while (--samples1 >= 0)
  742. {
  743. *destL++ = *src++ * g;
  744. *destR++ = *src++ * g;
  745. }
  746. src = (const short*)lpbuf2;
  747. while (--samples2 >= 0)
  748. {
  749. *destL++ = *src++ * g;
  750. *destR++ = *src++ * g;
  751. }
  752. }
  753. }
  754. else
  755. {
  756. jassertfalse
  757. }
  758. readOffset = (readOffset + dwsize1 + dwsize2) % totalBytesPerBuffer;
  759. pInputBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
  760. }
  761. else
  762. {
  763. logError (hr);
  764. jassertfalse
  765. }
  766. bytesFilled -= bytesPerBuffer;
  767. return true;
  768. }
  769. else
  770. {
  771. return false;
  772. }
  773. }
  774. };
  775. //==============================================================================
  776. static int findBestMatchForName (const String& name, const StringArray& names)
  777. {
  778. int i = names.indexOf (name);
  779. if (i >= 0)
  780. return i;
  781. StringArray tokens1;
  782. tokens1.addTokens (name, T(" :-"), 0);
  783. int bestResult = -1;
  784. int bestNumMatches = 1;
  785. for (i = 0; i < names.size(); ++i)
  786. {
  787. StringArray tokens2;
  788. tokens2.addTokens (names[i], T(" :-"), 0);
  789. int matches = 0;
  790. for (int j = tokens1.size(); --j >= 0;)
  791. if (tokens2.contains (tokens1 [j]))
  792. ++matches;
  793. if (matches > bestNumMatches)
  794. bestResult = i;
  795. }
  796. return bestResult;
  797. }
  798. class DSoundAudioIODevice : public AudioIODevice,
  799. public Thread
  800. {
  801. public:
  802. DSoundAudioIODevice (const String& deviceName,
  803. const int index,
  804. const int inputIndex_)
  805. : AudioIODevice (deviceName, "DirectSound"),
  806. Thread ("Juce DSound"),
  807. isOpen_ (false),
  808. isStarted (false),
  809. deviceIndex (index),
  810. inputIndex (inputIndex_),
  811. inChans (4),
  812. outChans (4),
  813. numInputBuffers (0),
  814. numOutputBuffers (0),
  815. totalSamplesOut (0),
  816. sampleRate (0.0),
  817. inputBuffers (0),
  818. outputBuffers (0),
  819. callback (0)
  820. {
  821. }
  822. ~DSoundAudioIODevice()
  823. {
  824. close();
  825. }
  826. const StringArray getOutputChannelNames()
  827. {
  828. return outChannels;
  829. }
  830. const StringArray getInputChannelNames()
  831. {
  832. return inChannels;
  833. }
  834. int getNumSampleRates()
  835. {
  836. return 4;
  837. }
  838. double getSampleRate (int index)
  839. {
  840. const double samps[] = { 44100.0, 48000.0, 88200.0, 96000.0 };
  841. return samps [jlimit (0, 3, index)];
  842. }
  843. int getNumBufferSizesAvailable()
  844. {
  845. return 50;
  846. }
  847. int getBufferSizeSamples (int index)
  848. {
  849. int n = 64;
  850. for (int i = 0; i < index; ++i)
  851. n += (n < 512) ? 32
  852. : ((n < 1024) ? 64
  853. : ((n < 2048) ? 128 : 256));
  854. return n;
  855. }
  856. int getDefaultBufferSize()
  857. {
  858. return 2560;
  859. }
  860. const String open (const BitArray& inputChannels,
  861. const BitArray& outputChannels,
  862. double sampleRate,
  863. int bufferSizeSamples)
  864. {
  865. BitArray ins, outs;
  866. if (deviceIndex >= 0)
  867. {
  868. if (outputChannels[0])
  869. outs.setBit (2 * deviceIndex);
  870. if (outputChannels[1])
  871. outs.setBit (2 * deviceIndex + 1);
  872. if (inputIndex >= 0)
  873. {
  874. if (inputChannels[0])
  875. ins.setBit (2 * inputIndex);
  876. if (inputChannels[1])
  877. ins.setBit (2 * inputIndex + 1);
  878. }
  879. }
  880. else
  881. {
  882. ins = inputChannels;
  883. outs = outputChannels;
  884. }
  885. lastError = openDevice (ins, outs, sampleRate, bufferSizeSamples);
  886. isOpen_ = lastError.isEmpty();
  887. return lastError;
  888. }
  889. void close()
  890. {
  891. stop();
  892. if (isOpen_)
  893. {
  894. closeDevice();
  895. isOpen_ = false;
  896. }
  897. }
  898. bool isOpen()
  899. {
  900. return isOpen_ && isThreadRunning();
  901. }
  902. int getCurrentBufferSizeSamples()
  903. {
  904. return bufferSizeSamples;
  905. }
  906. double getCurrentSampleRate()
  907. {
  908. return sampleRate;
  909. }
  910. int getCurrentBitDepth()
  911. {
  912. int i, bits = 256;
  913. for (i = inChans.size(); --i >= 0;)
  914. if (inChans[i] != 0)
  915. bits = jmin (bits, inChans[i]->bitDepth);
  916. for (i = outChans.size(); --i >= 0;)
  917. if (outChans[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. {
  1025. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1026. if (out != 0)
  1027. out->close();
  1028. }
  1029. for (i = inChans.size(); --i >= 0;)
  1030. {
  1031. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1032. if (in != 0)
  1033. in->close();
  1034. }
  1035. if (threadShouldExit())
  1036. return;
  1037. for (i = outChans.size(); --i >= 0;)
  1038. {
  1039. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1040. if (out != 0)
  1041. out->open();
  1042. }
  1043. for (i = inChans.size(); --i >= 0;)
  1044. {
  1045. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1046. if (in != 0)
  1047. in->open();
  1048. }
  1049. if (threadShouldExit())
  1050. return;
  1051. sleep (5);
  1052. for (i = 0; i < numOutputBuffers; ++i)
  1053. if (outChans[i] != 0)
  1054. outChans[i]->synchronisePosition();
  1055. for (i = 0; i < numInputBuffers; ++i)
  1056. if (inChans[i] != 0)
  1057. inChans[i]->synchronisePosition();
  1058. }
  1059. public:
  1060. void run()
  1061. {
  1062. while (! threadShouldExit())
  1063. {
  1064. if (wait (100))
  1065. break;
  1066. }
  1067. const int latencyMs = (int) (bufferSizeSamples * 1000.0 / sampleRate);
  1068. const int maxTimeMS = jmax (5, 3 * latencyMs);
  1069. while (! threadShouldExit())
  1070. {
  1071. int numToDo = 0;
  1072. uint32 startTime = Time::getMillisecondCounter();
  1073. int i;
  1074. for (i = inChans.size(); --i >= 0;)
  1075. {
  1076. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1077. if (in != 0)
  1078. {
  1079. in->doneFlag = false;
  1080. ++numToDo;
  1081. }
  1082. }
  1083. for (i = outChans.size(); --i >= 0;)
  1084. {
  1085. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1086. if (out != 0)
  1087. {
  1088. out->doneFlag = false;
  1089. ++numToDo;
  1090. }
  1091. }
  1092. if (numToDo > 0)
  1093. {
  1094. const int maxCount = 3;
  1095. int count = maxCount;
  1096. for (;;)
  1097. {
  1098. for (i = inChans.size(); --i >= 0;)
  1099. {
  1100. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1101. if (in != 0 && !in->doneFlag)
  1102. {
  1103. if (in->service())
  1104. {
  1105. in->doneFlag = true;
  1106. --numToDo;
  1107. }
  1108. }
  1109. }
  1110. for (i = outChans.size(); --i >= 0;)
  1111. {
  1112. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1113. if (out != 0 && !out->doneFlag)
  1114. {
  1115. if (out->service())
  1116. {
  1117. out->doneFlag = true;
  1118. --numToDo;
  1119. }
  1120. }
  1121. }
  1122. if (numToDo <= 0)
  1123. break;
  1124. if (Time::getMillisecondCounter() > startTime + maxTimeMS)
  1125. {
  1126. resync();
  1127. break;
  1128. }
  1129. if (--count <= 0)
  1130. {
  1131. Sleep (1);
  1132. count = maxCount;
  1133. }
  1134. if (threadShouldExit())
  1135. return;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. sleep (1);
  1141. }
  1142. const ScopedLock sl (startStopLock);
  1143. if (isStarted)
  1144. {
  1145. JUCE_TRY
  1146. {
  1147. callback->audioDeviceIOCallback ((const float**) inputBuffers,
  1148. numInputBuffers,
  1149. outputBuffers,
  1150. numOutputBuffers,
  1151. bufferSizeSamples);
  1152. }
  1153. JUCE_CATCH_EXCEPTION
  1154. totalSamplesOut += bufferSizeSamples;
  1155. }
  1156. else
  1157. {
  1158. for (i = 0; i < numOutputBuffers; ++i)
  1159. if (outputBuffers[i] != 0)
  1160. zeromem (outputBuffers[i], bufferSizeSamples * sizeof (float));
  1161. totalSamplesOut = 0;
  1162. sleep (1);
  1163. }
  1164. }
  1165. }
  1166. };
  1167. //==============================================================================
  1168. class DSoundAudioIODeviceType : public AudioIODeviceType
  1169. {
  1170. public:
  1171. DSoundAudioIODeviceType()
  1172. : AudioIODeviceType (T("DirectSound")),
  1173. hasScanned (false)
  1174. {
  1175. initialiseDSoundFunctions();
  1176. }
  1177. ~DSoundAudioIODeviceType()
  1178. {
  1179. }
  1180. //==============================================================================
  1181. void scanForDevices()
  1182. {
  1183. hasScanned = true;
  1184. outputDeviceNames.clear();
  1185. outputGuids.clear();
  1186. inputDeviceNames.clear();
  1187. inputGuids.clear();
  1188. if (dsDirectSoundEnumerateW != 0)
  1189. {
  1190. dsDirectSoundEnumerateW (outputEnumProcW, this);
  1191. dsDirectSoundCaptureEnumerateW (inputEnumProcW, this);
  1192. }
  1193. }
  1194. const StringArray getDeviceNames (const bool preferInputNames) const
  1195. {
  1196. jassert (hasScanned); // need to call scanForDevices() before doing this
  1197. return preferInputNames ? inputDeviceNames
  1198. : outputDeviceNames;
  1199. }
  1200. const String getDefaultDeviceName (const bool preferInputNames,
  1201. const int /*numInputChannelsNeeded*/,
  1202. const int /*numOutputChannelsNeeded*/) 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. enabledInputs.clear();
  1331. enabledOutputs.clear();
  1332. sampleRate = sampleRate_;
  1333. if (bufferSizeSamples_ <= 0)
  1334. bufferSizeSamples_ = 960; // use as a default size if none is set.
  1335. bufferSizeSamples = bufferSizeSamples_ & ~7;
  1336. DSoundAudioIODeviceType dlh;
  1337. dlh.scanForDevices();
  1338. numInputBuffers = 2 * dlh.inputDeviceNames.size();
  1339. inputBuffers = new float* [numInputBuffers + 2];
  1340. numOutputBuffers = 2 * dlh.outputDeviceNames.size();
  1341. outputBuffers = new float* [numOutputBuffers + 2];
  1342. int i;
  1343. for (i = 0; i < numInputBuffers + 2; ++i)
  1344. {
  1345. if (inputChannels[i] && i < numInputBuffers)
  1346. {
  1347. inputBuffers[i] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1348. enabledInputs.setBit (i);
  1349. }
  1350. else
  1351. {
  1352. inputBuffers[i] = 0;
  1353. }
  1354. }
  1355. for (i = 0; i < numOutputBuffers + 2; ++i)
  1356. {
  1357. if (outputChannels[i] && i < numOutputBuffers)
  1358. {
  1359. outputBuffers[i] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1360. enabledOutputs.setBit (i);
  1361. }
  1362. else
  1363. {
  1364. outputBuffers[i] = 0;
  1365. }
  1366. }
  1367. for (i = 0; i < numInputBuffers; ++i)
  1368. {
  1369. if (inputChannels[i] || inputChannels[i + 1])
  1370. {
  1371. inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [i / 2],
  1372. dlh.inputGuids [i / 2],
  1373. (int) sampleRate, bufferSizeSamples,
  1374. inputBuffers[i], inputBuffers[i + 1]));
  1375. }
  1376. else
  1377. {
  1378. inChans.add (0);
  1379. }
  1380. ++i;
  1381. }
  1382. for (i = 0; i < numOutputBuffers; ++i)
  1383. {
  1384. if (outputChannels[i] || outputChannels[i + 1])
  1385. {
  1386. outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[i / 2],
  1387. dlh.outputGuids [i / 2],
  1388. (int) sampleRate, bufferSizeSamples,
  1389. outputBuffers[i], outputBuffers[i + 1]));
  1390. }
  1391. else
  1392. {
  1393. outChans.add (0);
  1394. }
  1395. ++i;
  1396. }
  1397. String error;
  1398. for (i = 0; i < numOutputBuffers; ++i)
  1399. {
  1400. if (outChans[i] != 0)
  1401. {
  1402. error = outChans[i]->open();
  1403. if (error.isNotEmpty())
  1404. {
  1405. error = T("Error opening ") + dlh.outputDeviceNames[i]
  1406. + T(": \"") + error + T("\"");
  1407. break;
  1408. }
  1409. }
  1410. }
  1411. if (error.isEmpty())
  1412. {
  1413. for (i = 0; i < numInputBuffers; ++i)
  1414. {
  1415. if (inChans[i] != 0)
  1416. {
  1417. error = inChans[i]->open();
  1418. if (error.isNotEmpty())
  1419. {
  1420. error = T("Error opening ") + dlh.inputDeviceNames[i]
  1421. + T(": \"") + error + T("\"");
  1422. break;
  1423. }
  1424. }
  1425. }
  1426. }
  1427. if (error.isNotEmpty())
  1428. {
  1429. log (error);
  1430. return error;
  1431. }
  1432. totalSamplesOut = 0;
  1433. startThread (9);
  1434. sleep (10);
  1435. for (i = 0; i < numOutputBuffers; ++i)
  1436. if (outChans[i] != 0)
  1437. outChans[i]->synchronisePosition();
  1438. for (i = 0; i < numInputBuffers; ++i)
  1439. if (inChans[i] != 0)
  1440. inChans[i]->synchronisePosition();
  1441. notify();
  1442. return String::empty;
  1443. }
  1444. END_JUCE_NAMESPACE