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.

1561 lines
40 KiB

  1. //
  2. // Copyright (c) 1996-2001 Microsoft Corporation
  3. // CSynth.cpp
  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. #ifdef DMSYNTH_MINIPORT
  24. #include "common.h"
  25. #else
  26. #include "simple.h"
  27. #include <mmsystem.h>
  28. #include "dsoundp.h"
  29. #include <dmusicc.h>
  30. #include <dmusics.h>
  31. #include "synth.h"
  32. #include "CSynth.h"
  33. #ifdef REVERB_ENABLED
  34. #include "sverb.h"
  35. #endif
  36. #include "debug.h"
  37. #endif
  38. #include "dsoundp.h" // For IDirectSoundSynthSink
  39. #ifdef _X86_
  40. #define MMX_ENABLED 1
  41. #endif
  42. #ifdef MMX_ENABLED
  43. BOOL MultiMediaInstructionsSupported();
  44. #endif
  45. CSynth::CSynth()
  46. {
  47. DWORD nIndex;
  48. CVoice *pVoice;
  49. m_fCSInitialized = FALSE;
  50. ::InitializeCriticalSection(&m_CriticalSection);
  51. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  52. // ever pops in stress, we can add an exception handler and retry loop.
  53. m_fCSInitialized = TRUE;
  54. for (nIndex = 0;nIndex < MAX_NUM_VOICES;nIndex++)
  55. {
  56. pVoice = new CVoice;
  57. if (pVoice != NULL)
  58. {
  59. m_VoicesFree.AddHead(pVoice);
  60. }
  61. }
  62. for (nIndex = 0;nIndex < NUM_EXTRA_VOICES;nIndex++)
  63. {
  64. pVoice = new CVoice;
  65. if (pVoice != NULL)
  66. {
  67. m_VoicesExtra.AddHead(pVoice);
  68. }
  69. }
  70. m_fReverbActive = FALSE;
  71. m_pCoefs = NULL;
  72. m_pStates = NULL;
  73. m_ReverbParams.fInGain = 0.0;
  74. m_ReverbParams.fReverbMix = -10.0;
  75. m_ReverbParams.fReverbTime = 1000.0;
  76. m_ReverbParams.fHighFreqRTRatio = (float) 0.001;
  77. m_ppControl = NULL;
  78. m_dwControlCount = 0;
  79. m_nMaxVoices = MAX_NUM_VOICES;
  80. m_nExtraVoices = NUM_EXTRA_VOICES;
  81. m_stLastStats = 0;
  82. m_fAllowPanWhilePlayingNote = TRUE;
  83. m_fAllowVolumeChangeWhilePlayingNote = TRUE;
  84. ResetPerformanceStats();
  85. m_stLastTime = 0;
  86. m_dwSampleRate = SAMPLE_RATE_22;
  87. SetSampleRate(SAMPLE_RATE_22);
  88. SetStereoMode(BUFFERFLAG_INTERLEAVED);
  89. SetGainAdjust(600);
  90. m_sfMMXEnabled = FALSE;
  91. #ifdef MMX_ENABLED
  92. m_sfMMXEnabled = MultiMediaInstructionsSupported();
  93. #endif // MMX_ENABLED
  94. }
  95. CSynth::~CSynth()
  96. {
  97. CVoice *pVoice;
  98. if (m_fCSInitialized)
  99. {
  100. // If CS never initialized, nothing else will have been set up
  101. //
  102. Close();
  103. while (pVoice = m_VoicesInUse.RemoveHead())
  104. {
  105. delete pVoice;
  106. }
  107. while (pVoice = m_VoicesFree.RemoveHead())
  108. {
  109. delete pVoice;
  110. }
  111. while (pVoice = m_VoicesExtra.RemoveHead())
  112. {
  113. delete pVoice;
  114. }
  115. DeleteCriticalSection(&m_CriticalSection);
  116. }
  117. }
  118. short CSynth::ChangeVoiceCount(CVoiceList *pList,short nOld,short nCount)
  119. {
  120. if (nCount > nOld)
  121. {
  122. short nNew = nCount - nOld;
  123. for (;nNew != 0; nNew--)
  124. {
  125. CVoice *pVoice = new CVoice;
  126. if (pVoice != NULL)
  127. {
  128. pList->AddHead(pVoice);
  129. }
  130. }
  131. }
  132. else
  133. {
  134. short nNew = nOld - nCount;
  135. for (;nNew > 0; nNew--)
  136. {
  137. CVoice *pVoice = pList->RemoveHead();
  138. if (pVoice != NULL)
  139. {
  140. delete pVoice;
  141. }
  142. else
  143. {
  144. nCount += nNew;
  145. break;
  146. }
  147. }
  148. }
  149. return nCount;
  150. }
  151. HRESULT CSynth::SetMaxVoices(short nVoices,short nTempVoices)
  152. {
  153. if (nVoices < 1)
  154. {
  155. nVoices = 1;
  156. }
  157. if (nTempVoices < 1)
  158. {
  159. nTempVoices = 1;
  160. }
  161. ::EnterCriticalSection(&m_CriticalSection);
  162. m_nMaxVoices = ChangeVoiceCount(&m_VoicesFree,m_nMaxVoices,nVoices);
  163. m_nExtraVoices = ChangeVoiceCount(&m_VoicesExtra,m_nExtraVoices,nTempVoices);
  164. ::LeaveCriticalSection(&m_CriticalSection);
  165. return S_OK;
  166. }
  167. HRESULT CSynth::SetNumChannelGroups(DWORD dwCableCount)
  168. {
  169. HRESULT hr = S_OK;
  170. CControlLogic **ppControl;
  171. if ((dwCableCount < 1) || (dwCableCount > MAX_CHANNEL_GROUPS))
  172. {
  173. Trace(1,"Error: Request to set synth to %ld channel groups is invalid.\n",dwCableCount);
  174. return E_INVALIDARG;
  175. }
  176. ::EnterCriticalSection(&m_CriticalSection);
  177. if (m_dwControlCount != dwCableCount)
  178. {
  179. try
  180. {
  181. ppControl = new CControlLogic *[dwCableCount];
  182. }
  183. catch( ... )
  184. {
  185. ppControl = NULL;
  186. }
  187. if (ppControl)
  188. {
  189. DWORD dwX;
  190. for (dwX = 0; dwX < dwCableCount; dwX++)
  191. {
  192. ppControl[dwX] = NULL;
  193. }
  194. if (m_dwControlCount < dwCableCount)
  195. {
  196. for (dwX = 0; dwX < m_dwControlCount; dwX++)
  197. {
  198. ppControl[dwX] = m_ppControl[dwX];
  199. }
  200. for (;dwX < dwCableCount; dwX++)
  201. {
  202. try
  203. {
  204. ppControl[dwX] = new CControlLogic;
  205. }
  206. catch( ... )
  207. {
  208. ppControl[dwX] = NULL;
  209. }
  210. if (ppControl[dwX])
  211. {
  212. hr = ppControl[dwX]->Init(&m_Instruments, this);
  213. if (FAILED(hr))
  214. {
  215. delete ppControl[dwX];
  216. ppControl[dwX] = NULL;
  217. dwCableCount = dwX;
  218. break;
  219. }
  220. ppControl[dwX]->SetGainAdjust(m_vrGainAdjust);
  221. }
  222. else
  223. {
  224. dwCableCount = dwX;
  225. break;
  226. }
  227. }
  228. }
  229. else
  230. {
  231. AllNotesOff();
  232. for (dwX = 0; dwX < dwCableCount; dwX++)
  233. {
  234. ppControl[dwX] = m_ppControl[dwX];
  235. }
  236. for (; dwX < m_dwControlCount; dwX++)
  237. {
  238. if (m_ppControl[dwX])
  239. {
  240. delete m_ppControl[dwX];
  241. }
  242. }
  243. }
  244. if (m_ppControl)
  245. {
  246. delete[] m_ppControl;
  247. }
  248. m_ppControl = ppControl;
  249. m_dwControlCount = dwCableCount;
  250. }
  251. else
  252. {
  253. hr = E_OUTOFMEMORY;
  254. }
  255. }
  256. ::LeaveCriticalSection(&m_CriticalSection);
  257. return hr;
  258. }
  259. void CSynth::SetGainAdjust(VREL vrGainAdjust)
  260. {
  261. DWORD idx;
  262. m_vrGainAdjust = vrGainAdjust;
  263. ::EnterCriticalSection(&m_CriticalSection);
  264. for (idx = 0; idx < m_dwControlCount; idx++)
  265. {
  266. m_ppControl[idx]->SetGainAdjust(m_vrGainAdjust);
  267. }
  268. ::LeaveCriticalSection(&m_CriticalSection);
  269. }
  270. HRESULT CSynth::SetReverb(DMUS_WAVES_REVERB_PARAMS *pParams)
  271. {
  272. m_ReverbParams = *pParams;
  273. if (m_pCoefs)
  274. {
  275. #ifdef REVERB_ENABLED
  276. ::SetSVerb(m_ReverbParams.fInGain,m_ReverbParams.fReverbMix,
  277. m_ReverbParams.fReverbTime,m_ReverbParams.fHighFreqRTRatio,m_pCoefs );
  278. #endif
  279. }
  280. return S_OK;;
  281. }
  282. void CSynth::SetReverbActive(BOOL fReverb)
  283. {
  284. ::EnterCriticalSection(&m_CriticalSection);
  285. #ifdef REVERB_ENABLED
  286. if (m_fReverbActive != fReverb)
  287. {
  288. if (m_fReverbActive = fReverb)
  289. {
  290. if (!m_pCoefs)
  291. {
  292. long lSize = GetCoefsSize();
  293. m_pCoefs = (void *) malloc(lSize);
  294. lSize = GetStatesSize();
  295. m_pStates = (long *) malloc(lSize);
  296. if (m_pCoefs && m_pStates)
  297. {
  298. memset((void *) m_pStates,0,lSize);
  299. InitSVerb( (float) m_dwSampleRate, m_pCoefs);
  300. InitSVerbStates( m_pStates );
  301. SetReverb(&m_ReverbParams);
  302. }
  303. }
  304. else if (m_pStates)
  305. {
  306. InitSVerbStates( m_pStates );
  307. }
  308. }
  309. }
  310. #else
  311. m_fReverbActive = FALSE;
  312. #endif
  313. ::LeaveCriticalSection(&m_CriticalSection);
  314. }
  315. void CSynth::GetReverb(DMUS_WAVES_REVERB_PARAMS *pParams)
  316. {
  317. *pParams = m_ReverbParams;
  318. }
  319. BOOL CSynth::IsReverbActive()
  320. {
  321. return m_fReverbActive;
  322. }
  323. HRESULT CSynth::Open(DWORD dwCableCount, DWORD dwVoices, BOOL fReverb)
  324. {
  325. HRESULT hr = S_OK;
  326. if ((dwCableCount < 1) || (dwCableCount > MAX_CHANNEL_GROUPS))
  327. {
  328. Trace(1,"Error: Request to open synth with %ld channel groups is invalid.\n",dwCableCount);
  329. return E_INVALIDARG;
  330. }
  331. if (m_ppControl)
  332. {
  333. Trace(1,"Error: Request to open synth failed because synth was already opened.\n");
  334. return E_FAIL; // Already opened.
  335. }
  336. ::EnterCriticalSection(&m_CriticalSection);
  337. hr = SetNumChannelGroups(dwCableCount);
  338. if (SUCCEEDED(hr))
  339. {
  340. short nTemp = (short) dwVoices / 4;
  341. if (nTemp < 4) nTemp = 4;
  342. SetMaxVoices((short) dwVoices, nTemp);
  343. }
  344. SetReverbActive(fReverb);
  345. m_vrGainAdjust = 0;
  346. ::LeaveCriticalSection(&m_CriticalSection);
  347. return hr;
  348. }
  349. HRESULT CSynth::Close()
  350. {
  351. ::EnterCriticalSection(&m_CriticalSection);
  352. AllNotesOff();
  353. DWORD dwX;
  354. for (dwX = 0; dwX < m_dwControlCount; dwX++)
  355. {
  356. if (m_ppControl[dwX])
  357. {
  358. delete m_ppControl[dwX];
  359. }
  360. }
  361. m_dwControlCount = 0;
  362. if (m_ppControl)
  363. {
  364. delete[] m_ppControl;
  365. m_ppControl = NULL;
  366. }
  367. m_stLastStats = 0;
  368. m_stLastTime = 0;
  369. m_fReverbActive = FALSE;
  370. #ifdef REVERB_ENABLED
  371. if (m_pCoefs)
  372. {
  373. free(m_pCoefs);
  374. m_pCoefs = NULL;
  375. }
  376. if (m_pStates)
  377. {
  378. free(m_pStates);
  379. m_pStates = NULL;
  380. }
  381. #endif
  382. ::LeaveCriticalSection(&m_CriticalSection);
  383. return S_OK;
  384. }
  385. HRESULT CSynth::GetMaxVoices(
  386. short * pnMaxVoices, // Returns maximum number of allowed voices for continuous play.
  387. short * pnTempVoices ) // Returns number of extra voices for voice overflow.
  388. {
  389. if (pnMaxVoices != NULL)
  390. {
  391. *pnMaxVoices = m_nMaxVoices;
  392. }
  393. if (pnTempVoices != NULL)
  394. {
  395. *pnTempVoices = m_nExtraVoices;
  396. }
  397. return S_OK;
  398. }
  399. HRESULT CSynth::SetSampleRate(
  400. DWORD dwSampleRate)
  401. {
  402. HRESULT hr = S_OK;
  403. // Can't set the sample rate to 0
  404. if (dwSampleRate == 0)
  405. {
  406. Trace(1,"Error: Request to set sample rate to 0 failed.\n");
  407. return E_INVALIDARG;
  408. }
  409. ::EnterCriticalSection(&m_CriticalSection);
  410. AllNotesOff();
  411. if ( m_dwSampleRate || dwSampleRate )
  412. {
  413. m_stLastTime *= dwSampleRate;
  414. m_stLastTime /= m_dwSampleRate;
  415. }
  416. //>>>>>>>>>>> why is this commented out????
  417. // m_stLastTime = MulDiv(m_stLastTime,dwSampleRate,m_dwSampleRate);
  418. m_stLastStats = 0;
  419. m_dwSampleRate = dwSampleRate;
  420. m_stMinSpan = dwSampleRate / 100; // 10 ms.
  421. m_stMaxSpan = (dwSampleRate + 19) / 20; // 50 ms.
  422. ::LeaveCriticalSection(&m_CriticalSection);
  423. m_Instruments.SetSampleRate(dwSampleRate);
  424. return hr;
  425. }
  426. HRESULT CSynth::Activate(DWORD dwSampleRate, DWORD dwBufferFlags)
  427. {
  428. #ifdef REVERB_ENABLED
  429. if (m_fReverbActive && m_pStates && m_pCoefs)
  430. {
  431. InitSVerb( (float) m_dwSampleRate, m_pCoefs);
  432. InitSVerbStates( m_pStates );
  433. SetReverb(&m_ReverbParams);
  434. }
  435. #endif
  436. m_stLastTime = 0;
  437. SetSampleRate(dwSampleRate);
  438. SetStereoMode(dwBufferFlags);
  439. ResetPerformanceStats();
  440. return S_OK;
  441. }
  442. HRESULT CSynth::Deactivate()
  443. {
  444. AllNotesOff();
  445. return S_OK;
  446. }
  447. HRESULT CSynth::GetPerformanceStats(PerfStats *pStats)
  448. {
  449. if (pStats == NULL)
  450. {
  451. Trace(1,"Error: Null pointer passed for performance stats.\n");
  452. return E_POINTER;
  453. }
  454. *pStats = m_CopyStats;
  455. return (S_OK);
  456. }
  457. bool CSynth::BusIDToFunctionID(DWORD dwBusID, DWORD *pdwFunctionID, long *plPitchBends, DWORD *pdwIndex)
  458. {
  459. // This should only be called if the internal bus pointers exist and there is at least one buffer.
  460. assert(m_pdwBusIDs && m_pdwFuncIDs && m_plPitchBends && m_dwBufferCount);
  461. // Scan through the list of bus ids, looking for the match for dwBusID.
  462. for ( DWORD nIndexSinkIds = 0; nIndexSinkIds < m_dwBufferCount; nIndexSinkIds++ )
  463. {
  464. // Is this one it?
  465. if (m_pdwBusIDs[nIndexSinkIds] == dwBusID)
  466. {
  467. *pdwFunctionID = m_pdwFuncIDs[nIndexSinkIds];
  468. if (plPitchBends)
  469. *plPitchBends = m_plPitchBends[nIndexSinkIds];
  470. if (pdwIndex)
  471. *pdwIndex = nIndexSinkIds;
  472. return true;
  473. }
  474. }
  475. return false;
  476. }
  477. void CSynth::Mix(short **ppvBuffer, DWORD *pdwIDs, DWORD *pdwFuncIDs, long *plPitchBends, DWORD dwBufferCount, DWORD dwBufferFlags, DWORD dwLength, LONGLONG llPosition)
  478. {
  479. static BOOL fDidLast = FALSE;
  480. STIME stEndTime;
  481. CVoice *pVoice;
  482. CVoice *pNextVoice;
  483. long lNumVoices = 0;
  484. DWORD i;
  485. ::EnterCriticalSection(&m_CriticalSection);
  486. // Store pointers to the id arrays so we can access them from BusIDToFunctionID.
  487. m_pdwBusIDs = pdwIDs;
  488. m_pdwFuncIDs = pdwFuncIDs;
  489. m_plPitchBends = plPitchBends;
  490. m_dwBufferCount = dwBufferCount;
  491. /* // Useful for debugging the incoming buses...
  492. static DWORD sdwCountDown = 0;
  493. if (!sdwCountDown)
  494. {
  495. for (DWORD dwIX = 0; dwIX < dwBufferCount; dwIX++)
  496. {
  497. Trace(0,"%ld:%ld->%ld\t",dwIX,pdwIDs[dwIX],pdwFuncIDs[dwIX]);
  498. }
  499. Trace(0,"\n");
  500. sdwCountDown = 100;
  501. }
  502. sdwCountDown--;*/
  503. LONG lTime = - (LONG)::GetTheCurrentTime();
  504. stEndTime = llPosition + dwLength;
  505. StealNotes(stEndTime);
  506. DWORD dwX;
  507. for ( i = 0; i < dwBufferCount; i++ )
  508. {
  509. // For interleaved buffers only the first buss is valid
  510. if ( dwBufferFlags & BUFFERFLAG_INTERLEAVED && i > 0 )
  511. {
  512. break;
  513. }
  514. StartMix(ppvBuffer[i],dwLength,(dwBufferFlags&BUFFERFLAG_INTERLEAVED));
  515. }
  516. for (dwX = 0; dwX < m_dwControlCount; dwX++)
  517. {
  518. m_ppControl[dwX]->QueueNotes(llPosition, stEndTime);
  519. m_ppControl[dwX]->QueueWaves(stEndTime);
  520. }
  521. pVoice = m_VoicesInUse.GetHead();
  522. for (;pVoice != NULL;pVoice = pNextVoice)
  523. {
  524. if (pVoice->m_stWaveStopTime && (pVoice->m_stWaveStopTime < stEndTime))
  525. {
  526. pVoice->StopVoice(pVoice->m_stWaveStopTime);
  527. }
  528. pNextVoice = pVoice->GetNext();
  529. pVoice->Mix(ppvBuffer, dwBufferFlags, dwLength, llPosition, stEndTime);
  530. lNumVoices++;
  531. if (pVoice->m_fInUse == FALSE)
  532. {
  533. m_VoicesInUse.Remove(pVoice);
  534. m_VoicesFree.AddHead(pVoice);
  535. if (pVoice->m_stStartTime < m_stLastStats)
  536. {
  537. m_BuildStats.dwTotalSamples += (long) (pVoice->m_stStopTime - m_stLastStats);
  538. }
  539. else
  540. {
  541. m_BuildStats.dwTotalSamples += (long) (pVoice->m_stStopTime - pVoice->m_stStartTime);
  542. }
  543. }
  544. }
  545. for (dwX = 0; dwX < m_dwControlCount; dwX++)
  546. {
  547. m_ppControl[dwX]->ClearMIDI(stEndTime);
  548. }
  549. #ifdef REVERB_ENABLED
  550. if (m_fReverbActive && m_pCoefs && m_pStates && !(dwBufferFlags & BUFFERFLAG_MULTIBUFFER) )
  551. {
  552. if (dwBufferFlags & BUFFERFLAG_INTERLEAVED)
  553. {
  554. SVerbStereoToStereoShort(dwLength,ppvBuffer[0],ppvBuffer[0],m_pCoefs,m_pStates);
  555. }
  556. else
  557. {
  558. SVerbMonoToMonoShort(dwLength,ppvBuffer[0],ppvBuffer[0],m_pCoefs,m_pStates);
  559. }
  560. }
  561. #endif
  562. for ( i = 0; i < dwBufferCount; i++ )
  563. {
  564. // For interleaved buffers only the first buss is valid
  565. if ( dwBufferFlags & BUFFERFLAG_INTERLEAVED && i > 0 )
  566. {
  567. break;
  568. }
  569. FinishMix(ppvBuffer[i],dwLength,(dwBufferFlags&BUFFERFLAG_INTERLEAVED));
  570. }
  571. if (stEndTime > m_stLastTime)
  572. {
  573. m_stLastTime = stEndTime;
  574. }
  575. lTime += ::GetTheCurrentTime();
  576. m_BuildStats.dwTotalTime += lTime;
  577. if ((m_stLastStats + m_dwSampleRate) <= m_stLastTime)
  578. {
  579. DWORD dwElapsed = (DWORD) (m_stLastTime - m_stLastStats);
  580. pVoice = m_VoicesInUse.GetHead();
  581. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  582. {
  583. if (pVoice->m_stStartTime < m_stLastStats)
  584. {
  585. m_BuildStats.dwTotalSamples += dwElapsed;
  586. }
  587. else
  588. {
  589. m_BuildStats.dwTotalSamples += (long) (m_stLastTime - pVoice->m_stStartTime);
  590. }
  591. }
  592. if (dwElapsed == 0)
  593. dwElapsed = 1;
  594. if (m_BuildStats.dwTotalSamples == 0)
  595. m_BuildStats.dwTotalSamples = 1;
  596. m_BuildStats.dwVoices =
  597. (m_BuildStats.dwTotalSamples + (dwElapsed >> 1)) / dwElapsed;
  598. {
  599. m_BuildStats.dwCPU = MulDiv(m_BuildStats.dwTotalTime,
  600. m_dwSampleRate, dwElapsed);
  601. }
  602. m_CopyStats = m_BuildStats;
  603. memset(&m_BuildStats, 0, sizeof(m_BuildStats));
  604. m_stLastStats = m_stLastTime;
  605. }
  606. m_pdwBusIDs = NULL;
  607. m_pdwFuncIDs = NULL;
  608. m_plPitchBends = NULL;
  609. m_dwBufferCount = 0;
  610. ::LeaveCriticalSection(&m_CriticalSection);
  611. }
  612. CVoice *CSynth::OldestVoice()
  613. {
  614. CVoice *pVoice;
  615. CVoice *pBest = NULL;
  616. pVoice = m_VoicesInUse.GetHead();
  617. pBest = pVoice;
  618. if (pBest)
  619. {
  620. pVoice = pVoice->GetNext();
  621. for (;pVoice;pVoice = pVoice->GetNext())
  622. {
  623. if (!pVoice->m_fTag)
  624. {
  625. if (pBest->m_fTag)
  626. {
  627. pBest = pVoice;
  628. }
  629. else
  630. {
  631. if (pVoice->m_dwPriority <= pBest->m_dwPriority)
  632. {
  633. if (pVoice->m_fNoteOn)
  634. {
  635. if (pBest->m_fNoteOn)
  636. {
  637. if (pBest->m_stStartTime > pVoice->m_stStartTime)
  638. {
  639. pBest = pVoice;
  640. }
  641. }
  642. }
  643. else
  644. {
  645. if (pBest->m_fNoteOn ||
  646. (pBest->m_vrVolume > pVoice->m_vrVolume))
  647. {
  648. pBest = pVoice;
  649. }
  650. }
  651. }
  652. }
  653. }
  654. }
  655. if (pBest->m_fTag)
  656. {
  657. pBest = NULL;
  658. }
  659. }
  660. return pBest;
  661. }
  662. CVoice *CSynth::StealVoice(DWORD dwPriority)
  663. {
  664. CVoice *pVoice;
  665. CVoice *pBest = NULL;
  666. pVoice = m_VoicesInUse.GetHead();
  667. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  668. {
  669. if (pVoice->m_dwPriority <= dwPriority)
  670. {
  671. if (!pBest)
  672. {
  673. pBest = pVoice;
  674. }
  675. else
  676. {
  677. if (pVoice->m_fNoteOn == FALSE)
  678. {
  679. if ((pBest->m_fNoteOn == TRUE) ||
  680. (pBest->m_vrVolume > pVoice->m_vrVolume))
  681. {
  682. pBest = pVoice;
  683. }
  684. }
  685. else
  686. {
  687. if (pBest->m_stStartTime > pVoice->m_stStartTime)
  688. {
  689. pBest = pVoice;
  690. }
  691. }
  692. }
  693. }
  694. }
  695. if (pBest != NULL)
  696. {
  697. pBest->ClearVoice();
  698. pBest->m_fInUse = FALSE;
  699. m_VoicesInUse.Remove(pBest);
  700. pBest->SetNext(NULL);
  701. }
  702. return pBest;
  703. }
  704. void CSynth::QueueVoice(CVoice *pVoice)
  705. /* This function queues a voice in the list of currently
  706. synthesizing voices. It places them in the queue so that
  707. the higher priority voices are later in the queue. This
  708. allows the note stealing algorithm to take off the top of
  709. the queue.
  710. And, we want older playing notes to be later in the queue
  711. so the note ons and offs overlap properly. So, the queue is
  712. sorted in priority order with older notes later within one
  713. priority level.
  714. */
  715. {
  716. CVoice *pScan = m_VoicesInUse.GetHead();
  717. CVoice *pNext = NULL;
  718. if (!pScan) // Empty list?
  719. {
  720. m_VoicesInUse.AddHead(pVoice);
  721. return;
  722. }
  723. if (pScan->m_dwPriority > pVoice->m_dwPriority)
  724. { // Are we lower priority than the head of the list?
  725. m_VoicesInUse.AddHead(pVoice);
  726. return;
  727. }
  728. pNext = pScan->GetNext();
  729. for (;pNext;)
  730. {
  731. if (pNext->m_dwPriority > pVoice->m_dwPriority)
  732. {
  733. // Lower priority than next in the list.
  734. pScan->SetNext(pVoice);
  735. pVoice->SetNext(pNext);
  736. return;
  737. }
  738. pScan = pNext;
  739. pNext = pNext->GetNext();
  740. }
  741. // Reached the end of the list.
  742. pScan->SetNext(pVoice);
  743. pVoice->SetNext(NULL);
  744. }
  745. void CSynth::StealNotes(STIME stTime)
  746. {
  747. CVoice *pVoice;
  748. long lToMove = m_nExtraVoices - m_VoicesExtra.GetCount();
  749. if (lToMove > 0)
  750. {
  751. for (;lToMove > 0;)
  752. {
  753. pVoice = m_VoicesFree.RemoveHead();
  754. if (pVoice != NULL)
  755. {
  756. m_VoicesExtra.AddHead(pVoice);
  757. lToMove--;
  758. }
  759. else break;
  760. }
  761. if (lToMove > 0)
  762. {
  763. pVoice = m_VoicesInUse.GetHead();
  764. for (;pVoice;pVoice = pVoice->GetNext())
  765. {
  766. if (pVoice->m_fTag) // Voice is already slated to be returned.
  767. {
  768. lToMove--;
  769. }
  770. }
  771. for (;lToMove > 0;lToMove--)
  772. {
  773. pVoice = OldestVoice();
  774. if (pVoice != NULL)
  775. {
  776. pVoice->QuickStopVoice(stTime);
  777. m_BuildStats.dwNotesLost++;
  778. }
  779. else break;
  780. }
  781. }
  782. }
  783. }
  784. #ifndef i386
  785. void CSynth::StartMix(short *pBuffer,DWORD dwLength, BOOL bInterleaved)
  786. {
  787. DWORD dwIndex = 0;
  788. DWORD dwLen = dwLength << bInterleaved;
  789. for (; dwIndex < dwLen; dwIndex++)
  790. {
  791. pBuffer[dwIndex] <<= 1;
  792. }
  793. }
  794. #else
  795. void CSynth::StartMix(short *pBuffer,DWORD dwLength, BOOL bInterleaved)
  796. {
  797. DWORD dwIndex;
  798. DWORD dwLen = dwLength << bInterleaved;
  799. dwIndex = 0;
  800. if (m_sfMMXEnabled && dwLen >= 16)
  801. {
  802. dwIndex = (dwLen & ~0x0000000F);
  803. _asm {
  804. mov eax, dwIndex
  805. mov ebx, pBuffer
  806. lea ebx, [ebx+eax*2] // move to the end to start...
  807. neg eax
  808. TopOfLoop:
  809. movq mm0, [ebx+eax*2]
  810. movq mm1, [ebx+eax*2+8]
  811. psraw mm0, 1
  812. movq mm2, [ebx+eax*2+16]
  813. psraw mm1, 1
  814. movq mm3, [ebx+eax*2+24]
  815. psraw mm2, 1
  816. movq [ebx+eax*2], mm0
  817. psraw mm3, 1
  818. movq [ebx+eax*2+8], mm1
  819. movq [ebx+eax*2+16], mm2
  820. movq [ebx+eax*2+24], mm3
  821. add eax, 16
  822. jl TopOfLoop
  823. emms
  824. }
  825. }
  826. for (; dwIndex < dwLen; dwIndex++)
  827. {
  828. pBuffer[dwIndex] <<= 1;
  829. }
  830. }
  831. #endif
  832. //////////////////////////////////////////////////////////////////
  833. // FinishMix - C Base for Optimized code
  834. #ifndef i386
  835. void CSynth::FinishMix(short *pBuffer,DWORD dwLength, BOOL bInterleaved)
  836. {
  837. DWORD dwIndex = 0;
  838. long lMax = (long) m_BuildStats.dwMaxAmplitude;
  839. long lTemp;
  840. DWORD dwLen = dwLength << bInterleaved;
  841. for (; dwIndex < dwLen; dwIndex++)
  842. {
  843. lTemp = pBuffer[dwIndex];
  844. lTemp <<= 1;
  845. if (lTemp < -32767) lTemp = -32767;
  846. if (lTemp > 32767) lTemp = 32767;
  847. pBuffer[dwIndex] = (short) lTemp;
  848. if (lTemp > lMax)
  849. {
  850. lMax = lTemp;
  851. }
  852. else if (lTemp < 0 && -lTemp > lMax)
  853. {
  854. lMax = -lTemp;
  855. }
  856. }
  857. m_BuildStats.dwMaxAmplitude = lMax;
  858. }
  859. #else
  860. void CSynth::FinishMix(short *pBuffer,DWORD dwLength, BOOL bInterleaved)
  861. {
  862. DWORD dwIndex;
  863. long lMax = (long) m_BuildStats.dwMaxAmplitude;
  864. long lTemp;
  865. DWORD dwLen = dwLength << bInterleaved;
  866. short PosMax, NegMax;
  867. PosMax = (short) lMax;
  868. NegMax = - (short) lMax;
  869. dwIndex = 0;
  870. if (m_sfMMXEnabled && dwLen >= 4)
  871. {
  872. dwIndex = (dwLen & ~0x3);
  873. _asm {
  874. mov eax, dwIndex
  875. mov ebx, pBuffer
  876. lea ebx, [ebx+eax*2] // move to the end to start...
  877. neg eax
  878. pxor mm0, mm0
  879. movsx ecx, WORD PTR PosMax
  880. movsx edx, WORD PTR NegMax
  881. Start:
  882. movq mm1, QWORD PTR [ebx+eax*2]
  883. movq mm2, mm1
  884. punpcklwd mm1, mm0
  885. punpckhwd mm2, mm0
  886. pslld mm1, 16
  887. pslld mm2, 16
  888. psrad mm1, 15
  889. psrad mm2, 15
  890. packssdw mm1, mm2
  891. movq QWORD PTR [ebx+eax*2], mm1
  892. movsx esi, WORD PTR [ebx+eax*2]
  893. movsx edi, WORD PTR [ebx+eax*2+2]
  894. cmp esi, ecx
  895. jg Max1
  896. Max10: cmp edi, edx
  897. jl Min1
  898. Min10: movsx esi, WORD PTR [ebx+eax*2+4]
  899. cmp edi, ecx
  900. jg Max2
  901. Max20: cmp edi, edx
  902. jl Min2
  903. Min20: movsx edi, WORD PTR [ebx+eax*2+6]
  904. cmp esi, ecx
  905. jg Max3
  906. Max30: cmp esi, edx
  907. jl Min3
  908. Min30: cmp edi, ecx
  909. jg Max4
  910. Max40: cmp edi, edx
  911. jl Min4
  912. Min40: add eax, 4
  913. jl Start
  914. jmp Finished
  915. Max1:
  916. mov ecx, esi
  917. jmp Max10
  918. Max2:
  919. mov ecx, edi
  920. jmp Max20
  921. Max3:
  922. mov ecx, esi
  923. jmp Max30
  924. Max4:
  925. mov ecx, edi
  926. jmp Max40
  927. Min1:
  928. mov edx, esi
  929. jmp Min10
  930. Min2:
  931. mov edx, edi
  932. jmp Min20
  933. Min3:
  934. mov edx, esi
  935. jmp Min30
  936. Min4:
  937. mov edx, edi
  938. jmp Min40
  939. Finished:
  940. emms
  941. mov WORD PTR PosMax, cx
  942. mov WORD PTR NegMax, dx
  943. }
  944. if (lMax < PosMax)
  945. lMax = PosMax;
  946. if (lMax < -NegMax)
  947. lMax = -NegMax;
  948. }
  949. for (; dwIndex < dwLen; dwIndex++)
  950. {
  951. lTemp = pBuffer[dwIndex];
  952. lTemp <<= 1;
  953. if (lTemp < -32767) lTemp = -32767;
  954. if (lTemp > 32767) lTemp = 32767;
  955. pBuffer[dwIndex] = (short) lTemp;
  956. if (lTemp > lMax)
  957. {
  958. lMax = lTemp;
  959. }
  960. else if (lTemp < 0 && -lTemp > lMax)
  961. {
  962. lMax = -lTemp;
  963. }
  964. }
  965. m_BuildStats.dwMaxAmplitude = lMax;
  966. }
  967. #endif
  968. HRESULT CSynth::Unload(HANDLE hDownload,
  969. HRESULT ( CALLBACK *lpFreeMemory)(HANDLE,HANDLE),
  970. HANDLE hUserData)
  971. {
  972. return m_Instruments.Unload( hDownload, lpFreeMemory, hUserData);
  973. }
  974. HRESULT CSynth::Download(LPHANDLE phDownload, void * pdwData, LPBOOL bpFree)
  975. {
  976. return m_Instruments.Download( phDownload, (DWORD *) pdwData, bpFree);
  977. }
  978. HRESULT CSynth::PlayBuffer(IDirectMusicSynthSink *pSynthSink, REFERENCE_TIME rt, LPBYTE lpBuffer, DWORD cbBuffer, ULONG ulCable)
  979. {
  980. STIME stTime;
  981. ::EnterCriticalSection(&m_CriticalSection);
  982. if ( rt == 0 ) // Special case of time == 0.
  983. {
  984. stTime = m_stLastTime;
  985. }
  986. else
  987. {
  988. pSynthSink->RefTimeToSample(rt, &stTime);
  989. }
  990. PlayBuffer(stTime, rt, lpBuffer, cbBuffer, ulCable);
  991. ::LeaveCriticalSection(&m_CriticalSection);
  992. return S_OK;
  993. }
  994. HRESULT CSynth::PlayBuffer(IDirectSoundSynthSink *pSynthSink, REFERENCE_TIME rt, LPBYTE lpBuffer, DWORD cbBuffer, ULONG ulCable)
  995. {
  996. STIME stTime;
  997. ::EnterCriticalSection(&m_CriticalSection);
  998. if ( rt == 0 ) // Special case of time == 0.
  999. {
  1000. stTime = m_stLastTime;
  1001. }
  1002. else
  1003. {
  1004. pSynthSink->RefToSampleTime(rt, &stTime);
  1005. }
  1006. //Trace(0,"Reftime[%lx%08lx] LastTime[%lx%08lx] SampleTime[%lx%08lx]\n\r",(DWORD)(rt>>32),(DWORD)(rt&0x00000000ffffffff),(DWORD)(m_stLastTime>>32),(DWORD)(m_stLastTime&0x00000000ffffffff),(DWORD)(stTime>>32),(DWORD)(stTime&0x00000000ffffffff));
  1007. PlayBuffer(stTime, rt, lpBuffer, cbBuffer, ulCable);
  1008. ::LeaveCriticalSection(&m_CriticalSection);
  1009. return S_OK;
  1010. }
  1011. HRESULT CSynth::PlayBuffer(STIME stTime, REFERENCE_TIME rt, LPBYTE lpBuffer, DWORD cbBuffer, ULONG ulCable)
  1012. {
  1013. ::EnterCriticalSection(&m_CriticalSection);
  1014. if (cbBuffer <= sizeof(DWORD))
  1015. {
  1016. #ifdef DBG
  1017. if (stTime < m_stLastTime)
  1018. {
  1019. static DWORD dwFailed = 0;
  1020. if ((lpBuffer[0] & 0xF0) == MIDI_NOTEON)
  1021. {
  1022. if (!dwFailed)
  1023. {
  1024. Trace(2,"Warning: Note On arrived too late to the synth, synth has mixed ahead by %ld samples. This could be caused by latency calculated too low.\n",
  1025. (long) (m_stLastTime - stTime));
  1026. dwFailed = 100;
  1027. }
  1028. dwFailed--;
  1029. }
  1030. }
  1031. else if ((stTime - (10000 * 1000)) > m_stLastTime)
  1032. {
  1033. static DWORD dwFailed = 0;
  1034. if ((lpBuffer[0] & 0xF0) == MIDI_NOTEON)
  1035. {
  1036. if (!dwFailed)
  1037. {
  1038. Trace(2,"Warning: Note On at sample %ld, was stamped too late for synth, which is at mix time %ld, error is %ld samples\n",
  1039. (long) stTime, (long) m_stLastTime, (long) (m_stLastTime - stTime));
  1040. dwFailed = 100;
  1041. }
  1042. dwFailed--;
  1043. }
  1044. }
  1045. #endif
  1046. if (ulCable <= m_dwControlCount)
  1047. {
  1048. if (ulCable == 0) // Play all groups if 0.
  1049. {
  1050. for (; ulCable < m_dwControlCount; ulCable++)
  1051. {
  1052. m_ppControl[ulCable]->RecordMIDI(stTime,lpBuffer[0],
  1053. lpBuffer[1], lpBuffer[2]);
  1054. }
  1055. }
  1056. else
  1057. {
  1058. m_ppControl[ulCable - 1]->RecordMIDI(stTime,lpBuffer[0],
  1059. lpBuffer[1], lpBuffer[2]);
  1060. }
  1061. }
  1062. else
  1063. {
  1064. Trace(1,"Error: MIDI event on channel group %ld is beyond range of %ld opened channel groups\n",
  1065. ulCable, m_dwControlCount);
  1066. }
  1067. }
  1068. else
  1069. {
  1070. if (ulCable <= m_dwControlCount)
  1071. {
  1072. if (ulCable == 0)
  1073. {
  1074. for (; ulCable < m_dwControlCount; ulCable++)
  1075. {
  1076. m_ppControl[ulCable]->RecordSysEx(cbBuffer,
  1077. &lpBuffer[0], stTime);
  1078. }
  1079. }
  1080. else
  1081. {
  1082. m_ppControl[ulCable-1]->RecordSysEx(cbBuffer,
  1083. &lpBuffer[0], stTime);
  1084. }
  1085. }
  1086. }
  1087. ::LeaveCriticalSection(&m_CriticalSection);
  1088. return S_OK;
  1089. }
  1090. // Sets the stereo mode for the synth
  1091. // this value is currently only being used
  1092. // to deterim whether one can pan or not.
  1093. HRESULT CSynth::SetStereoMode(
  1094. DWORD dwBufferFlags )
  1095. {
  1096. HRESULT hr = S_OK;
  1097. if (dwBufferFlags & BUFFERFLAG_INTERLEAVED )
  1098. {
  1099. m_dwStereo = TRUE;
  1100. }
  1101. else if (dwBufferFlags & BUFFERFLAG_MULTIBUFFER )
  1102. {
  1103. m_dwStereo = TRUE;
  1104. }
  1105. else
  1106. m_dwStereo = FALSE;
  1107. return hr;
  1108. }
  1109. void CSynth::ResetPerformanceStats()
  1110. {
  1111. m_BuildStats.dwNotesLost = 0;
  1112. m_BuildStats.dwTotalTime = 0;
  1113. m_BuildStats.dwVoices = 0;
  1114. m_BuildStats.dwTotalSamples = 0;
  1115. m_BuildStats.dwCPU = 0;
  1116. m_BuildStats.dwMaxAmplitude = 0;
  1117. m_CopyStats = m_BuildStats;
  1118. }
  1119. HRESULT CSynth::AllNotesOff()
  1120. {
  1121. CVoice *pVoice;
  1122. ::EnterCriticalSection(&m_CriticalSection);
  1123. while (pVoice = m_VoicesInUse.RemoveHead())
  1124. {
  1125. pVoice->ClearVoice();
  1126. pVoice->m_fInUse = FALSE;
  1127. m_VoicesFree.AddHead(pVoice);
  1128. if (pVoice->m_stStartTime < m_stLastStats)
  1129. {
  1130. m_BuildStats.dwTotalSamples += (long) (pVoice->m_stStopTime - m_stLastStats);
  1131. }
  1132. else
  1133. {
  1134. m_BuildStats.dwTotalSamples += (long) (pVoice->m_stStopTime - pVoice->m_stStartTime);
  1135. }
  1136. }
  1137. ::LeaveCriticalSection(&m_CriticalSection);
  1138. return (S_OK);
  1139. }
  1140. HRESULT CSynth::SetChannelPriority(
  1141. DWORD dwChannelGroup,
  1142. DWORD dwChannel,
  1143. DWORD dwPriority)
  1144. {
  1145. HRESULT hr = S_OK;
  1146. ::EnterCriticalSection(&m_CriticalSection);
  1147. dwChannelGroup--;
  1148. if ((dwChannelGroup >= m_dwControlCount) || (dwChannel > 15))
  1149. {
  1150. Trace(1,"Error: Request to set channel priority on channel group %ld, channel %ld, is out of range.\n",
  1151. dwChannelGroup,dwChannel);
  1152. hr = E_INVALIDARG;
  1153. }
  1154. else
  1155. {
  1156. if (m_ppControl)
  1157. {
  1158. hr = m_ppControl[dwChannelGroup]->SetChannelPriority(dwChannel,dwPriority);
  1159. }
  1160. }
  1161. ::LeaveCriticalSection(&m_CriticalSection);
  1162. return hr;
  1163. }
  1164. HRESULT CSynth::GetChannelPriority(
  1165. DWORD dwChannelGroup,
  1166. DWORD dwChannel,
  1167. LPDWORD pdwPriority)
  1168. {
  1169. HRESULT hr = S_OK;
  1170. ::EnterCriticalSection(&m_CriticalSection);
  1171. dwChannelGroup--;
  1172. if ((dwChannelGroup >= m_dwControlCount) || (dwChannel > 15))
  1173. {
  1174. Trace(1,"Error: Request to get channel priority on channel group %ld, channel %ld, is out of range.\n",
  1175. dwChannelGroup,dwChannel);
  1176. hr = E_INVALIDARG;
  1177. }
  1178. else
  1179. {
  1180. if (m_ppControl)
  1181. {
  1182. hr = m_ppControl[dwChannelGroup]->GetChannelPriority(dwChannel,pdwPriority);
  1183. }
  1184. }
  1185. ::LeaveCriticalSection(&m_CriticalSection);
  1186. return hr;
  1187. }
  1188. //////////////////////////////////////////////////////////
  1189. // Directx8 Methods
  1190. HRESULT CSynth::PlayVoice(
  1191. IDirectSoundSynthSink *pSynthSink,
  1192. REFERENCE_TIME rt,
  1193. DWORD dwVoiceId,
  1194. DWORD dwChannelGroup,
  1195. DWORD dwChannel,
  1196. DWORD dwDLId,
  1197. VREL vrVolume,
  1198. PREL prPitch,
  1199. SAMPLE_TIME stVoiceStart,
  1200. SAMPLE_TIME stLoopStart,
  1201. SAMPLE_TIME stLoopEnd
  1202. )
  1203. {
  1204. HRESULT hr = S_OK;
  1205. STIME stTime;
  1206. ::EnterCriticalSection(&m_CriticalSection);
  1207. dwChannelGroup--;
  1208. if ((dwChannelGroup >= m_dwControlCount) || (dwChannel > 15))
  1209. {
  1210. Trace(1,"Error: Request to set play voice on channel group %ld, channel %ld, is out of range.\n",
  1211. dwChannelGroup,dwChannel);
  1212. hr = E_INVALIDARG;
  1213. }
  1214. if ( rt == 0 ) // Special case of time == 0.
  1215. {
  1216. stTime = m_stLastTime;
  1217. }
  1218. else
  1219. {
  1220. pSynthSink->RefToSampleTime(rt, &stTime);
  1221. }
  1222. CWaveArt *pWaveArt = m_Instruments.GetWaveArt(dwDLId);
  1223. if ( pWaveArt )
  1224. m_ppControl[dwChannelGroup]->RecordWaveEvent(
  1225. stTime,
  1226. (BYTE)(dwChannel & 0xF),
  1227. dwVoiceId,
  1228. vrVolume,
  1229. prPitch,
  1230. stVoiceStart,
  1231. stLoopStart,
  1232. stLoopEnd,
  1233. pWaveArt);
  1234. ::LeaveCriticalSection(&m_CriticalSection);
  1235. return hr;
  1236. }
  1237. HRESULT CSynth::StopVoice(
  1238. IDirectSoundSynthSink *pSynthSink,
  1239. REFERENCE_TIME rt,
  1240. DWORD dwVoiceId )
  1241. {
  1242. HRESULT hr = S_OK;
  1243. STIME stTime;
  1244. ::EnterCriticalSection(&m_CriticalSection);
  1245. if ( rt == 0 ) // Special case of time == 0.
  1246. {
  1247. stTime = m_stLastTime;
  1248. }
  1249. else
  1250. {
  1251. pSynthSink->RefToSampleTime(rt, &stTime);
  1252. }
  1253. CVoice * pVoice = m_VoicesInUse.GetHead();
  1254. bool fFoundVoice = false;
  1255. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  1256. {
  1257. if ( pVoice->m_dwVoiceId == dwVoiceId )
  1258. {
  1259. pVoice->m_stWaveStopTime = stTime;
  1260. fFoundVoice = true;
  1261. }
  1262. }
  1263. if (!fFoundVoice)
  1264. {
  1265. TraceI(2, "Warning: Synth couldn't find voice %d to stop.\n", dwVoiceId);
  1266. for (DWORD dwX = 0; dwX < m_dwControlCount; dwX++)
  1267. {
  1268. m_ppControl[dwX]->FlushWaveByStopTime(dwVoiceId, stTime);
  1269. }
  1270. }
  1271. ::LeaveCriticalSection(&m_CriticalSection);
  1272. return hr;
  1273. }
  1274. HRESULT CSynth::GetVoiceState(
  1275. DWORD dwVoice[],
  1276. DWORD cbVoice,
  1277. DMUS_VOICE_STATE VoiceState[] )
  1278. {
  1279. HRESULT hr = E_FAIL;
  1280. ::EnterCriticalSection(&m_CriticalSection);
  1281. for ( DWORD i = 0; i < cbVoice; i++ )
  1282. {
  1283. VoiceState[i].bExists = FALSE;
  1284. VoiceState[i].spPosition = 0;
  1285. CVoice * pVoice = m_VoicesInUse.GetHead();
  1286. for (;pVoice != NULL;pVoice = pVoice->GetNext())
  1287. {
  1288. if ( pVoice->m_dwVoiceId == dwVoice[i] )
  1289. {
  1290. VoiceState[i].bExists = TRUE;
  1291. VoiceState[i].spPosition = pVoice->GetCurrentPos();
  1292. break;
  1293. }
  1294. }
  1295. }
  1296. ::LeaveCriticalSection(&m_CriticalSection);
  1297. return S_OK;
  1298. }
  1299. HRESULT CSynth::Refresh(
  1300. DWORD dwDownloadID,
  1301. DWORD dwFlags)
  1302. {
  1303. HRESULT hr = S_OK;
  1304. ::EnterCriticalSection(&m_CriticalSection);
  1305. CWave *pWave = m_Instruments.GetWave(dwDownloadID);
  1306. if ( pWave )
  1307. {
  1308. if ( pWave->m_bValid )
  1309. {
  1310. Trace(1,"Error: Attempting to validate already validated streaming buffer\n\r");
  1311. hr = E_FAIL;
  1312. }
  1313. if ( pWave->m_bActive )
  1314. {
  1315. Trace(1,"Error: Attempting to validate active playing streaming buffer\n\r");
  1316. hr = E_FAIL;
  1317. }
  1318. if (SUCCEEDED(hr))
  1319. {
  1320. pWave->m_bValid = TRUE;
  1321. if (pWave->m_bSampleType == SFORMAT_8)
  1322. {
  1323. DWORD dwX;
  1324. char *pData = (char *) pWave->m_pnWave;
  1325. for (dwX = 0; dwX < pWave->m_dwSampleLength; dwX++)
  1326. {
  1327. pData[dwX] -= (char) 128;
  1328. }
  1329. }
  1330. // Indicate that we did find a vaild download id
  1331. hr = S_OK;
  1332. }
  1333. }
  1334. ::LeaveCriticalSection(&m_CriticalSection);
  1335. return hr;
  1336. }
  1337. HRESULT CSynth::AssignChannelToBuses(
  1338. DWORD dwChannelGroup,
  1339. DWORD dwChannel,
  1340. LPDWORD pdwBuses,
  1341. DWORD cBuses)
  1342. {
  1343. HRESULT hr = S_OK;
  1344. ::EnterCriticalSection(&m_CriticalSection);
  1345. //>>>>>>> Probably need a better check here since panning is only valid for left and right?
  1346. dwChannelGroup--;
  1347. if ((dwChannelGroup >= m_dwControlCount) || (dwChannel > 15))
  1348. {
  1349. hr = E_INVALIDARG;
  1350. }
  1351. if (SUCCEEDED(hr))
  1352. {
  1353. hr = m_ppControl[dwChannelGroup]->AssignChannelToBuses(dwChannel, pdwBuses, cBuses);
  1354. }
  1355. ::LeaveCriticalSection(&m_CriticalSection);
  1356. return hr;
  1357. }