Leaked source code of windows server 2003
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.

1780 lines
52 KiB

  1. //
  2. // Copyright (c) 1996-2001 Microsoft Corporation
  3. // UMSynth.cpp : Implementation of CUserModeSynth
  4. //
  5. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  6. //
  7. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  8. //
  9. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  10. // sources).
  11. //
  12. // The one place we use exceptions is around construction of objects that call
  13. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  14. // the restriction given by not using -GX (automatic objects in the call chain between
  15. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  16. // size because of the unwind code.
  17. //
  18. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  19. //
  20. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  21. //
  22. #pragma warning(disable:4530)
  23. #include <objbase.h>
  24. #include <mmsystem.h>
  25. #include <dsoundp.h>
  26. #include <ks.h>
  27. #include "debug.h"
  28. #include "UMSynth.h"
  29. #include "dmusicc.h"
  30. #include "dmusics.h"
  31. #include "math.h"
  32. #include "misc.h"
  33. #include "dmksctrl.h"
  34. #include "dsoundp.h" // For IDirectSoundSource
  35. #include "..\shared\dmusiccp.h" // For class ids.
  36. #include <dmusprop.h>
  37. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
  38. #include "..\shared\validate.h"
  39. #if 0 // The following section will only take affect in the DDK sample.
  40. // @@END_DDKSPLIT
  41. #include "validate.h"
  42. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample.
  43. #endif
  44. // @@END_DDKSPLIT
  45. extern long g_cComponent;
  46. /////////////////////////////////////////////////////////////////////
  47. // User mode registry helper
  48. //
  49. BOOL GetRegValueDword(
  50. LPCTSTR szRegPath,
  51. LPCTSTR szValueName,
  52. LPDWORD pdwValue)
  53. {
  54. HKEY hKeyOpen;
  55. DWORD dwType;
  56. DWORD dwCbData;
  57. LONG lResult;
  58. BOOL fReturn = FALSE;
  59. assert(pdwValue);
  60. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  61. szRegPath,
  62. 0, KEY_QUERY_VALUE,
  63. &hKeyOpen );
  64. if (lResult == ERROR_SUCCESS)
  65. {
  66. dwCbData = sizeof(DWORD);
  67. lResult = RegQueryValueEx(hKeyOpen,
  68. szValueName,
  69. NULL,
  70. &dwType,
  71. (LPBYTE)pdwValue,
  72. &dwCbData);
  73. if (lResult == ERROR_SUCCESS &&
  74. dwType == REG_DWORD)
  75. {
  76. fReturn = TRUE;
  77. }
  78. RegCloseKey( hKeyOpen );
  79. }
  80. return fReturn;
  81. }
  82. DWORD GetTheCurrentTime()
  83. {
  84. static BOOL s_fFirstTime = TRUE;
  85. static LARGE_INTEGER s_liPerfFrequency;
  86. static BOOL s_fUsePerfCounter = FALSE;
  87. if (s_fFirstTime)
  88. {
  89. s_fFirstTime = FALSE;
  90. s_fUsePerfCounter = QueryPerformanceFrequency(&s_liPerfFrequency);
  91. s_liPerfFrequency.QuadPart /= 1000;
  92. }
  93. if (s_fUsePerfCounter)
  94. {
  95. LARGE_INTEGER liPerfCounter;
  96. QueryPerformanceCounter(&liPerfCounter);
  97. liPerfCounter.QuadPart /= s_liPerfFrequency.QuadPart;
  98. return (DWORD) liPerfCounter.QuadPart;
  99. }
  100. else
  101. {
  102. return timeGetTime();
  103. }
  104. }
  105. /////////////////////////////////////////////////////////////////////////////
  106. // CUserModeSynth
  107. HRESULT CUserModeSynth::Init()
  108. {
  109. return S_OK;
  110. }
  111. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
  112. HRESULT CUserModeSynth::UseDefaultSynthSink()
  113. {
  114. HRESULT hr = S_OK;
  115. if (!m_pSynthSink)
  116. {
  117. IDirectMusicSynthSink *pSink = NULL;
  118. hr = CoCreateInstance(CLSID_DirectMusicSynthSink,
  119. NULL,
  120. CLSCTX_INPROC_SERVER,
  121. IID_IDirectMusicSynthSink,
  122. (void **) &pSink);
  123. if (pSink)
  124. {
  125. SetSynthSink(pSink);
  126. pSink->Release();
  127. }
  128. }
  129. return hr;
  130. }
  131. // @@END_DDKSPLIT
  132. CUserModeSynth::CUserModeSynth()
  133. {
  134. InterlockedIncrement(&g_cComponent);
  135. m_fCSInitialized = FALSE;
  136. ::InitializeCriticalSection(&m_CriticalSection);
  137. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  138. // ever pops in stress, we can add an exception handler and retry loop.
  139. m_fCSInitialized = TRUE;
  140. m_cRef = 0;
  141. m_dwSampleRate = 22050;
  142. m_dwChannels = 2;
  143. m_lVolume = 0;
  144. m_lBoost = 6 * 100;
  145. m_lGainAdjust = 6 * 100; // Default 6 dB boost
  146. m_fActive = FALSE;
  147. m_pSynth = NULL;
  148. m_pSynthSink = NULL;
  149. m_pSynthSink8 = NULL;
  150. m_ullPosition = 0;
  151. m_dwBufferFlags = BUFFERFLAG_INTERLEAVED;
  152. }
  153. CUserModeSynth::~CUserModeSynth()
  154. {
  155. Activate(FALSE);
  156. if (m_fCSInitialized)
  157. {
  158. ::EnterCriticalSection(&m_CriticalSection);
  159. if (m_pSynth)
  160. {
  161. delete m_pSynth;
  162. m_pSynth = NULL;
  163. }
  164. if (m_pSynthSink)
  165. {
  166. m_pSynthSink->Release();
  167. }
  168. if (m_pSynthSink8)
  169. {
  170. m_pSynthSink8->Release();
  171. }
  172. ::LeaveCriticalSection(&m_CriticalSection);
  173. ::DeleteCriticalSection(&m_CriticalSection);
  174. }
  175. InterlockedDecrement(&g_cComponent);
  176. }
  177. // CUserModeSynth::QueryInterface
  178. //
  179. STDMETHODIMP
  180. CUserModeSynth::QueryInterface(const IID &iid, void **ppv)
  181. {
  182. V_INAME(IDirectMusicSynth::QueryInterface);
  183. V_REFGUID(iid);
  184. V_PTRPTR_WRITE(ppv);
  185. if (iid == IID_IUnknown || iid == IID_IDirectMusicSynth) {
  186. *ppv = static_cast<IDirectMusicSynth*>(this);
  187. }
  188. else if (iid == IID_IKsControl)
  189. {
  190. *ppv = static_cast<IKsControl*>(this);
  191. }
  192. else if (iid == IID_IDirectMusicSynth8 )
  193. {
  194. *ppv = static_cast<IDirectMusicSynth8*>(this);
  195. }
  196. else if (iid == IID_IDirectSoundSource)
  197. {
  198. *ppv = static_cast<IDirectSoundSource*>(this);
  199. }
  200. else
  201. {
  202. *ppv = NULL;
  203. return E_NOINTERFACE;
  204. }
  205. reinterpret_cast<IUnknown*>(this)->AddRef();
  206. return S_OK;
  207. }
  208. // CUserModeSynth::AddRef
  209. //
  210. STDMETHODIMP_(ULONG)
  211. CUserModeSynth::AddRef()
  212. {
  213. return InterlockedIncrement(&m_cRef);
  214. }
  215. // CUserModeSynth::Release
  216. //
  217. STDMETHODIMP_(ULONG)
  218. CUserModeSynth::Release()
  219. {
  220. if (!InterlockedDecrement(&m_cRef)) {
  221. delete this;
  222. return 0;
  223. }
  224. return m_cRef;
  225. }
  226. STDMETHODIMP CUserModeSynth::SetSynthSink(
  227. IDirectMusicSynthSink *pSynthSink) // <i IDirectMusicSynthSink> to connect to synth, or
  228. // NULL to disconnect.
  229. {
  230. HRESULT hr = S_OK;
  231. V_INAME(IDirectMusicSynth::SetSynthSink);
  232. V_INTERFACE_OPT(pSynthSink);
  233. ::EnterCriticalSection(&m_CriticalSection);
  234. //>>>>>>>>. RELEASE THE DSINK IF PRESENT !!!!
  235. if (m_pSynthSink)
  236. {
  237. hr = m_pSynthSink->Init(NULL);
  238. m_pSynthSink->Release();
  239. }
  240. m_pSynthSink = pSynthSink;
  241. //>>>>>>>>> the current state of the format of the the synth is
  242. //>>>>>>>>> ambiguos if a sink has been previously applied.
  243. m_dwBufferFlags &= ~BUFFERFLAG_MULTIBUFFER; // .... just in case
  244. if (m_pSynthSink)
  245. {
  246. m_pSynthSink->AddRef();
  247. hr = m_pSynthSink->Init(static_cast<IDirectMusicSynth*>(this));
  248. }
  249. ::LeaveCriticalSection(&m_CriticalSection);
  250. return hr;
  251. }
  252. STDMETHODIMP CUserModeSynth::Open(
  253. LPDMUS_PORTPARAMS pPortParams) // <t DMUS_PORTPARAMS> structure for opening the port. If NULL, default settings are used.
  254. {
  255. V_INAME(IDirectMusicSynth::Open);
  256. //if (pPortParams == NULL)
  257. //{
  258. // Trace(1, "Error: Open called with NULL PortParams.\n");
  259. // return E_FAIL;
  260. //}
  261. DWORD cbPortParams = 0;
  262. DWORD dwVer;
  263. if (pPortParams)
  264. {
  265. V_STRUCTPTR_READ_VER(pPortParams, dwVer);
  266. V_STRUCTPTR_READ_VER_CASE(DMUS_PORTPARAMS, 7);
  267. V_STRUCTPTR_READ_VER_CASE(DMUS_PORTPARAMS, 8);
  268. V_STRUCTPTR_READ_VER_END(DMUS_PORTPARAMS, pPortParams);
  269. switch (dwVer)
  270. {
  271. case 7:
  272. cbPortParams = sizeof(DMUS_PORTPARAMS7);
  273. break;
  274. case 8:
  275. cbPortParams = sizeof(DMUS_PORTPARAMS8);
  276. break;
  277. }
  278. }
  279. bool bPartialOpen = false;
  280. DMUS_PORTPARAMS myParams;
  281. myParams.dwSize = sizeof (myParams);
  282. myParams.dwVoices = 32;
  283. myParams.dwChannelGroups = 2;
  284. myParams.dwAudioChannels = 2;
  285. myParams.dwSampleRate = 22050;
  286. #ifdef REVERB_ENABLED
  287. myParams.dwEffectFlags = DMUS_EFFECT_REVERB;
  288. #else
  289. myParams.dwEffectFlags = DMUS_EFFECT_NONE;
  290. #endif
  291. myParams.fShare = FALSE;
  292. myParams.dwValidParams =
  293. DMUS_PORTPARAMS_VOICES |
  294. DMUS_PORTPARAMS_CHANNELGROUPS |
  295. DMUS_PORTPARAMS_AUDIOCHANNELS |
  296. DMUS_PORTPARAMS_SAMPLERATE |
  297. DMUS_PORTPARAMS_EFFECTS |
  298. DMUS_PORTPARAMS_SHARE;
  299. if (pPortParams)
  300. {
  301. if (pPortParams->dwSize >= sizeof(DMUS_PORTPARAMS8))
  302. {
  303. myParams.dwValidParams |= DMUS_PORTPARAMS_FEATURES;
  304. myParams.dwFeatures = 0;
  305. }
  306. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_VOICES)
  307. {
  308. if (pPortParams->dwVoices)
  309. {
  310. if (pPortParams->dwVoices <= MAX_VOICES)
  311. {
  312. myParams.dwVoices = pPortParams->dwVoices;
  313. }
  314. else
  315. {
  316. bPartialOpen = true;
  317. myParams.dwVoices = MAX_VOICES;
  318. }
  319. }
  320. else
  321. {
  322. bPartialOpen = true;
  323. myParams.dwVoices = 1; // MIN_VOICES
  324. }
  325. }
  326. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS)
  327. {
  328. if (pPortParams->dwChannelGroups)
  329. {
  330. if (pPortParams->dwChannelGroups <= MAX_CHANNEL_GROUPS)
  331. {
  332. myParams.dwChannelGroups = pPortParams->dwChannelGroups;
  333. }
  334. else
  335. {
  336. bPartialOpen = true;
  337. myParams.dwChannelGroups = MAX_CHANNEL_GROUPS;
  338. }
  339. }
  340. else
  341. {
  342. bPartialOpen = true;
  343. myParams.dwChannelGroups = 1; // MIN_CHANNEL_GROUPS
  344. }
  345. }
  346. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS)
  347. {
  348. if (pPortParams->dwAudioChannels)
  349. {
  350. if (pPortParams->dwAudioChannels <= 2)
  351. {
  352. myParams.dwAudioChannels = pPortParams->dwAudioChannels;
  353. }
  354. else
  355. {
  356. bPartialOpen = true;
  357. myParams.dwAudioChannels = 2; // MAX_AUDIO_CHANNELS
  358. }
  359. }
  360. else
  361. {
  362. bPartialOpen = true;
  363. myParams.dwAudioChannels = 1; // MIN_AUDIO_CHANNELS
  364. }
  365. }
  366. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_SAMPLERATE)
  367. {
  368. if (dwVer == 7)
  369. {
  370. // DX-7 compat: clamp sample rate to one of the
  371. // understood rates.
  372. //
  373. if (pPortParams->dwSampleRate > 30000)
  374. {
  375. if(pPortParams->dwSampleRate != 44100)
  376. {
  377. bPartialOpen = true;
  378. }
  379. myParams.dwSampleRate = 44100;
  380. }
  381. else if (pPortParams->dwSampleRate > 15000)
  382. {
  383. if(pPortParams->dwSampleRate != 22050)
  384. {
  385. bPartialOpen = true;
  386. }
  387. myParams.dwSampleRate = 22050;
  388. }
  389. else
  390. {
  391. if(pPortParams->dwSampleRate != 11025)
  392. {
  393. bPartialOpen = true;
  394. }
  395. myParams.dwSampleRate = 11025;
  396. }
  397. }
  398. else
  399. {
  400. if (pPortParams->dwSampleRate > 96000)
  401. {
  402. bPartialOpen = true;
  403. myParams.dwSampleRate = 96000;
  404. }
  405. else if (pPortParams->dwSampleRate < 11025)
  406. {
  407. bPartialOpen = true;
  408. myParams.dwSampleRate = 11025;
  409. }
  410. else myParams.dwSampleRate = pPortParams->dwSampleRate;
  411. }
  412. }
  413. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_EFFECTS)
  414. {
  415. if (pPortParams->dwEffectFlags & ~DMUS_EFFECT_REVERB)
  416. {
  417. bPartialOpen = true;
  418. pPortParams->dwEffectFlags &= DMUS_EFFECT_REVERB;
  419. }
  420. #ifdef REVERB_ENABLED
  421. myParams.dwEffectFlags = pPortParams->dwEffectFlags;
  422. #else
  423. myParams.dwEffectFlags = DMUS_EFFECT_NONE;
  424. if (pPortParams->dwEffectFlags & DMUS_EFFECT_REVERB)
  425. {
  426. bPartialOpen = true;
  427. }
  428. #endif
  429. }
  430. if (pPortParams->dwValidParams & DMUS_PORTPARAMS_SHARE)
  431. {
  432. if (pPortParams->fShare)
  433. {
  434. bPartialOpen = true;
  435. }
  436. }
  437. if ((pPortParams->dwValidParams & DMUS_PORTPARAMS_FEATURES) &&
  438. (pPortParams->dwSize >= sizeof(DMUS_PORTPARAMS8)))
  439. {
  440. myParams.dwFeatures = pPortParams->dwFeatures;
  441. }
  442. }
  443. if (pPortParams)
  444. {
  445. DWORD dwSize = min(cbPortParams, myParams.dwSize);
  446. memcpy(pPortParams, &myParams, dwSize);
  447. pPortParams->dwSize = dwSize;
  448. }
  449. m_dwSampleRate = myParams.dwSampleRate;
  450. m_dwChannels = myParams.dwAudioChannels;
  451. m_dwBufferFlags = (m_dwChannels==1)?BUFFERFLAG_MONO:BUFFERFLAG_INTERLEAVED;
  452. ::EnterCriticalSection(&m_CriticalSection);
  453. HRESULT hr = DMUS_E_ALREADYOPEN;
  454. if (!m_pSynth)
  455. {
  456. try
  457. {
  458. m_pSynth = new CSynth;
  459. }
  460. catch( ... )
  461. {
  462. m_pSynth = NULL;
  463. }
  464. if (!m_pSynth)
  465. {
  466. hr = E_OUTOFMEMORY;
  467. }
  468. else
  469. {
  470. hr = m_pSynth->Open(myParams.dwChannelGroups,
  471. myParams.dwVoices,
  472. (myParams.dwEffectFlags & DMUS_EFFECT_REVERB) ? TRUE : FALSE);
  473. if (SUCCEEDED(hr))
  474. {
  475. m_pSynth->SetGainAdjust(m_lGainAdjust);
  476. m_pSynth->Activate(m_dwSampleRate, m_dwBufferFlags);
  477. }
  478. else
  479. {
  480. delete m_pSynth;
  481. m_pSynth = NULL;
  482. }
  483. }
  484. }
  485. ::LeaveCriticalSection(&m_CriticalSection);
  486. if(SUCCEEDED(hr))
  487. {
  488. if(bPartialOpen)
  489. {
  490. hr = S_FALSE;
  491. }
  492. }
  493. return hr;
  494. }
  495. STDMETHODIMP CUserModeSynth::SetNumChannelGroups(
  496. DWORD dwGroups) // Number of ChannelGroups requested.
  497. {
  498. ::EnterCriticalSection(&m_CriticalSection);
  499. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  500. if (m_pSynth)
  501. {
  502. hr = m_pSynth->SetNumChannelGroups(dwGroups);
  503. }
  504. ::LeaveCriticalSection(&m_CriticalSection);
  505. return hr;
  506. }
  507. STDMETHODIMP CUserModeSynth::Close()
  508. {
  509. ::EnterCriticalSection(&m_CriticalSection);
  510. HRESULT hr = DMUS_E_ALREADYCLOSED;
  511. if (m_pSynth)
  512. {
  513. hr = m_pSynth->Close();
  514. delete m_pSynth;
  515. m_pSynth = NULL;
  516. }
  517. ::LeaveCriticalSection(&m_CriticalSection);
  518. return hr;
  519. }
  520. STDMETHODIMP CUserModeSynth::Download(
  521. LPHANDLE phDownload, // Pointer to download handle, to be created by <om IDirectMusicSynth::Download> and used later to unload the data.
  522. LPVOID pvData, // Pointer to continuous memory segment with download data.
  523. LPBOOL pbFree) // <p pbFree> indicates whether the synthesizer wishes to keep the memory in <p pvData> allocated.
  524. {
  525. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  526. V_INAME(IDirectMusicSynth::Download);
  527. V_PTR_WRITE(phDownload, HANDLE);
  528. V_PTR_WRITE(pbFree, BOOL);
  529. // pvData is validated inside synth while parsing.
  530. ::EnterCriticalSection(&m_CriticalSection);
  531. if (m_pSynth)
  532. {
  533. hr = m_pSynth->Download(phDownload, pvData, pbFree);
  534. }
  535. ::LeaveCriticalSection(&m_CriticalSection);
  536. return hr;
  537. }
  538. STDMETHODIMP CUserModeSynth::Unload(
  539. HANDLE hDownload, // Handle to data, previously downloaded with a call to <om IDirectMusicSynth::Download>.
  540. HRESULT ( CALLBACK *lpFreeHandle)(HANDLE, HANDLE), // If the original call to
  541. // <om IDirectMusicSynth::Download> returned FALSE in <p pbFree>,
  542. // the synthesizer hung onto the memory in the download chunk. If so,
  543. // the caller must be notified once the memory has been freed,
  544. // but that could occur later than <om IDirectMusicSynth::Download>
  545. // since a wave might be currently in use. <p lpFreeHandle> is a
  546. // pointer to a callback
  547. // function which will be called when the memory is no longer in use.
  548. HANDLE hUserData) // Pointer to user data, passed as a parameter to the
  549. // <p lpFreeHandle> function, typically used so the callback routine can retrieve
  550. // its state.
  551. {
  552. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  553. ::EnterCriticalSection(&m_CriticalSection);
  554. if (m_pSynth)
  555. {
  556. hr = m_pSynth->Unload(hDownload, lpFreeHandle, hUserData);
  557. }
  558. ::LeaveCriticalSection(&m_CriticalSection);
  559. return hr;
  560. }
  561. STDMETHODIMP CUserModeSynth::PlayBuffer(
  562. REFERENCE_TIME rt, // Start time of the buffer. This should be in
  563. // REFERENCE_TIME units, relative to the master
  564. // clock, previously set with a call to <om IDirectMusicSynth::SetMasterClock>.
  565. // And, this should be after the time returned by the clock in
  566. // <om IDirectMusicSynth::GetLatencyClock>.
  567. LPBYTE pbBuffer, // Memory chunk with all the MIDI events, generated by <i IDirectMusicBuffer>.
  568. DWORD cbBuffer) // Size of buffer.
  569. {
  570. class MIDIEVENT : public DMUS_EVENTHEADER {
  571. public:
  572. BYTE abEvent[4]; /* Actual event data, rounded up to be an even number */
  573. /* of QWORD's (8 bytes) */
  574. };
  575. typedef class MIDIEVENT FAR *LPMIDIEVENT;
  576. #define QWORD_ALIGN(x) (((x) + 7) & ~7)
  577. HRESULT hr = DMUS_E_NOT_INIT;
  578. V_INAME(IDirectMusicSynth::PlayBuffer);
  579. V_BUFPTR_READ(pbBuffer, cbBuffer);
  580. ::EnterCriticalSection(&m_CriticalSection);
  581. if (!m_pSynthSink && !m_pSynthSink8)
  582. {
  583. ::LeaveCriticalSection(&m_CriticalSection);
  584. return DMUS_E_NOSYNTHSINK;
  585. }
  586. if (!m_fActive)
  587. {
  588. ::LeaveCriticalSection(&m_CriticalSection);
  589. Trace(3, "Warning: Synth is inactive, can not process MIDI events.\n");
  590. return DMUS_E_SYNTHINACTIVE;
  591. }
  592. LPMIDIEVENT lpEventHdr;
  593. DWORD cbEvent;
  594. while (cbBuffer)
  595. {
  596. if (cbBuffer < sizeof(DMUS_EVENTHEADER))
  597. {
  598. Trace(1, "Error: PlayBuffer called with error in buffer size.\n");
  599. ::LeaveCriticalSection(&m_CriticalSection);
  600. return E_INVALIDARG;
  601. }
  602. lpEventHdr = (LPMIDIEVENT)pbBuffer;
  603. cbEvent = DMUS_EVENT_SIZE(lpEventHdr->cbEvent);
  604. if (cbEvent > cbBuffer)
  605. {
  606. Trace(1, "Error: PlayBuffer called with error in event size.\n");
  607. ::LeaveCriticalSection(&m_CriticalSection);
  608. return E_INVALIDARG;
  609. }
  610. pbBuffer += cbEvent;
  611. cbBuffer -= cbEvent;
  612. if ( m_pSynthSink )
  613. {
  614. hr = m_pSynth->PlayBuffer(m_pSynthSink,
  615. rt + lpEventHdr->rtDelta,
  616. &lpEventHdr->abEvent[0],
  617. lpEventHdr->cbEvent,
  618. lpEventHdr->dwChannelGroup);
  619. }
  620. if ( m_pSynthSink8 )
  621. {
  622. hr = m_pSynth->PlayBuffer(m_pSynthSink8,
  623. rt + lpEventHdr->rtDelta,
  624. &lpEventHdr->abEvent[0],
  625. lpEventHdr->cbEvent,
  626. lpEventHdr->dwChannelGroup);
  627. }
  628. if (FAILED(hr))
  629. {
  630. ::LeaveCriticalSection(&m_CriticalSection);
  631. return hr;
  632. }
  633. }
  634. ::LeaveCriticalSection(&m_CriticalSection);
  635. return S_OK;
  636. }
  637. STDMETHODIMP CUserModeSynth::GetPortCaps(
  638. LPDMUS_PORTCAPS pCaps) // <t DMUS_PORTCAPS> structure to be filled in by synth.
  639. {
  640. V_INAME(IDirectMusicSynth::GetPortCaps);
  641. V_STRUCTPTR_WRITE(pCaps, DMUS_PORTCAPS);
  642. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
  643. wcscpy(pCaps->wszDescription, L"Microsoft Synthesizer");
  644. #if 0 // The following section will only take affect in the DDK sample.
  645. // @@END_DDKSPLIT
  646. wcscpy(pCaps->wszDescription, L"Microsoft DDK Synthesizer");
  647. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample.
  648. #endif
  649. // @@END_DDKSPLIT
  650. pCaps->dwClass = DMUS_PC_OUTPUTCLASS;
  651. pCaps->dwType = DMUS_PORT_USER_MODE_SYNTH;
  652. pCaps->dwFlags = DMUS_PC_DLS | DMUS_PC_DLS2 | DMUS_PC_SOFTWARESYNTH |
  653. DMUS_PC_DIRECTSOUND | DMUS_PC_AUDIOPATH | DMUS_PC_WAVE;
  654. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
  655. pCaps->guidPort = CLSID_DirectMusicSynth;
  656. #if 0 // The following section will only take affect in the DDK sample.
  657. // @@END_DDKSPLIT
  658. pCaps->guidPort = CLSID_DDKSynth;
  659. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample.
  660. #endif
  661. // @@END_DDKSPLIT
  662. pCaps->dwMemorySize = DMUS_PC_SYSTEMMEMORY;
  663. pCaps->dwMaxChannelGroups = MAX_CHANNEL_GROUPS;
  664. pCaps->dwMaxVoices = MAX_VOICES;
  665. pCaps->dwMaxAudioChannels = 2;
  666. pCaps->dwEffectFlags = 0;
  667. // @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
  668. pCaps->dwEffectFlags = DMUS_EFFECT_REVERB;
  669. // @@END_DDKSPLIT
  670. return S_OK;
  671. }
  672. STDMETHODIMP CUserModeSynth::SetMasterClock(
  673. IReferenceClock *pClock) // Pointer to master <i IReferenceClock>,
  674. // used by all devices in current instance of DirectMusic.
  675. {
  676. V_INAME(IDirectMusicSynth::SetMasterClock);
  677. V_INTERFACE(pClock);
  678. return S_OK;
  679. }
  680. STDMETHODIMP CUserModeSynth::GetLatencyClock(
  681. IReferenceClock **ppClock) // <i IReferenceClock> interface designed to return the current mix time.
  682. {
  683. IDirectSoundSynthSink* pDSSink = NULL;
  684. V_INAME(IDirectMusicSynth::GetLatencyClock);
  685. V_PTR_WRITE(ppClock, IReferenceClock *);
  686. HRESULT hr = DMUS_E_NOSYNTHSINK;
  687. ::EnterCriticalSection(&m_CriticalSection);
  688. if (m_pSynthSink)
  689. {
  690. hr = m_pSynthSink->GetLatencyClock(ppClock);
  691. ::LeaveCriticalSection(&m_CriticalSection);
  692. }
  693. else if (m_pSynthSink8)
  694. {
  695. pDSSink = m_pSynthSink8;
  696. ::LeaveCriticalSection(&m_CriticalSection);
  697. // FIXME:: The call to GetLatencyClock requres the DSound DLL Mutex and
  698. // so we have to be outside of the Synth CriticalSection to make the call
  699. // In theory, pDSSink could have been released by another thread at this point
  700. //
  701. // That happens if we get a simultaneous call to the destructor or to SetSink.
  702. try
  703. {
  704. hr = pDSSink->GetLatencyClock(ppClock);
  705. }
  706. catch(...)
  707. {
  708. // If we're here the pointer to pDSSink has gone bad.
  709. hr = E_UNEXPECTED;
  710. }
  711. }
  712. else // still need to leave the critical section...
  713. {
  714. ::LeaveCriticalSection(&m_CriticalSection);
  715. }
  716. return hr;
  717. }
  718. STDMETHODIMP CUserModeSynth::Activate(
  719. BOOL fEnable) // Whether to activate or deactivate audio.
  720. {
  721. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  722. // ::EnterCriticalSection(&m_CriticalSection);
  723. if (fEnable)
  724. {
  725. if (m_pSynthSink || m_pSynthSink8)
  726. {
  727. if (!m_fActive)
  728. {
  729. if (m_dwSampleRate && m_dwChannels)
  730. {
  731. if (m_pSynth)
  732. {
  733. m_pSynth->Activate(m_dwSampleRate, m_dwBufferFlags);
  734. if (m_pSynthSink)
  735. {
  736. if (SUCCEEDED(m_pSynthSink->Activate(fEnable)))
  737. {
  738. m_fActive = TRUE;
  739. hr = S_OK;
  740. }
  741. }
  742. if ( m_pSynthSink8 )
  743. {
  744. hr = m_pSynthSink8->Activate(fEnable);
  745. if (SUCCEEDED(hr) || hr == DMUS_E_SYNTHACTIVE)
  746. {
  747. m_fActive = TRUE;
  748. hr = S_OK;
  749. }
  750. }
  751. }
  752. }
  753. }
  754. else
  755. {
  756. Trace(1, "Error: Synth::Activate- synth already active\n");
  757. hr = DMUS_E_SYNTHACTIVE;
  758. //>>>>>>>>>>>>>>>>>>>>> what's this about test it before removing????
  759. hr = S_FALSE;
  760. }
  761. }
  762. else
  763. {
  764. Trace(1, "Error: Synth::Activate- sink not connected\n");
  765. hr = DMUS_E_NOSYNTHSINK;
  766. }
  767. }
  768. else
  769. {
  770. if (m_fActive)
  771. {
  772. m_fActive = FALSE;
  773. if (m_pSynth)
  774. {
  775. m_pSynth->Deactivate();
  776. }
  777. if (m_pSynthSink)
  778. {
  779. if (SUCCEEDED(m_pSynthSink->Activate(fEnable)))
  780. {
  781. hr = S_OK;
  782. }
  783. }
  784. if (m_pSynthSink8)
  785. {
  786. hr = m_pSynthSink8->Activate(fEnable);
  787. }
  788. }
  789. else
  790. {
  791. Trace(2, "Warning: Synth::Activate- synth already inactive\n");
  792. hr = S_FALSE;
  793. }
  794. }
  795. // ::LeaveCriticalSection(&m_CriticalSection);
  796. return hr;
  797. }
  798. STDMETHODIMP CUserModeSynth::Render(
  799. short *pBuffer, // Pointer to buffer to write into.
  800. DWORD dwLength, // Length of buffer, in samples. This is not the
  801. // memory size of the buffer. The memory size may vary,
  802. // dependant on the buffer format, which the synth
  803. // sets when in response to an <om IDirectMusicSynth::Activate>
  804. // command.
  805. LONGLONG llPosition) // Position in the audio stream, also in samples.
  806. // This should always increment by <p dwLength> after
  807. // each call.
  808. {
  809. V_INAME(IDirectMusicSynth::Render);
  810. V_BUFPTR_WRITE(pBuffer, dwLength << (m_dwBufferFlags&BUFFERFLAG_INTERLEAVED)?1:0 );
  811. if (!m_pSynthSink)
  812. {
  813. Trace(1, "Error: Synth is not configured, can not render.\n");
  814. return DMUS_E_SYNTHNOTCONFIGURED;
  815. }
  816. if (!m_fActive)
  817. {
  818. Trace(1, "Error: Synth is not inactive, can not render.\n");
  819. return DMUS_E_SYNTHINACTIVE;
  820. }
  821. ::EnterCriticalSection(&m_CriticalSection);
  822. if (m_pSynth)
  823. {
  824. DWORD dwID[2];
  825. DWORD dwFuncID[2];
  826. long lPitchBend[2];
  827. // Setup busid for a Backward compatible DX7 interleaved buffer
  828. dwID[0] = DSBUSID_LEFT;
  829. dwID[1] = DSBUSID_RIGHT;
  830. dwFuncID[0] = DSBUSID_LEFT;
  831. dwFuncID[1] = DSBUSID_RIGHT;
  832. lPitchBend[0] = lPitchBend[1] = 0;
  833. DWORD dwChannels = 1;
  834. if (m_pSynth->m_dwStereo)
  835. {
  836. dwChannels = 2;
  837. }
  838. m_pSynth->Mix(&pBuffer, dwID, dwFuncID, lPitchBend, dwChannels, m_dwBufferFlags, dwLength, llPosition);
  839. }
  840. ::LeaveCriticalSection(&m_CriticalSection);
  841. return S_OK;
  842. }
  843. STDMETHODIMP CUserModeSynth::SetChannelPriority(
  844. DWORD dwChannelGroup,
  845. DWORD dwChannel,
  846. DWORD dwPriority)
  847. {
  848. if (m_pSynth)
  849. {
  850. return m_pSynth->SetChannelPriority(dwChannelGroup, dwChannel, dwPriority);
  851. }
  852. Trace(1, "Error: Synth not initialized.\n");
  853. return E_FAIL;
  854. }
  855. STDMETHODIMP CUserModeSynth::GetChannelPriority(
  856. DWORD dwChannelGroup,
  857. DWORD dwChannel,
  858. LPDWORD pdwPriority)
  859. {
  860. if (m_pSynth)
  861. {
  862. return m_pSynth->GetChannelPriority(dwChannelGroup, dwChannel, pdwPriority);
  863. }
  864. Trace(1, "Error: Synth not initialized.\n");
  865. return E_FAIL;
  866. }
  867. // IDirectSoundSource version of GetFormat()
  868. STDMETHODIMP CUserModeSynth::GetFormat(
  869. LPWAVEFORMATEX pWaveFormatEx,
  870. DWORD dwSizeAllocated,
  871. LPDWORD pdwSizeWritten)
  872. {
  873. V_INAME(IDirectMusicSynth::GetFormat);
  874. if (!m_pSynth)
  875. {
  876. Trace(1, "Error: Synth is not configured, can not get format.\n");
  877. return DMUS_E_SYNTHNOTCONFIGURED;
  878. }
  879. if (!pWaveFormatEx && !pdwSizeWritten)
  880. {
  881. Trace(1, "Error: GetFormat failed, must request either the format or the required size");
  882. return E_INVALIDARG;
  883. }
  884. if (pdwSizeWritten)
  885. {
  886. V_PTR_WRITE(pdwSizeWritten, DWORD);
  887. *pdwSizeWritten = sizeof(WAVEFORMATEX);
  888. }
  889. if (pWaveFormatEx)
  890. {
  891. V_BUFPTR_WRITE_OPT(pWaveFormatEx, dwSizeAllocated);
  892. WAVEFORMATEX wfx;
  893. memset(&wfx, 0, sizeof(wfx));
  894. wfx.wFormatTag = WAVE_FORMAT_PCM;
  895. wfx.nChannels = (WORD)m_dwChannels;
  896. wfx.nSamplesPerSec = (WORD)m_dwSampleRate;
  897. wfx.wBitsPerSample = 16;
  898. wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
  899. wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  900. wfx.cbSize = 0; // no extra data
  901. memcpy(pWaveFormatEx, &wfx, min(sizeof wfx, dwSizeAllocated));
  902. }
  903. return S_OK;
  904. }
  905. // IDirectMusicSynth8 version of GetFormat()
  906. STDMETHODIMP CUserModeSynth::GetFormat(
  907. LPWAVEFORMATEX pWaveFormatEx,
  908. LPDWORD pdwWaveFormatExSize)
  909. {
  910. V_INAME(IDirectMusicSynth::GetFormat);
  911. V_PTR_WRITE(pdwWaveFormatExSize, DWORD);
  912. V_BUFPTR_WRITE_OPT(pWaveFormatEx, *pdwWaveFormatExSize);
  913. return GetFormat(pWaveFormatEx, *pdwWaveFormatExSize, pdwWaveFormatExSize);
  914. }
  915. STDMETHODIMP CUserModeSynth::GetAppend(
  916. DWORD* pdwAppend)
  917. {
  918. V_INAME(IDirectMusicSynth::GetAppend);
  919. V_PTR_WRITE(pdwAppend, DWORD);
  920. *pdwAppend = 2; // The synth needs 1 extra sample for loop interpolation.
  921. // We're adding one more to be paranoid.
  922. return S_OK;
  923. }
  924. STDMETHODIMP CUserModeSynth::GetRunningStats(
  925. LPDMUS_SYNTHSTATS pStats) // <t DMUS_SYNTHSTATS> structure to fill in.
  926. {
  927. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  928. V_INAME(IDirectMusicSynth::GetRunningStats);
  929. V_STRUCTPTR_WRITE(pStats, DMUS_SYNTHSTATS);
  930. if ( pStats->dwSize == sizeof(DMUS_SYNTHSTATS8) )
  931. {
  932. V_STRUCTPTR_WRITE(pStats, DMUS_SYNTHSTATS8);
  933. }
  934. if (!m_pSynthSink && !m_pSynthSink8)
  935. {
  936. Trace(1, "Error: Synth::GetRunningStats failed because synth is inactove.\n");
  937. return hr;
  938. }
  939. if (m_fActive)
  940. {
  941. ::EnterCriticalSection(&m_CriticalSection);
  942. if (m_pSynth)
  943. {
  944. PerfStats Stats;
  945. m_pSynth->GetPerformanceStats(&Stats);
  946. long lCPU = Stats.dwCPU;
  947. if (Stats.dwVoices)
  948. {
  949. lCPU /= Stats.dwVoices;
  950. }
  951. else
  952. {
  953. lCPU = 0;
  954. }
  955. pStats->dwVoices = Stats.dwVoices;
  956. pStats->dwCPUPerVoice = lCPU * 10;
  957. pStats->dwTotalCPU = Stats.dwCPU * 10;
  958. pStats->dwLostNotes = Stats.dwNotesLost;
  959. long ldB = 6;
  960. double fLevel = Stats.dwMaxAmplitude;
  961. if (Stats.dwMaxAmplitude < 1)
  962. {
  963. fLevel = -96.0;
  964. }
  965. else
  966. {
  967. fLevel /= 32768.0;
  968. fLevel = log10(fLevel);
  969. fLevel *= 20.0;
  970. }
  971. pStats->lPeakVolume = (long) fLevel;
  972. pStats->dwValidStats = DMUS_SYNTHSTATS_VOICES | DMUS_SYNTHSTATS_TOTAL_CPU |
  973. DMUS_SYNTHSTATS_CPU_PER_VOICE | DMUS_SYNTHSTATS_LOST_NOTES | DMUS_SYNTHSTATS_PEAK_VOLUME;
  974. if ( pStats->dwSize == sizeof(DMUS_SYNTHSTATS8) )
  975. {
  976. ((DMUS_SYNTHSTATS8*)pStats)->dwSynthMemUse = m_pSynth->m_Instruments.m_dwSynthMemUse;
  977. }
  978. hr = S_OK;
  979. }
  980. ::LeaveCriticalSection(&m_CriticalSection);
  981. }
  982. else
  983. {
  984. DWORD dwSize = pStats->dwSize;
  985. memset(pStats, 0, dwSize);
  986. pStats->dwSize = dwSize;
  987. hr = S_OK;
  988. }
  989. return hr;
  990. }
  991. static DWORD dwPropFalse = FALSE;
  992. static DWORD dwPropTrue = TRUE;
  993. static DWORD dwSystemMemory = DMUS_PC_SYSTEMMEMORY;
  994. GENERICPROPERTY CUserModeSynth::m_aProperty[] =
  995. {
  996. {
  997. &GUID_DMUS_PROP_GM_Hardware, // Set
  998. 0, // Item
  999. KSPROPERTY_SUPPORT_GET, // KS support flags
  1000. GENPROP_F_STATIC, // GENPROP flags
  1001. &dwPropFalse, sizeof(dwPropFalse), // static data and size
  1002. NULL // Handler
  1003. },
  1004. { &GUID_DMUS_PROP_GS_Hardware,
  1005. 0,
  1006. KSPROPERTY_SUPPORT_GET,
  1007. GENPROP_F_STATIC,
  1008. &dwPropFalse, sizeof(dwPropFalse),
  1009. NULL
  1010. },
  1011. { &GUID_DMUS_PROP_XG_Hardware,
  1012. 0,
  1013. KSPROPERTY_SUPPORT_GET,
  1014. GENPROP_F_STATIC,
  1015. &dwPropFalse, sizeof(dwPropFalse),
  1016. NULL
  1017. },
  1018. { &GUID_DMUS_PROP_XG_Capable,
  1019. 0,
  1020. KSPROPERTY_SUPPORT_GET,
  1021. GENPROP_F_STATIC,
  1022. &dwPropTrue, sizeof(dwPropTrue),
  1023. NULL
  1024. },
  1025. { &GUID_DMUS_PROP_GS_Capable,
  1026. 0,
  1027. KSPROPERTY_SUPPORT_GET,
  1028. GENPROP_F_STATIC,
  1029. &dwPropTrue, sizeof(dwPropTrue),
  1030. NULL
  1031. },
  1032. { &GUID_DMUS_PROP_INSTRUMENT2,
  1033. 0,
  1034. KSPROPERTY_SUPPORT_GET,
  1035. GENPROP_F_STATIC,
  1036. &dwPropTrue, sizeof(dwPropTrue),
  1037. NULL
  1038. },
  1039. {
  1040. &GUID_DMUS_PROP_DLS1,
  1041. 0,
  1042. KSPROPERTY_SUPPORT_GET,
  1043. GENPROP_F_STATIC,
  1044. &dwPropTrue, sizeof(dwPropTrue),
  1045. NULL
  1046. },
  1047. {
  1048. &GUID_DMUS_PROP_DLS2,
  1049. 0,
  1050. KSPROPERTY_SUPPORT_GET,
  1051. GENPROP_F_STATIC,
  1052. &dwPropTrue, sizeof(dwPropTrue),
  1053. NULL
  1054. },
  1055. {
  1056. &GUID_DMUS_PROP_SampleMemorySize,
  1057. 0,
  1058. KSPROPERTY_SUPPORT_GET,
  1059. GENPROP_F_STATIC,
  1060. &dwSystemMemory, sizeof(dwSystemMemory),
  1061. NULL
  1062. },
  1063. {
  1064. &KSPROPSETID_Synth,
  1065. KSPROPERTY_SYNTH_VOLUME,
  1066. KSPROPERTY_SUPPORT_SET,
  1067. GENPROP_F_FNHANDLER,
  1068. NULL, 0,
  1069. CUserModeSynth::HandleSetVolume
  1070. },
  1071. {
  1072. &KSPROPSETID_Synth,
  1073. KSPROPERTY_SYNTH_VOLUMEBOOST,
  1074. KSPROPERTY_SUPPORT_SET,
  1075. GENPROP_F_FNHANDLER,
  1076. NULL, 0,
  1077. CUserModeSynth::HandleSetBoost
  1078. },
  1079. {
  1080. &GUID_DMUS_PROP_WavesReverb,
  1081. 0,
  1082. KSPROPERTY_SUPPORT_SET | KSPROPERTY_SUPPORT_GET,
  1083. GENPROP_F_FNHANDLER,
  1084. NULL, 0,
  1085. CUserModeSynth::HandleReverb
  1086. },
  1087. {
  1088. &GUID_DMUS_PROP_Effects,
  1089. 0,
  1090. KSPROPERTY_SUPPORT_SET | KSPROPERTY_SUPPORT_GET,
  1091. GENPROP_F_FNHANDLER,
  1092. NULL, 0,
  1093. CUserModeSynth::HandleEffects
  1094. },
  1095. {
  1096. &GUID_DMUS_PROP_SamplePlaybackRate,
  1097. 0,
  1098. KSPROPERTY_SUPPORT_GET,
  1099. GENPROP_F_FNHANDLER,
  1100. NULL, 0,
  1101. CUserModeSynth::HandleGetSampleRate
  1102. }
  1103. };
  1104. const int CUserModeSynth::m_nProperty = sizeof(m_aProperty) / sizeof(m_aProperty[0]);
  1105. HRESULT CUserModeSynth::HandleGetSampleRate(
  1106. ULONG ulId,
  1107. BOOL fSet,
  1108. LPVOID pbBuffer,
  1109. PULONG pcbBuffer)
  1110. {
  1111. if (*pcbBuffer != sizeof(LONG))
  1112. {
  1113. return E_INVALIDARG;
  1114. }
  1115. if (!fSet)
  1116. {
  1117. *(long*)pbBuffer = m_dwSampleRate;
  1118. }
  1119. return S_OK;
  1120. }
  1121. HRESULT CUserModeSynth::HandleSetVolume(
  1122. ULONG ulId,
  1123. BOOL fSet,
  1124. LPVOID pbBuffer,
  1125. PULONG pcbBuffer)
  1126. {
  1127. if (*pcbBuffer != sizeof(LONG))
  1128. {
  1129. return E_INVALIDARG;
  1130. }
  1131. m_lVolume = *(LONG*)pbBuffer;
  1132. m_lGainAdjust = m_lVolume + m_lBoost;
  1133. if (m_pSynth)
  1134. {
  1135. m_pSynth->SetGainAdjust(m_lGainAdjust);
  1136. }
  1137. return S_OK;
  1138. }
  1139. HRESULT CUserModeSynth::HandleSetBoost(
  1140. ULONG ulId,
  1141. BOOL fSet,
  1142. LPVOID pbBuffer,
  1143. PULONG pcbBuffer)
  1144. {
  1145. if (*pcbBuffer != sizeof(LONG))
  1146. {
  1147. return E_INVALIDARG;
  1148. }
  1149. m_lBoost = *(LONG*)pbBuffer;
  1150. m_lGainAdjust = m_lVolume + m_lBoost;
  1151. if (m_pSynth)
  1152. {
  1153. m_pSynth->SetGainAdjust(m_lGainAdjust);
  1154. }
  1155. return S_OK;
  1156. }
  1157. HRESULT CUserModeSynth::HandleReverb(ULONG ulId, BOOL fSet, LPVOID pbBuffer, PULONG pcbBuffer)
  1158. {
  1159. DMUS_WAVES_REVERB_PARAMS *pParams;
  1160. if (*pcbBuffer != sizeof(DMUS_WAVES_REVERB_PARAMS))
  1161. {
  1162. return E_INVALIDARG;
  1163. }
  1164. pParams = (DMUS_WAVES_REVERB_PARAMS *) pbBuffer;
  1165. if (m_pSynth)
  1166. {
  1167. if (fSet)
  1168. {
  1169. m_pSynth->SetReverb(pParams);
  1170. }
  1171. else
  1172. {
  1173. m_pSynth->GetReverb(pParams);
  1174. }
  1175. }
  1176. return S_OK;
  1177. }
  1178. HRESULT CUserModeSynth::HandleEffects(
  1179. ULONG ulId,
  1180. BOOL fSet,
  1181. LPVOID pbBuffer,
  1182. PULONG pcbBuffer)
  1183. {
  1184. if (*pcbBuffer != sizeof(LONG))
  1185. {
  1186. return E_INVALIDARG;
  1187. }
  1188. if (fSet)
  1189. {
  1190. long lEffects = *(long*)pbBuffer;
  1191. if (m_pSynth)
  1192. {
  1193. m_pSynth->SetReverbActive(lEffects & DMUS_EFFECT_REVERB);
  1194. }
  1195. }
  1196. else
  1197. {
  1198. if (m_pSynth && m_pSynth->IsReverbActive())
  1199. {
  1200. *(long*)pbBuffer = DMUS_EFFECT_REVERB;
  1201. }
  1202. else
  1203. {
  1204. *(long*)pbBuffer = 0;
  1205. }
  1206. }
  1207. return S_OK;
  1208. }
  1209. //
  1210. // CDirectMusicEmulatePort::FindPropertyItem
  1211. //
  1212. // Given a GUID and an item ID, find the associated property item in the synth's
  1213. // table of SYNPROPERTY's.
  1214. //
  1215. // Returns a pointer to the entry or NULL if the item was not found.
  1216. //
  1217. GENERICPROPERTY *CUserModeSynth::FindPropertyItem(REFGUID rguid, ULONG ulId)
  1218. {
  1219. GENERICPROPERTY *pPropertyItem = &m_aProperty[0];
  1220. GENERICPROPERTY *pEndOfItems = pPropertyItem + m_nProperty;
  1221. // Special Case -- We don't support Waves Reverb on a SinthSink8
  1222. if ((rguid == GUID_DMUS_PROP_WavesReverb) && (this->m_pSynthSink8 != NULL))
  1223. return NULL;
  1224. for (; pPropertyItem != pEndOfItems; pPropertyItem++)
  1225. {
  1226. if (*pPropertyItem->pguidPropertySet == rguid &&
  1227. pPropertyItem->ulId == ulId)
  1228. {
  1229. return pPropertyItem;
  1230. }
  1231. }
  1232. return NULL;
  1233. }
  1234. #define KS_VALID_FLAGS (KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET| KSPROPERTY_TYPE_BASICSUPPORT)
  1235. STDMETHODIMP CUserModeSynth::KsProperty(
  1236. PKSPROPERTY pPropertyIn, ULONG ulPropertyLength,
  1237. LPVOID pvPropertyData, ULONG ulDataLength,
  1238. PULONG pulBytesReturned)
  1239. {
  1240. V_INAME(DirectMusicSynthPort::IKsContol::KsProperty);
  1241. V_BUFPTR_WRITE(pPropertyIn, ulPropertyLength);
  1242. DWORD dwFlags = pPropertyIn->Flags & KS_VALID_FLAGS;
  1243. switch (dwFlags)
  1244. {
  1245. case KSPROPERTY_TYPE_GET:
  1246. V_BUFPTR_WRITE_OPT(pvPropertyData, ulDataLength);
  1247. break;
  1248. case KSPROPERTY_TYPE_SET:
  1249. V_BUFPTR_READ(pvPropertyData, ulDataLength);
  1250. break;
  1251. case KSPROPERTY_TYPE_BASICSUPPORT:
  1252. V_BUFPTR_WRITE(pvPropertyData, ulDataLength);
  1253. break;
  1254. }
  1255. V_PTR_WRITE(pulBytesReturned, ULONG);
  1256. GENERICPROPERTY *pProperty = FindPropertyItem(pPropertyIn->Set, pPropertyIn->Id);
  1257. if (pProperty == NULL)
  1258. {
  1259. Trace(2, "Warning: KsProperty call requested unknown property.\n");
  1260. return DMUS_E_UNKNOWN_PROPERTY;
  1261. }
  1262. switch (dwFlags)
  1263. {
  1264. case KSPROPERTY_TYPE_GET:
  1265. if (!(pProperty->ulSupported & KSPROPERTY_SUPPORT_GET))
  1266. {
  1267. Trace(1, "Error: SynthSink does not support Get for the requested property.\n");
  1268. return DMUS_E_GET_UNSUPPORTED;
  1269. }
  1270. if (pProperty->ulFlags & GENPROP_F_FNHANDLER)
  1271. {
  1272. GENPROPHANDLER pfn = pProperty->pfnHandler;
  1273. *pulBytesReturned = ulDataLength;
  1274. return (this->*pfn)(pPropertyIn->Id, FALSE, pvPropertyData, pulBytesReturned);
  1275. }
  1276. if (ulDataLength > pProperty->cbPropertyData)
  1277. {
  1278. ulDataLength = pProperty->cbPropertyData;
  1279. }
  1280. if (pvPropertyData != NULL)
  1281. {
  1282. CopyMemory(pvPropertyData, pProperty->pPropertyData, ulDataLength);
  1283. }
  1284. *pulBytesReturned = ulDataLength;
  1285. return S_OK;
  1286. case KSPROPERTY_TYPE_SET:
  1287. if (!(pProperty->ulSupported & KSPROPERTY_SUPPORT_SET))
  1288. {
  1289. Trace(1, "Error: SynthSink does not support Set for the requested property.\n");
  1290. return DMUS_E_SET_UNSUPPORTED;
  1291. }
  1292. if (pProperty->ulFlags & GENPROP_F_FNHANDLER)
  1293. {
  1294. GENPROPHANDLER pfn = pProperty->pfnHandler;
  1295. return (this->*pfn)(pPropertyIn->Id, TRUE, pvPropertyData, &ulDataLength);
  1296. }
  1297. if (ulDataLength > pProperty->cbPropertyData)
  1298. {
  1299. ulDataLength = pProperty->cbPropertyData;
  1300. }
  1301. CopyMemory(pProperty->pPropertyData, pvPropertyData, ulDataLength);
  1302. return S_OK;
  1303. case KSPROPERTY_TYPE_BASICSUPPORT:
  1304. if (pProperty == NULL)
  1305. {
  1306. Trace(1, "Error: Synth does not provide support for requested property type.\n");
  1307. return DMUS_E_UNKNOWN_PROPERTY;
  1308. }
  1309. // XXX Find out what convention is for this!!
  1310. //
  1311. if (ulDataLength < sizeof(DWORD))
  1312. {
  1313. Trace(1, "Error: Data size for property is too small.\n");
  1314. return E_INVALIDARG;
  1315. }
  1316. *(LPDWORD)pvPropertyData = pProperty->ulSupported;
  1317. *pulBytesReturned = sizeof(DWORD);
  1318. return S_OK;
  1319. }
  1320. Trace(1, "Error: KSProperty Flags must contain one of: %s\n"
  1321. "\tKSPROPERTY_TYPE_SET, KSPROPERTY_TYPE_GET, or KSPROPERTY_TYPE_BASICSUPPORT\n");
  1322. return E_INVALIDARG;
  1323. }
  1324. STDMETHODIMP CUserModeSynth::KsMethod(
  1325. PKSMETHOD pMethod, ULONG ulMethodLength,
  1326. LPVOID pvMethodData, ULONG ulDataLength,
  1327. PULONG pulBytesReturned)
  1328. {
  1329. V_INAME(DirectMusicSynth::IKsContol::KsMethod);
  1330. V_BUFPTR_WRITE(pMethod, ulMethodLength);
  1331. V_BUFPTR_WRITE_OPT(pvMethodData, ulDataLength);
  1332. V_PTR_WRITE(pulBytesReturned, ULONG);
  1333. return DMUS_E_UNKNOWN_PROPERTY;
  1334. }
  1335. STDMETHODIMP CUserModeSynth::KsEvent(
  1336. PKSEVENT pEvent, ULONG ulEventLength,
  1337. LPVOID pvEventData, ULONG ulDataLength,
  1338. PULONG pulBytesReturned)
  1339. {
  1340. V_INAME(DirectMusicSynthPort::IKsContol::KsEvent);
  1341. V_BUFPTR_WRITE(pEvent, ulEventLength);
  1342. V_BUFPTR_WRITE_OPT(pvEventData, ulDataLength);
  1343. V_PTR_WRITE(pulBytesReturned, ULONG);
  1344. return DMUS_E_UNKNOWN_PROPERTY;
  1345. }
  1346. /////////////////////////////////////////////////////////////////////
  1347. // Implementation of IDirectMusicSynth8
  1348. STDMETHODIMP CUserModeSynth::PlayVoice(REFERENCE_TIME rt, DWORD dwVoiceId, DWORD dwChannelGroup, DWORD dwChannel, DWORD dwDLId, PREL prPitch, VREL vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd )
  1349. {
  1350. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  1351. ::EnterCriticalSection(&m_CriticalSection);
  1352. if (m_pSynth)
  1353. {
  1354. hr = m_pSynth->PlayVoice(m_pSynthSink8,
  1355. rt,
  1356. dwVoiceId,
  1357. dwChannelGroup,
  1358. dwChannel,
  1359. dwDLId,
  1360. vrVolume,
  1361. prPitch,
  1362. stVoiceStart,
  1363. stLoopStart,
  1364. stLoopEnd);
  1365. }
  1366. else
  1367. {
  1368. Trace(1, "Error: Failed wave playback, synth is not properly configured.\n");
  1369. }
  1370. ::LeaveCriticalSection(&m_CriticalSection);
  1371. return hr;
  1372. }
  1373. STDMETHODIMP CUserModeSynth::StopVoice(REFERENCE_TIME rt, DWORD dwVoiceId )
  1374. {
  1375. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  1376. ::EnterCriticalSection(&m_CriticalSection);
  1377. if (m_pSynth)
  1378. {
  1379. hr = m_pSynth->StopVoice(m_pSynthSink8,
  1380. rt,
  1381. dwVoiceId);
  1382. }
  1383. else
  1384. {
  1385. Trace(1, "Error: Failed stop of wave playback, synth is not properly configured.\n");
  1386. }
  1387. ::LeaveCriticalSection(&m_CriticalSection);
  1388. return hr;
  1389. }
  1390. STDMETHODIMP CUserModeSynth::GetVoiceState(DWORD dwVoice[], DWORD cbVoice, DMUS_VOICE_STATE VoiceState[] )
  1391. {
  1392. V_INAME(IDirectMusicSynth::GetVoiceState);
  1393. V_PTR_READ(dwVoice, sizeof(DWORD)*cbVoice);
  1394. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  1395. ::EnterCriticalSection(&m_CriticalSection);
  1396. if (m_pSynth)
  1397. {
  1398. hr = m_pSynth->GetVoiceState(dwVoice,
  1399. cbVoice,
  1400. VoiceState);
  1401. }
  1402. ::LeaveCriticalSection(&m_CriticalSection);
  1403. return hr;
  1404. }
  1405. STDMETHODIMP CUserModeSynth::Refresh(DWORD dwDownloadID, DWORD dwFlags )
  1406. {
  1407. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  1408. ::EnterCriticalSection(&m_CriticalSection);
  1409. if (m_pSynth)
  1410. {
  1411. hr = m_pSynth->Refresh(dwDownloadID,
  1412. dwFlags);
  1413. }
  1414. ::LeaveCriticalSection(&m_CriticalSection);
  1415. return hr;
  1416. }
  1417. STDMETHODIMP CUserModeSynth::AssignChannelToBuses(DWORD dwChannelGroup, DWORD dwChannel, LPDWORD pdwBuses, DWORD cBuses )
  1418. {
  1419. HRESULT hr = DMUS_E_SYNTHNOTCONFIGURED;
  1420. ::EnterCriticalSection(&m_CriticalSection);
  1421. if (m_pSynth)
  1422. {
  1423. hr = m_pSynth->AssignChannelToBuses(dwChannelGroup,
  1424. dwChannel,
  1425. pdwBuses,
  1426. cBuses);
  1427. }
  1428. else
  1429. {
  1430. Trace(1, "Error: Failed synth channel assignment, synth is not properly configured.\n");
  1431. }
  1432. ::LeaveCriticalSection(&m_CriticalSection);
  1433. return hr;
  1434. }
  1435. /////////////////////////////////////////////////////////////////////
  1436. // Implementation of IDirectSoundSource
  1437. STDMETHODIMP CUserModeSynth::SetSink(IDirectSoundConnect* pSinkConnect)
  1438. {
  1439. V_INAME(IDirectSoundSink::SetSink);
  1440. V_INTERFACE_OPT(pSinkConnect);
  1441. HRESULT hr = S_OK;
  1442. LPVOID ptr = NULL;
  1443. V_BUFPTR_WRITE_OPT(ptr, 0);
  1444. ::EnterCriticalSection(&m_CriticalSection);
  1445. //>>>>>>>> RELEASE THE DSLINK IF PRESENT !!!!
  1446. // FIXME: The calls into the SynthSink8 may require the DSound DLL Mutex. If the Sink
  1447. // is making a a call to READ then we end up in a deadlock. We need to be sure that the
  1448. // Synth isn't playing when we do this.
  1449. if (m_pSynthSink8)
  1450. {
  1451. // FIXME: whoever called us->SetSink() should previously have called
  1452. // pOldSink->RemoveSource(us) - it shouldn't be our responsibility to
  1453. // do this call (??):
  1454. // m_pSynthSink8->RemoveSource(this);
  1455. m_pSynthSink8->Release();
  1456. m_pSynthSink8 = NULL;
  1457. }
  1458. if (pSinkConnect)
  1459. {
  1460. // Obtain the IDirectSoundSynthSink interface on the sink
  1461. hr = pSinkConnect->QueryInterface(IID_IDirectSoundSynthSink, (void**)&m_pSynthSink8);
  1462. if (SUCCEEDED(hr))
  1463. {
  1464. //
  1465. // Get the sink's format and validate it
  1466. //
  1467. WAVEFORMATEX wfx;
  1468. DWORD dwSize = sizeof wfx;
  1469. hr = m_pSynthSink8->GetFormat(&wfx, dwSize, NULL);
  1470. if (SUCCEEDED(hr) && wfx.wBitsPerSample != 16 )
  1471. {
  1472. Trace(1, "Error; Synth can not write to any format other than 16 bit PCM.\n");
  1473. hr = DMUS_E_WAVEFORMATNOTSUPPORTED;
  1474. }
  1475. if (SUCCEEDED(hr))
  1476. {
  1477. // Flag the buffer format to be non-interleaved
  1478. m_dwChannels = 1; // This synth with a sink is concidered a mono source.
  1479. m_dwBufferFlags = BUFFERFLAG_MULTIBUFFER;
  1480. if (m_pSynth)
  1481. {
  1482. m_pSynth->SetStereoMode(m_dwBufferFlags);
  1483. // reset sample rate if it has changed
  1484. if (wfx.nSamplesPerSec != (WORD)m_dwSampleRate)
  1485. {
  1486. m_pSynth->SetSampleRate(wfx.nSamplesPerSec);
  1487. }
  1488. // disable DX7 Reverb
  1489. m_pSynth->SetReverbActive(FALSE);
  1490. }
  1491. }
  1492. }
  1493. }
  1494. ::LeaveCriticalSection(&m_CriticalSection);
  1495. return hr;
  1496. }
  1497. STDMETHODIMP CUserModeSynth::Seek(ULONGLONG sp)
  1498. {
  1499. m_ullPosition = sp/2; // Convert from bytes to samples
  1500. return S_OK;
  1501. }
  1502. STDMETHODIMP CUserModeSynth::Read(LPVOID *ppvBuffer, LPDWORD pdwIDs, LPDWORD pdwFuncIDs, LPLONG plPitchBends, DWORD dwBufferCount, PULONGLONG pullLength )
  1503. {
  1504. V_INAME(IDirectMusicSynth::Read);
  1505. V_PTR_READ(ppvBuffer, sizeof(LPVOID)*dwBufferCount);
  1506. V_PTR_READ(pdwIDs, sizeof(LPDWORD)*dwBufferCount);
  1507. for ( DWORD i = 0; i < dwBufferCount; i++ )
  1508. {
  1509. V_BUFPTR_WRITE(ppvBuffer[i], (DWORD)*pullLength);
  1510. if ( ppvBuffer[i] == NULL )
  1511. {
  1512. Trace(1, "Error: Read called with NULL buffer.\n");
  1513. return E_INVALIDARG;
  1514. }
  1515. }
  1516. if ( *pullLength > 0x00000000FFFFFFFF ) // can't read more than a DWORD's worth of data
  1517. {
  1518. Trace(1, "Error: Read called with invalid buffer length.\n");
  1519. return E_INVALIDARG;
  1520. }
  1521. if ( dwBufferCount == 0 ) // don't read no buffers
  1522. {
  1523. Trace(4, "Warning: Read called with 0 buffers.\n");
  1524. return E_INVALIDARG;
  1525. }
  1526. if (!m_pSynthSink8)
  1527. {
  1528. Trace(1, "Error: Synth is not configured, can not play.\n");
  1529. return DMUS_E_SYNTHNOTCONFIGURED;
  1530. }
  1531. if (!m_fActive)
  1532. {
  1533. Trace(3, "Warning: Synth is not active, can not play.\n");
  1534. return DMUS_E_SYNTHINACTIVE;
  1535. }
  1536. ::EnterCriticalSection(&m_CriticalSection);
  1537. if (m_pSynth)
  1538. {
  1539. // Mix
  1540. DWORD dwLength = (DWORD)(*pullLength)/2; // Convert from bytes to number of samples. Synth assumes 16 bit
  1541. m_pSynth->Mix((short**)ppvBuffer, pdwIDs, pdwFuncIDs, plPitchBends, dwBufferCount, m_dwBufferFlags, dwLength, m_ullPosition);
  1542. // Increment current sample position in the audio stream
  1543. m_ullPosition += dwLength;
  1544. }
  1545. ::LeaveCriticalSection(&m_CriticalSection);
  1546. return S_OK;
  1547. }
  1548. STDMETHODIMP CUserModeSynth::GetSize(PULONGLONG pcb)
  1549. {
  1550. return E_NOTIMPL;
  1551. }