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.

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