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.

1786 lines
53KB

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