Source code of Windows XP (NT5)
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.

2200 lines
67 KiB

  1. /*
  2. DirectMusic Software Synthesizer Miniport
  3. Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
  4. */
  5. #include "common.h"
  6. #include "private.h"
  7. #include "fltsafe.h"
  8. #include <math.h>
  9. #define STR_MODULENAME "DDKSynth.sys:Miniport: "
  10. /* NYI:
  11. more sample rates?
  12. */
  13. #ifdef USE_OBSOLETE_FUNCS
  14. VOID PutMessageWorker(PVOID Param);
  15. #endif
  16. // Property handler
  17. //
  18. NTSTATUS PropertyHandler_Support(IN PPCPROPERTY_REQUEST);
  19. NTSTATUS PropertyHandler_Effects(IN PPCPROPERTY_REQUEST);
  20. NTSTATUS PropertyHandler_Synth(IN PPCPROPERTY_REQUEST);
  21. NTSTATUS PropertyHandler_SynthCaps(IN PPCPROPERTY_REQUEST);
  22. NTSTATUS PropertyHandler_SynthDls(IN PPCPROPERTY_REQUEST);
  23. // Misc.
  24. NTSTATUS DefaultSynthBasicPropertyHandler(IN PPCPROPERTY_REQUEST pRequest);
  25. NTSTATUS DefaultBasicPropertyHandler(IN PPCPROPERTY_REQUEST pRequest, IN DWORD dwSupportVerb);
  26. NTSTATUS ValidatePropertyParams(IN PPCPROPERTY_REQUEST pRequest, IN ULONG cbSize, IN DWORD dwExcludeVerb);
  27. /*****************************************************************************
  28. * PinDataRangesStream[]
  29. *****************************************************************************
  30. * Structures indicating range of valid format values for streaming pins.
  31. * If your device can also support legacy MIDI, include a second data range
  32. * here that supports KSDATAFORMAT_SUBTYPE_MIDI.
  33. */
  34. static const
  35. KSDATARANGE_MUSIC
  36. PinDataRangesStream[] =
  37. {
  38. {
  39. {
  40. sizeof(KSDATARANGE_MUSIC),
  41. 0,
  42. 0,
  43. 0,
  44. STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC),
  45. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC),
  46. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
  47. },
  48. STATICGUIDOF(KSMUSIC_TECHNOLOGY_WAVETABLE),
  49. 0, // Channels
  50. 0, // Notes
  51. 0x0000ffff // ChannelMask
  52. }
  53. };
  54. /*****************************************************************************
  55. * PinDataRangePointersStream[]
  56. *****************************************************************************
  57. * List of pointers to structures indicating range of valid format values
  58. * for streaming pins.
  59. */
  60. static const
  61. PKSDATARANGE
  62. PinDataRangePointersStream[] =
  63. {
  64. PKSDATARANGE(&PinDataRangesStream[0])
  65. };
  66. /*****************************************************************************
  67. * PinDataRangesAudio[]
  68. *****************************************************************************
  69. * Structures indicating range of valid format values for audio pins.
  70. *
  71. * Do not include this if you are building a hardware device that does not
  72. * output audio back into the system.
  73. */
  74. static const
  75. KSDATARANGE_AUDIO
  76. PinDataRangesAudio[] =
  77. {
  78. {
  79. {
  80. sizeof(KSDATARANGE_AUDIO),
  81. 0,
  82. 0,
  83. 0,
  84. STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
  85. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
  86. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
  87. },
  88. 2,
  89. 16,
  90. 16,
  91. 22050,
  92. 22050
  93. }
  94. };
  95. /*****************************************************************************
  96. * PinDataRangePointersAudio[]
  97. *****************************************************************************
  98. * List of pointers to structures indicating range of valid format values
  99. * for audio pins.
  100. *
  101. * Do not include this if you are building a hardware device that does not
  102. * output audio back into the system.
  103. */
  104. static const
  105. PKSDATARANGE
  106. PinDataRangePointersAudio[] =
  107. {
  108. PKSDATARANGE(&PinDataRangesAudio[0])
  109. };
  110. /*****************************************************************************
  111. * SynthProperties[]
  112. *****************************************************************************
  113. * Array of properties supported.
  114. */
  115. static const
  116. PCPROPERTY_ITEM
  117. SynthProperties[] =
  118. {
  119. ///////////////////////////////////////////////////////////////////
  120. // Support items
  121. {
  122. &GUID_DMUS_PROP_GM_Hardware,
  123. 0,
  124. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  125. PropertyHandler_Support
  126. },
  127. {
  128. &GUID_DMUS_PROP_GS_Hardware,
  129. 0,
  130. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  131. PropertyHandler_Support
  132. },
  133. {
  134. &GUID_DMUS_PROP_XG_Hardware,
  135. 0,
  136. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  137. PropertyHandler_Support
  138. },
  139. {
  140. &GUID_DMUS_PROP_XG_Capable,
  141. 0,
  142. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  143. PropertyHandler_Support
  144. },
  145. {
  146. &GUID_DMUS_PROP_GS_Capable,
  147. 0,
  148. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  149. PropertyHandler_Support
  150. },
  151. {
  152. &GUID_DMUS_PROP_DLS1,
  153. 0,
  154. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  155. PropertyHandler_Support
  156. },
  157. {
  158. &GUID_DMUS_PROP_Effects,
  159. 0,
  160. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  161. PropertyHandler_Effects
  162. },
  163. ///////////////////////////////////////////////////////////////////
  164. // Configuration items
  165. // Global: Synth caps
  166. {
  167. &KSPROPSETID_Synth,
  168. KSPROPERTY_SYNTH_CAPS,
  169. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  170. PropertyHandler_SynthCaps
  171. },
  172. // Per Stream: Synth port parameters
  173. {
  174. &KSPROPSETID_Synth,
  175. KSPROPERTY_SYNTH_PORTPARAMETERS,
  176. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  177. PropertyHandler_Synth
  178. },
  179. // Per Stream: Volume
  180. {
  181. &KSPROPSETID_Synth,
  182. KSPROPERTY_SYNTH_VOLUME,
  183. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  184. PropertyHandler_Synth
  185. },
  186. // Per Stream: Volume boost value
  187. {
  188. &KSPROPSETID_Synth,
  189. KSPROPERTY_SYNTH_VOLUMEBOOST,
  190. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  191. PropertyHandler_Synth
  192. },
  193. // Per Stream: Channel groups
  194. {
  195. &KSPROPSETID_Synth,
  196. KSPROPERTY_SYNTH_CHANNELGROUPS,
  197. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  198. PropertyHandler_Synth
  199. },
  200. // Per stream: Voice priority
  201. {
  202. &KSPROPSETID_Synth,
  203. KSPROPERTY_SYNTH_VOICEPRIORITY,
  204. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  205. PropertyHandler_Synth
  206. },
  207. // Per Stream: Running Stats
  208. {
  209. &KSPROPSETID_Synth,
  210. KSPROPERTY_SYNTH_RUNNINGSTATS,
  211. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  212. PropertyHandler_Synth
  213. },
  214. ///////////////////////////////////////////////////////////////////
  215. // Clock items
  216. // Per stream: Get current latency time
  217. {
  218. &KSPROPSETID_Synth,
  219. KSPROPERTY_SYNTH_LATENCYCLOCK,
  220. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  221. PropertyHandler_Synth
  222. },
  223. ///////////////////////////////////////////////////////////////////
  224. // DLS items
  225. // Per stream: Download DLS sample
  226. {
  227. &KSPROPSETID_Synth_Dls,
  228. KSPROPERTY_SYNTH_DLS_DOWNLOAD,
  229. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  230. PropertyHandler_SynthDls
  231. },
  232. // Per stream: Unload DLS sample
  233. {
  234. &KSPROPSETID_Synth_Dls,
  235. KSPROPERTY_SYNTH_DLS_UNLOAD,
  236. KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
  237. PropertyHandler_SynthDls
  238. },
  239. // Per stream: append
  240. {
  241. &KSPROPSETID_Synth_Dls,
  242. KSPROPERTY_SYNTH_DLS_APPEND,
  243. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  244. PropertyHandler_SynthDls
  245. },
  246. // Per stream: format
  247. {
  248. &KSPROPSETID_Synth_Dls,
  249. KSPROPERTY_SYNTH_DLS_WAVEFORMAT,
  250. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
  251. PropertyHandler_SynthDls
  252. }
  253. };
  254. DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties);
  255. /*****************************************************************************
  256. * MiniportPins[]
  257. *****************************************************************************
  258. * List of pins. Do not expose a wave pin if you are writing a driver for a
  259. * hardware device that does not inject wave data back into the system.
  260. */
  261. static const
  262. PCPIN_DESCRIPTOR
  263. MiniportPins[] =
  264. {
  265. {
  266. 1,1,1, // InstanceCount
  267. NULL,
  268. { // KsPinDescriptor
  269. 0, // InterfacesCount
  270. NULL, // Interfaces
  271. 0, // MediumsCount
  272. NULL, // Mediums
  273. SIZEOF_ARRAY(PinDataRangePointersStream), // DataRangesCount
  274. PinDataRangePointersStream, // DataRanges
  275. KSPIN_DATAFLOW_IN, // DataFlow
  276. KSPIN_COMMUNICATION_SINK, // Communication
  277. &KSCATEGORY_WDMAUD_USE_PIN_NAME, // Category
  278. &KSNODETYPE_DMDDKSYNTH, // Name
  279. 0 // Reserved
  280. }
  281. },
  282. {
  283. 1,1,1, // InstanceCount
  284. NULL, // AutomationTable
  285. { // KsPinDescriptor
  286. 0, // InterfacesCount
  287. NULL, // Interfaces
  288. 0, // MediumsCount
  289. NULL, // Mediums
  290. SIZEOF_ARRAY(PinDataRangePointersAudio), // DataRangesCount
  291. PinDataRangePointersAudio, // DataRanges
  292. KSPIN_DATAFLOW_OUT, // DataFlow
  293. KSPIN_COMMUNICATION_SOURCE, // Communication
  294. &KSCATEGORY_AUDIO, // Category
  295. NULL, // Name
  296. 0 // Reserved
  297. }
  298. }
  299. };
  300. /*****************************************************************************
  301. * MiniportNodes[]
  302. *****************************************************************************
  303. * List of nodes
  304. */
  305. static const
  306. PCNODE_DESCRIPTOR
  307. MiniportNodes[] =
  308. {
  309. { 0, &AutomationSynth, &KSNODETYPE_SYNTHESIZER, &KSNODETYPE_DMSYNTH}
  310. };
  311. /*****************************************************************************
  312. * MiniportConnections[]
  313. *****************************************************************************
  314. * List of connections.
  315. */
  316. static const
  317. PCCONNECTION_DESCRIPTOR
  318. MiniportConnections[] =
  319. {
  320. // From node From pin To node To pin
  321. //
  322. { PCFILTER_NODE, 0, 0, 1}, // Stream in to synth.
  323. { 0, 0, PCFILTER_NODE, 1} // Synth to audio out
  324. };
  325. /*****************************************************************************
  326. * TopologyCategories[]
  327. *****************************************************************************
  328. * List of categories. If your driver runs a hardware device that performs
  329. * actual audio output (i.e. contains a DAC) and does not register a physical
  330. * connection to a topology miniport, then you can use KSCATEGORY_RENDER instead
  331. * of KSCATEGORY_DATATRANSFORM.
  332. *
  333. * Note that if you use CATEGORY_RENDER instead of CATEGORY_DATATRANSFORM,
  334. * you must list _AUDIO category before _RENDER, so that SysAudio and DMusic.DLL
  335. * will agree upon what to label your device (DMusic currently expects _AUDIO).
  336. *
  337. */
  338. static const
  339. GUID TopologyCategories[] =
  340. {
  341. STATICGUIDOF(KSCATEGORY_DATATRANSFORM),
  342. STATICGUIDOF(KSCATEGORY_AUDIO),
  343. STATICGUIDOF(KSCATEGORY_SYNTHESIZER)
  344. };
  345. /*****************************************************************************
  346. * MiniportFilterDescriptor
  347. *****************************************************************************
  348. * Complete miniport description.
  349. */
  350. static const
  351. PCFILTER_DESCRIPTOR
  352. MiniportFilterDescriptor =
  353. {
  354. 0, // Version
  355. NULL, // AutomationTable
  356. sizeof(PCPIN_DESCRIPTOR), // PinSize
  357. SIZEOF_ARRAY(MiniportPins), // PinCount
  358. MiniportPins, // Pins
  359. sizeof(PCNODE_DESCRIPTOR), // NodeSize
  360. SIZEOF_ARRAY(MiniportNodes), // NodeCount
  361. MiniportNodes, // Nodes
  362. SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
  363. MiniportConnections, // Connections
  364. SIZEOF_ARRAY(TopologyCategories), // CategoryCount
  365. TopologyCategories, // Categories
  366. };
  367. #pragma code_seg()
  368. /*****************************************************************************
  369. * MapHRESULT()
  370. *****************************************************************************
  371. * Maps DMusic HRESULT to NTSTATUS
  372. */
  373. NTSTATUS MapHRESULT(IN HRESULT hr)
  374. {
  375. PAGED_CODE();
  376. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  377. // NYI: map hr to ntStatus
  378. return ntStatus;
  379. }
  380. /*****************************************************************************
  381. * CreateMiniportDmSynth()
  382. *****************************************************************************
  383. * Creates a DMus_Synth miniport driver for the adapter.
  384. * This uses a macro from STDUNK.H to do all the work.
  385. */
  386. NTSTATUS CreateMiniportDmSynth
  387. #ifdef USE_OBSOLETE_FUNCS
  388. (
  389. OUT PUNKNOWN * Unknown,
  390. IN PUNKNOWN UnknownOuter OPTIONAL,
  391. IN POOL_TYPE PoolType
  392. )
  393. #else
  394. (
  395. OUT PUNKNOWN * Unknown,
  396. IN PUNKNOWN UnknownOuter OPTIONAL,
  397. IN POOL_TYPE PoolType,
  398. IN PDEVICE_OBJECT pDeviceObject
  399. )
  400. #endif
  401. {
  402. PAGED_CODE();
  403. _DbgPrintF(DEBUGLVL_VERBOSE, ("CreateMiniportDmSynth"));
  404. ASSERT(Unknown);
  405. #ifdef USE_OBSOLETE_FUNCS
  406. STD_CREATE_BODY_WITH_TAG(CMiniportDmSynth, Unknown, UnknownOuter, PoolType,'pMmD'); // DmMp
  407. #else
  408. NTSTATUS ntStatus;
  409. CMiniportDmSynth *p = new(PoolType, 'pMmD') CMiniportDmSynth(UnknownOuter);
  410. if(p != NULL)
  411. {
  412. // the following line is the only difference between this code and
  413. // STD_CREATE_BODY_WITH_TAG and is necessary to handle passing the
  414. // DeviceObject pointer down without changing PortCls.
  415. p->m_pDeviceObject = pDeviceObject;
  416. *Unknown = reinterpret_cast<PUNKNOWN>(p);
  417. (*Unknown)->AddRef();
  418. ntStatus = STATUS_SUCCESS;
  419. }
  420. else
  421. {
  422. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  423. }
  424. return ntStatus;
  425. #endif
  426. }
  427. /*****************************************************************************
  428. * CMiniportDmSynth::NonDelegatingQueryInterface()
  429. *****************************************************************************
  430. * Obtains an interface. This method works just like a COM QueryInterface
  431. * call and is used if the object is not being aggregated.
  432. */
  433. STDMETHODIMP
  434. CMiniportDmSynth::NonDelegatingQueryInterface(IN REFIID Interface,
  435. OUT PVOID * Object)
  436. {
  437. PAGED_CODE();
  438. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::NonDelegatingQueryInterface"));
  439. ASSERT(Object);
  440. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  441. {
  442. *Object = PVOID(PUNKNOWN(this));
  443. }
  444. else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
  445. {
  446. *Object = PVOID(PMINIPORT(this));
  447. }
  448. else if (IsEqualGUIDAligned(Interface, IID_IMiniportDMus))
  449. {
  450. *Object = PVOID(PMINIPORTDMUS(this));
  451. }
  452. else
  453. {
  454. *Object = NULL;
  455. }
  456. if (*Object)
  457. {
  458. PUNKNOWN(*Object)->AddRef();
  459. return STATUS_SUCCESS;
  460. }
  461. return STATUS_INVALID_PARAMETER;
  462. }
  463. /*****************************************************************************
  464. * CMiniportDmSynth::~CMiniportDmSynth()
  465. *****************************************************************************
  466. * Destructor for miniport object. Let go of the port reference.
  467. */
  468. CMiniportDmSynth::~CMiniportDmSynth()
  469. {
  470. PAGED_CODE();
  471. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::~CMiniportDmSynth"));
  472. if (m_pPort)
  473. {
  474. m_pPort->Release();
  475. m_pPort = NULL;
  476. }
  477. DeleteCriticalSection(&m_CriticalSection);
  478. }
  479. /*****************************************************************************
  480. * CMiniportDmSynth::GetDescription()
  481. *****************************************************************************
  482. * Gets the topology for this miniport.
  483. */
  484. STDMETHODIMP
  485. CMiniportDmSynth::GetDescription(OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor)
  486. {
  487. PAGED_CODE();
  488. ASSERT(OutFilterDescriptor);
  489. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::GetDescription"));
  490. *OutFilterDescriptor = PPCFILTER_DESCRIPTOR(&MiniportFilterDescriptor);
  491. return STATUS_SUCCESS;
  492. }
  493. /*****************************************************************************
  494. * CMiniportDmSynth::DataRangeIntersection()
  495. *****************************************************************************
  496. * No data range for this miniport.
  497. */
  498. STDMETHODIMP
  499. CMiniportDmSynth::DataRangeIntersection(IN ULONG PinId,
  500. IN PKSDATARANGE DataRange,
  501. IN PKSDATARANGE MatchingDataRange,
  502. IN ULONG OutputBufferLength,
  503. OUT PVOID ResultantFormat OPTIONAL,
  504. OUT PULONG ResultantFormatLength)
  505. {
  506. PAGED_CODE();
  507. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::DataRangeIntersection"));
  508. return STATUS_NOT_IMPLEMENTED;
  509. }
  510. /*****************************************************************************
  511. * CMiniportDmSynth::Init()
  512. *****************************************************************************
  513. * Initializes the miniport.
  514. */
  515. STDMETHODIMP
  516. CMiniportDmSynth::Init
  517. (
  518. IN PUNKNOWN Unknown OPTIONAL,
  519. IN PRESOURCELIST ResourceList,
  520. IN PPORTDMUS Port,
  521. OUT PSERVICEGROUP* ServiceGroup
  522. )
  523. {
  524. PAGED_CODE();
  525. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::Init"));
  526. ASSERT(ResourceList);
  527. ASSERT(Port);
  528. ASSERT(ServiceGroup);
  529. m_pPort = Port;
  530. m_pPort->AddRef();
  531. *ServiceGroup = NULL;
  532. InitializeCriticalSection(&m_CriticalSection);
  533. return STATUS_SUCCESS;
  534. }
  535. /*****************************************************************************
  536. * CMiniportDmSynth::Service()
  537. *****************************************************************************
  538. * Not used.
  539. */
  540. STDMETHODIMP_(void)
  541. CMiniportDmSynth::Service()
  542. {
  543. }
  544. /*****************************************************************************
  545. * CMiniportDmSynth::NewStream()
  546. *****************************************************************************
  547. * Create a new stream. SchedulePreFetch tells the sequencer how far in
  548. * advance to deliver events. Allocator and master clock are required.
  549. */
  550. STDMETHODIMP
  551. CMiniportDmSynth::NewStream
  552. (
  553. OUT PMXF * MXF,
  554. IN PUNKNOWN OuterUnknown OPTIONAL,
  555. IN POOL_TYPE PoolType,
  556. IN ULONG PinID,
  557. IN DMUS_STREAM_TYPE StreamType,
  558. IN PKSDATAFORMAT DataFormat,
  559. OUT PSERVICEGROUP * ServiceGroup,
  560. IN PAllocatorMXF AllocatorMXF,
  561. IN PMASTERCLOCK MasterClock,
  562. OUT PULONGLONG SchedulePreFetch
  563. )
  564. {
  565. PAGED_CODE();
  566. _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportDmSynth::NewStream"));
  567. NTSTATUS ntStatus = STATUS_SUCCESS;
  568. *MXF = NULL;
  569. *ServiceGroup = NULL;
  570. *SchedulePreFetch = DONT_HOLD_FOR_SEQUENCING;
  571. if ((StreamType != DMUS_STREAM_WAVE_SINK) && (StreamType != DMUS_STREAM_MIDI_RENDER) )
  572. {
  573. _DbgPrintF(DEBUGLVL_TERSE, ("CMiniportDmSynth::NewStream stream type not supported"));
  574. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  575. }
  576. else
  577. {
  578. EnterCriticalSection(&m_CriticalSection);
  579. for (CDmSynthStream* pStreamItem = (CDmSynthStream*)m_StreamList.GetHead();
  580. pStreamItem;
  581. pStreamItem = (CDmSynthStream*)pStreamItem->GetNext())
  582. {
  583. if ( (StreamType == DMUS_STREAM_WAVE_SINK && !pStreamItem->m_fWaveOutCreated)
  584. || (StreamType == DMUS_STREAM_MIDI_RENDER && !pStreamItem->m_fMidiInCreated) )
  585. {
  586. if (StreamType == DMUS_STREAM_MIDI_RENDER)
  587. {
  588. ntStatus = pStreamItem->InitMidiIn(AllocatorMXF, MasterClock);
  589. }
  590. else // DMUS_STREAM_WAVE_SINK
  591. {
  592. ntStatus = pStreamItem->InitWaveOut(DataFormat);
  593. }
  594. if (NT_SUCCESS(ntStatus))
  595. {
  596. pStreamItem->AddRef();
  597. *MXF = PMXF(pStreamItem);
  598. }
  599. break;
  600. }
  601. }
  602. if (!*MXF)
  603. {
  604. CDmSynthStream* pNewStream = new(PoolType,'sSmD') CDmSynthStream(OuterUnknown); // DmSs
  605. if (pNewStream)
  606. {
  607. #ifdef USE_OBSOLETE_FUNCS
  608. ntStatus = pNewStream->Init(this);
  609. #else
  610. ntStatus = pNewStream->Init(this, m_pDeviceObject);
  611. #endif
  612. if (NT_SUCCESS(ntStatus))
  613. {
  614. if (StreamType == DMUS_STREAM_MIDI_RENDER)
  615. {
  616. ntStatus = pNewStream->InitMidiIn(AllocatorMXF, MasterClock);
  617. }
  618. else // DMUS_STREAM_WAVE_SINK
  619. {
  620. ntStatus = pNewStream->InitWaveOut(DataFormat);
  621. }
  622. }
  623. if (NT_SUCCESS(ntStatus))
  624. {
  625. m_StreamList.AddTail(pNewStream);
  626. pNewStream->AddRef();
  627. *MXF = PMXF(pNewStream);
  628. }
  629. else
  630. {
  631. pNewStream->Release();
  632. pNewStream = NULL;
  633. }
  634. }
  635. else
  636. {
  637. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  638. }
  639. }
  640. LeaveCriticalSection(&m_CriticalSection);
  641. }
  642. return ntStatus;
  643. }
  644. /*****************************************************************************
  645. *****************************************************************************
  646. * CDmSynthStream implementation
  647. *****************************************************************************
  648. *****************************************************************************/
  649. /*****************************************************************************
  650. * CDmSynthStream::~CDmSynthStream()
  651. *****************************************************************************
  652. * Destructor for miniport stream (MXF). Remove the download objects, clock,
  653. * allocator, miniport, synth, etc.
  654. *
  655. * All instruments and waves downloaded to
  656. * the synth are released (though a well behaved
  657. * client should have unloaded them prior to now).
  658. */
  659. CDmSynthStream::~CDmSynthStream()
  660. {
  661. PAGED_CODE();
  662. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::~CDmSynthStream"));
  663. if (m_pMasterClock)
  664. {
  665. m_pMasterClock->Release();
  666. m_pMasterClock = NULL;
  667. }
  668. if (m_pAllocator)
  669. {
  670. m_pAllocator->Release();
  671. m_pAllocator = NULL;
  672. }
  673. #ifndef USE_OBSOLETE_FUNCS
  674. if(m_pEventListWorkItem != NULL)
  675. {
  676. IoFreeWorkItem(m_pEventListWorkItem);
  677. }
  678. #endif
  679. if (m_pMiniport)
  680. {
  681. EnterCriticalSection(&m_pMiniport->m_CriticalSection);
  682. for (CDmSynthStream* pStreamItem = (CDmSynthStream*)m_pMiniport->m_StreamList.GetHead();
  683. pStreamItem;
  684. pStreamItem = (CDmSynthStream*)pStreamItem->GetNext())
  685. {
  686. if (pStreamItem == this)
  687. {
  688. m_pMiniport->m_StreamList.Remove(pStreamItem);
  689. break;
  690. }
  691. }
  692. LeaveCriticalSection(&m_pMiniport->m_CriticalSection);
  693. m_pMiniport->Release();
  694. }
  695. if (m_pSynth)
  696. {
  697. delete m_pSynth;
  698. }
  699. }
  700. /*****************************************************************************
  701. * CDmSynthStream::Init()
  702. *****************************************************************************
  703. * Initialize the miniport stream (MXF). Create a synth.
  704. */
  705. NTSTATUS
  706. CDmSynthStream::Init
  707. #ifdef USE_OBSOLETE_FUNCS
  708. (
  709. CMiniportDmSynth * Miniport
  710. )
  711. #else
  712. (
  713. CMiniportDmSynth * Miniport,
  714. PDEVICE_OBJECT pDeviceObject
  715. )
  716. #endif
  717. {
  718. PAGED_CODE();
  719. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::Init"));
  720. if (!Miniport)
  721. {
  722. return STATUS_INVALID_PARAMETER;
  723. }
  724. m_pSynth = new(NonPagedPool,'SSmD') CSynth; // DmSS
  725. if (m_pSynth == NULL)
  726. {
  727. return STATUS_INSUFFICIENT_RESOURCES;
  728. }
  729. // Initialize Synth with default settings.
  730. //
  731. if (FAILED(m_pSynth->Open(DEFAULT_CHANNEL_GROUPS, DEFAULT_VOICES)))
  732. {
  733. delete m_pSynth;
  734. m_pSynth = NULL;
  735. return STATUS_INSUFFICIENT_RESOURCES;
  736. }
  737. m_PortParams.ChannelGroups = DEFAULT_CHANNEL_GROUPS;
  738. m_PortParams.Voices = DEFAULT_VOICES;
  739. m_PortParams.EffectsFlags = 0;
  740. m_pMiniport = Miniport;
  741. m_pMiniport->AddRef();
  742. m_fWaveOutCreated = FALSE;
  743. m_fMidiInCreated = FALSE;
  744. m_State = KSSTATE_STOP;
  745. m_EventList = NULL;
  746. KeInitializeSpinLock(&m_EventListLock);
  747. #ifdef USE_OBSOLETE_FUNCS
  748. ExInitializeWorkItem(&m_EventListWorkItem,
  749. (PWORKER_THREAD_ROUTINE)PutMessageWorker,
  750. (PVOID)this);
  751. #else
  752. m_pEventListWorkItem = IoAllocateWorkItem(pDeviceObject);
  753. if(m_pEventListWorkItem == NULL)
  754. {
  755. return STATUS_INSUFFICIENT_RESOURCES;
  756. }
  757. #endif
  758. return STATUS_SUCCESS;
  759. }
  760. /*****************************************************************************
  761. * CDmSynthStream::InitMidiIn()
  762. *****************************************************************************
  763. * Initialize the MIDI input side. Allocator and master clock are required.
  764. */
  765. NTSTATUS
  766. CDmSynthStream::InitMidiIn
  767. (
  768. IN PAllocatorMXF AllocatorMXF,
  769. IN PMASTERCLOCK MasterClock
  770. )
  771. {
  772. PAGED_CODE();
  773. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::Init"));
  774. if (!AllocatorMXF || !MasterClock)
  775. {
  776. return STATUS_INVALID_PARAMETER;
  777. }
  778. m_pAllocator = AllocatorMXF;
  779. m_pAllocator->AddRef();
  780. // NOTE: master clock is set on midi pin, not wave pin
  781. m_pMasterClock = MasterClock;
  782. m_pMasterClock->AddRef();
  783. m_fMidiInCreated = TRUE;
  784. return STATUS_SUCCESS;
  785. }
  786. /*****************************************************************************
  787. * CDmSynthStream::InitWaveOut()
  788. *****************************************************************************
  789. * Initialize the wave output side.
  790. */
  791. NTSTATUS
  792. CDmSynthStream::InitWaveOut
  793. (
  794. IN PKSDATAFORMAT DataFormat
  795. )
  796. {
  797. PAGED_CODE();
  798. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::Init"));
  799. if (!DataFormat)
  800. {
  801. return STATUS_INVALID_PARAMETER;
  802. }
  803. RtlZeroMemory(&m_PortParams, sizeof(m_PortParams));
  804. m_PortParams.SampleRate = PKSDATAFORMAT_WAVEFORMATEX(DataFormat)->WaveFormatEx.nSamplesPerSec;
  805. m_PortParams.AudioChannels = PKSDATAFORMAT_WAVEFORMATEX(DataFormat)->WaveFormatEx.nChannels;
  806. m_lVolume = 0;
  807. m_lBoost = 6 * 100;
  808. m_fWaveOutCreated = TRUE;
  809. return STATUS_SUCCESS;
  810. }
  811. /*****************************************************************************
  812. * CDmSynthStream::NonDelegatingQueryInterface()
  813. *****************************************************************************
  814. * Obtains an interface. This method works just like a COM QueryInterface
  815. * call and is used if the object is not being aggregated.
  816. */
  817. STDMETHODIMP
  818. CDmSynthStream::NonDelegatingQueryInterface
  819. (
  820. IN REFIID Interface,
  821. OUT PVOID* Object
  822. )
  823. {
  824. PAGED_CODE();
  825. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::NonDelegatingQueryInterface"));
  826. ASSERT(Object);
  827. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  828. {
  829. *Object = PVOID(PUNKNOWN(this));
  830. }
  831. else if (IsEqualGUIDAligned(Interface, IID_IMXF))
  832. {
  833. *Object = PVOID(PMXF(this));
  834. }
  835. else if (IsEqualGUIDAligned(Interface, IID_ISynthSinkDMus))
  836. {
  837. *Object = PVOID(PSYNTHSINKDMUS(this));
  838. }
  839. else
  840. {
  841. *Object = NULL;
  842. }
  843. if (*Object)
  844. {
  845. //
  846. // We reference the interface for the caller.
  847. //
  848. PUNKNOWN(*Object)->AddRef();
  849. return STATUS_SUCCESS;
  850. }
  851. return STATUS_INVALID_PARAMETER;
  852. }
  853. /*****************************************************************************
  854. * CDmSynthStream::SetState()
  855. *****************************************************************************
  856. * Set the state of the stream (RUN/PAUSE/ACQUIRE/STOP) and act accordingly.
  857. * Activate the synth if we are running.
  858. */
  859. STDMETHODIMP
  860. CDmSynthStream::SetState
  861. (
  862. IN KSSTATE NewState
  863. )
  864. {
  865. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::SetState: %d", NewState));
  866. NTSTATUS ntStatus = STATUS_SUCCESS;
  867. m_llStartPosition = 0;
  868. m_llLastPosition = 0;
  869. switch (NewState)
  870. {
  871. case KSSTATE_RUN:
  872. {
  873. if (m_PortParams.SampleRate && m_PortParams.AudioChannels)
  874. {
  875. if (NT_SUCCESS(ntStatus))
  876. {
  877. HRESULT hr = m_pSynth->Activate(m_PortParams.SampleRate,
  878. m_PortParams.AudioChannels);
  879. if (FAILED(hr))
  880. {
  881. ntStatus = MapHRESULT(hr);
  882. }
  883. }
  884. }
  885. else
  886. {
  887. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::SetState invalid port params"));
  888. ntStatus = STATUS_UNSUCCESSFUL;
  889. }
  890. break;
  891. }
  892. case KSSTATE_ACQUIRE:
  893. case KSSTATE_STOP:
  894. case KSSTATE_PAUSE:
  895. {
  896. HRESULT hr = m_pSynth->Deactivate();
  897. if (FAILED(hr))
  898. {
  899. ntStatus = MapHRESULT(hr);
  900. }
  901. break;
  902. }
  903. }
  904. m_State = NewState;
  905. return ntStatus;
  906. }
  907. /*****************************************************************************
  908. * CDmSynthStream::ConnectOutput()
  909. *****************************************************************************
  910. * MXF base function. This MXF does not feed another, so it is not implemented.
  911. */
  912. STDMETHODIMP
  913. CDmSynthStream::ConnectOutput(PMXF ConnectionPoint)
  914. {
  915. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::ConnectOutput"));
  916. return STATUS_SUCCESS; // do nothing
  917. }
  918. /*****************************************************************************
  919. * CDmSynthStream::DisconnectOutput()
  920. *****************************************************************************
  921. * MXF base function. This MXF does not feed another, so it is not implemented.
  922. */
  923. STDMETHODIMP
  924. CDmSynthStream::DisconnectOutput(PMXF ConnectionPoint)
  925. {
  926. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::DisconnectOutput"));
  927. return STATUS_SUCCESS; // do nothing
  928. }
  929. /*****************************************************************************
  930. * PutMessageWorker()
  931. *****************************************************************************
  932. * C function that thunks over to the stream's member function.
  933. */
  934. #ifdef USE_OBSOLETE_FUNCS
  935. VOID PutMessageWorker(PVOID Param)
  936. #else
  937. VOID PutMessageWorker(PDEVICE_OBJECT pDeviceObject, PVOID Param)
  938. #endif
  939. {
  940. CDmSynthStream *pCDmSynthStream = (CDmSynthStream *)Param;
  941. pCDmSynthStream->PutMessageInternal();
  942. }
  943. /*****************************************************************************
  944. * CDmSynthStream::PutMessageInternal()
  945. *****************************************************************************
  946. * Can be called at PASSIVE_LEVEL. Receive MIDI events and queue them.
  947. */
  948. void CDmSynthStream::PutMessageInternal(void)
  949. {
  950. KIRQL oldIrql;
  951. PDMUS_KERNEL_EVENT pEvent,pDMKEvt;
  952. NTSTATUS ntStatus;
  953. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::PutMessageInternal"));
  954. // Grab everything on the list
  955. KeAcquireSpinLock(&m_EventListLock,&oldIrql);
  956. pEvent=m_EventList;
  957. m_EventList=NULL;
  958. KeReleaseSpinLock(&m_EventListLock,oldIrql);
  959. pDMKEvt=pEvent;
  960. while (pDMKEvt)
  961. {
  962. if (!(PACKAGE_EVT(pDMKEvt)))
  963. {
  964. PBYTE pData;
  965. if (pDMKEvt->cbEvent <= sizeof(PBYTE))
  966. {
  967. pData = (PBYTE)&pDMKEvt->uData;
  968. }
  969. else
  970. {
  971. pData = (PBYTE)pDMKEvt->uData.pbData;
  972. }
  973. // This is just MIDI bytes
  974. HRESULT hr = m_pSynth->PlayBuffer(PSYNTHSINKDMUS(this),
  975. pDMKEvt->ullPresTime100ns,
  976. pData,
  977. pDMKEvt->cbEvent,
  978. (ULONG)pDMKEvt->usChannelGroup);
  979. if (FAILED(hr))
  980. {
  981. ntStatus = MapHRESULT(hr);
  982. }
  983. }
  984. else
  985. {
  986. PutMessage(pDMKEvt->uData.pPackageEvt);
  987. pDMKEvt->uData.pPackageEvt = NULL;
  988. }
  989. pDMKEvt = pDMKEvt->pNextEvt;
  990. }
  991. m_pAllocator->PutMessage(pEvent);
  992. }
  993. /*****************************************************************************
  994. * CDmSynthStream::PutMessage()
  995. *****************************************************************************
  996. * Must be called at DISPATH_LEVEL (e.g. from a DPC). We jam an event into
  997. * a queue and call a work item. If the queue already exists, we just append
  998. * (no need to call the work item).
  999. */
  1000. STDMETHODIMP
  1001. CDmSynthStream::PutMessage(IN PDMUS_KERNEL_EVENT pEvent)
  1002. {
  1003. BOOL bQueueWorkItem;
  1004. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::::PutMessage"));
  1005. // Queue up on event list
  1006. KeAcquireSpinLockAtDpcLevel(&m_EventListLock);
  1007. if (!m_EventList) // If nothing on event list
  1008. {
  1009. m_EventList = pEvent; // Link to head
  1010. bQueueWorkItem = TRUE; // Need to queue work item
  1011. }
  1012. else // Something already pending, queue up behind them
  1013. {
  1014. // Find last event in queue to link to
  1015. PDMUS_KERNEL_EVENT pEventTail = m_EventList;
  1016. while (pEventTail->pNextEvt)
  1017. {
  1018. pEventTail = pEventTail->pNextEvt;
  1019. }
  1020. pEventTail->pNextEvt = pEvent;
  1021. bQueueWorkItem = FALSE; // No need to queue new work item
  1022. }
  1023. KeReleaseSpinLockFromDpcLevel(&m_EventListLock);
  1024. // Queue up the work item after we release spinlock
  1025. if (bQueueWorkItem)
  1026. {
  1027. #ifdef USE_OBSOLETE_FUNCS
  1028. ExQueueWorkItem(&m_EventListWorkItem, CriticalWorkQueue);
  1029. #else
  1030. IoQueueWorkItem(m_pEventListWorkItem, PutMessageWorker,
  1031. CriticalWorkQueue, (PVOID)this);
  1032. #endif
  1033. }
  1034. return STATUS_SUCCESS;
  1035. }
  1036. /*****************************************************************************
  1037. * CDmSynthStream::HandlePropertySupport()
  1038. *****************************************************************************
  1039. * Handle the support property.
  1040. */
  1041. NTSTATUS
  1042. CDmSynthStream::HandlePropertySupport(IN PPCPROPERTY_REQUEST pRequest)
  1043. {
  1044. PAGED_CODE();
  1045. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandlePropertySupport"));
  1046. NTSTATUS ntStatus;
  1047. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1048. {
  1049. ntStatus = DefaultBasicPropertyHandler(pRequest,
  1050. KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET);
  1051. }
  1052. else
  1053. {
  1054. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONG), KSPROPERTY_TYPE_SET);
  1055. if (NT_SUCCESS(ntStatus))
  1056. {
  1057. if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_GM_Hardware))
  1058. {
  1059. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_GM_Hardware"));
  1060. *(PULONG)(pRequest->Value) = FALSE;
  1061. }
  1062. else if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_GS_Hardware))
  1063. {
  1064. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_GS_Hardware"));
  1065. *(PULONG)(pRequest->Value) = FALSE;
  1066. }
  1067. else if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_XG_Hardware))
  1068. {
  1069. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_XG_Hardware"));
  1070. *(PULONG)(pRequest->Value) = FALSE;
  1071. }
  1072. else if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_XG_Capable))
  1073. {
  1074. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_XG_Capable"));
  1075. *(PULONG)(pRequest->Value) = TRUE;
  1076. }
  1077. else if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_GS_Capable))
  1078. {
  1079. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_GS_Capable"));
  1080. *(PULONG)(pRequest->Value) = TRUE;
  1081. }
  1082. else if (IsEqualGUIDAligned(*pRequest->PropertyItem->Set, GUID_DMUS_PROP_DLS1))
  1083. {
  1084. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySupport GUID_DMUS_PROP_DLS1"));
  1085. *(PULONG)(pRequest->Value) = TRUE;
  1086. }
  1087. else
  1088. {
  1089. _DbgPrintF(DEBUGLVL_TERSE,("CDmSynthStream::HandlePropertySupport unrecognized set ID"));
  1090. ntStatus = STATUS_UNSUCCESSFUL;
  1091. pRequest->ValueSize = 0;
  1092. }
  1093. }
  1094. if (NT_SUCCESS(ntStatus))
  1095. {
  1096. pRequest->ValueSize = sizeof(ULONG);
  1097. }
  1098. }
  1099. return ntStatus;
  1100. }
  1101. /*****************************************************************************
  1102. * CDmSynthStream::HandlePropertyEffects()
  1103. *****************************************************************************
  1104. * Handle the effects property.
  1105. */
  1106. NTSTATUS
  1107. CDmSynthStream::HandlePropertyEffects(IN PPCPROPERTY_REQUEST pRequest)
  1108. {
  1109. PAGED_CODE();
  1110. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandlePropertyEffects"));
  1111. NTSTATUS ntStatus;
  1112. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1113. {
  1114. ntStatus = DefaultBasicPropertyHandler(pRequest,
  1115. KSPROPERTY_TYPE_BASICSUPPORT |
  1116. KSPROPERTY_TYPE_GET);
  1117. }
  1118. else
  1119. {
  1120. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONG), 0);
  1121. if (NT_SUCCESS(ntStatus))
  1122. {
  1123. if (pRequest->Verb & KSPROPERTY_TYPE_GET)
  1124. {
  1125. PULONG pulEffects = (PULONG)pRequest->Value;
  1126. pRequest->ValueSize = sizeof(ULONG);
  1127. *pulEffects = 0;
  1128. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream: Get effects flags %x", *pulEffects));
  1129. }
  1130. else
  1131. {
  1132. pRequest->ValueSize = 0;
  1133. ntStatus = STATUS_INVALID_PARAMETER;
  1134. }
  1135. }
  1136. }
  1137. return ntStatus;
  1138. }
  1139. /*****************************************************************************
  1140. * CDmSynthStream::HandlePortParams()
  1141. *****************************************************************************
  1142. * Handle the port parameters property.
  1143. * Fix up the port params to include defaults. Cache the params as well
  1144. * as passing the updated version back.
  1145. */
  1146. NTSTATUS
  1147. CDmSynthStream::HandlePortParams(IN PPCPROPERTY_REQUEST pRequest)
  1148. {
  1149. PAGED_CODE();
  1150. NTSTATUS ntStatus;
  1151. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::HandlePortParams"));
  1152. ntStatus = ValidatePropertyParams(pRequest, sizeof(SYNTH_PORTPARAMS), KSPROPERTY_TYPE_SET);
  1153. if (!NT_SUCCESS(ntStatus))
  1154. {
  1155. return ntStatus;
  1156. }
  1157. if (pRequest->InstanceSize < sizeof(SYNTH_PORTPARAMS))
  1158. {
  1159. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandlePortParams InstanceSize too small"));
  1160. pRequest->ValueSize = 0;
  1161. return STATUS_BUFFER_TOO_SMALL;
  1162. }
  1163. RtlCopyMemory(pRequest->Value, pRequest->Instance, sizeof(SYNTH_PORTPARAMS));
  1164. PSYNTH_PORTPARAMS Params = (PSYNTH_PORTPARAMS)pRequest->Value;
  1165. if (!(Params->ValidParams & SYNTH_PORTPARAMS_VOICES))
  1166. {
  1167. Params->Voices = DEFAULT_VOICES;
  1168. }
  1169. else if (Params->Voices > MAX_VOICES)
  1170. {
  1171. Params->Voices = MAX_VOICES;
  1172. }
  1173. else if (Params->Voices < 1)
  1174. {
  1175. Params->Voices = 1;
  1176. }
  1177. if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS))
  1178. {
  1179. Params->ChannelGroups = DEFAULT_CHANNEL_GROUPS;
  1180. }
  1181. else if (Params->ChannelGroups > MAX_CHANNEL_GROUPS)
  1182. {
  1183. Params->ChannelGroups = MAX_CHANNEL_GROUPS;
  1184. }
  1185. else if (Params->ChannelGroups < 1)
  1186. {
  1187. Params->ChannelGroups = 1;
  1188. }
  1189. // audio channels is fixed (chosen) by SysAudio
  1190. if (!(Params->ValidParams & SYNTH_PORTPARAMS_AUDIOCHANNELS))
  1191. {
  1192. Params->AudioChannels = m_PortParams.AudioChannels;
  1193. }
  1194. else if (Params->AudioChannels != m_PortParams.AudioChannels)
  1195. {
  1196. Params->AudioChannels = m_PortParams.AudioChannels;
  1197. }
  1198. // sample rate is fixed (chosen) by SysAudio
  1199. if (!(Params->ValidParams & SYNTH_PORTPARAMS_SAMPLERATE))
  1200. {
  1201. Params->SampleRate = m_PortParams.SampleRate;
  1202. }
  1203. else if (Params->SampleRate != m_PortParams.SampleRate)
  1204. {
  1205. Params->SampleRate = m_PortParams.SampleRate;
  1206. }
  1207. // set share. This cannot change.
  1208. Params->Share = m_PortParams.Share;
  1209. if (!(Params->ValidParams & SYNTH_PORTPARAMS_EFFECTS))
  1210. {
  1211. Params->EffectsFlags = SYNTH_EFFECT_NONE;
  1212. }
  1213. else
  1214. {
  1215. Params->EffectsFlags = SYNTH_EFFECT_NONE;
  1216. }
  1217. RtlCopyMemory(&m_PortParams, Params, sizeof(m_PortParams));
  1218. // Each channel groups is represented by a ControlLogic object
  1219. // (A channel groups is a set of sixteen MIDI channels)
  1220. HRESULT hr = m_pSynth->Open(m_PortParams.ChannelGroups,
  1221. m_PortParams.Voices
  1222. );
  1223. if (SUCCEEDED(hr))
  1224. {
  1225. m_pSynth->SetGainAdjust(m_lVolume + m_lBoost);
  1226. }
  1227. else
  1228. {
  1229. ntStatus = MapHRESULT(hr);
  1230. }
  1231. if (NT_SUCCESS(ntStatus))
  1232. {
  1233. pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS);
  1234. }
  1235. else
  1236. {
  1237. pRequest->ValueSize = 0;
  1238. }
  1239. return ntStatus;
  1240. }
  1241. /*****************************************************************************
  1242. * CDmSynthStream::HandleRunningStats()
  1243. *****************************************************************************
  1244. * Handle the property for running statistics.
  1245. */
  1246. NTSTATUS
  1247. CDmSynthStream::HandleRunningStats(IN PPCPROPERTY_REQUEST pRequest)
  1248. {
  1249. FLOATSAFE fs;
  1250. PAGED_CODE();
  1251. NTSTATUS ntStatus;
  1252. _DbgPrintF(DEBUGLVL_VERBOSE, ("CDmSynthStream::HandleRunningStats"));
  1253. ntStatus = ValidatePropertyParams(pRequest, sizeof(SYNTH_STATS), KSPROPERTY_TYPE_SET);
  1254. if (!NT_SUCCESS(ntStatus))
  1255. {
  1256. return ntStatus;
  1257. }
  1258. PSYNTH_STATS StatsOut = (PSYNTH_STATS)pRequest->Value;
  1259. PerfStats Stats;
  1260. m_pSynth->GetPerformanceStats(&Stats);
  1261. long lCPU = Stats.dwCPU;
  1262. if (Stats.dwVoices)
  1263. {
  1264. lCPU /= Stats.dwVoices;
  1265. }
  1266. else
  1267. {
  1268. lCPU = 0;
  1269. }
  1270. StatsOut->Voices = Stats.dwVoices;
  1271. StatsOut->CPUPerVoice = lCPU * 10;
  1272. StatsOut->TotalCPU = Stats.dwCPU * 10;
  1273. StatsOut->LostNotes = Stats.dwNotesLost;
  1274. long ldB = 6;
  1275. StatsOut->ValidStats =
  1276. SYNTH_STATS_VOICES |
  1277. SYNTH_STATS_TOTAL_CPU |
  1278. SYNTH_STATS_CPU_PER_VOICE |
  1279. SYNTH_STATS_LOST_NOTES;
  1280. double fLevel = Stats.dwMaxAmplitude;
  1281. if (Stats.dwMaxAmplitude < 1)
  1282. {
  1283. fLevel = -96.0;
  1284. }
  1285. else
  1286. {
  1287. fLevel /= 32768.0;
  1288. fLevel = log10(fLevel);
  1289. fLevel *= 20.0;
  1290. }
  1291. StatsOut->PeakVolume = (long) fLevel;
  1292. StatsOut->ValidStats |= SYNTH_STATS_PEAK_VOLUME;
  1293. pRequest->ValueSize = sizeof(SYNTH_STATS);
  1294. return ntStatus;
  1295. }
  1296. /*****************************************************************************
  1297. * CDmSynthStream::HandlePropertySynth()
  1298. *****************************************************************************
  1299. * Handle the synth property set.
  1300. */
  1301. NTSTATUS
  1302. CDmSynthStream::HandlePropertySynth(IN PPCPROPERTY_REQUEST pRequest)
  1303. {
  1304. PAGED_CODE();
  1305. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandlePropertySynth"));
  1306. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  1307. HRESULT hr;
  1308. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1309. {
  1310. ntStatus = DefaultSynthBasicPropertyHandler(pRequest);
  1311. }
  1312. else
  1313. {
  1314. switch (pRequest->PropertyItem->Id)
  1315. {
  1316. case KSPROPERTY_SYNTH_PORTPARAMETERS:
  1317. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_PORTPARAMETERS"));
  1318. ntStatus = HandlePortParams(pRequest);
  1319. break;
  1320. case KSPROPERTY_SYNTH_RUNNINGSTATS:
  1321. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_RUNNINGSTATS"));
  1322. ntStatus = HandleRunningStats(pRequest);
  1323. break;
  1324. case KSPROPERTY_SYNTH_VOLUME:
  1325. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_VOLUME"));
  1326. ntStatus = ValidatePropertyParams(pRequest, sizeof(m_lVolume), 0);
  1327. if (NT_SUCCESS(ntStatus))
  1328. {
  1329. if (pRequest->Verb & KSPROPERTY_TYPE_GET)
  1330. {
  1331. pRequest->ValueSize = sizeof(m_lVolume);
  1332. *(PLONG)pRequest->Value = m_lVolume;
  1333. }
  1334. else
  1335. {
  1336. m_lVolume = *(PLONG)pRequest->Value;
  1337. m_pSynth->SetGainAdjust(m_lVolume + m_lBoost);
  1338. }
  1339. }
  1340. break;
  1341. case KSPROPERTY_SYNTH_VOLUMEBOOST:
  1342. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_VOLUMEBOOST"));
  1343. ntStatus = ValidatePropertyParams(pRequest, sizeof(m_lBoost), 0);
  1344. if (NT_SUCCESS(ntStatus))
  1345. {
  1346. if (pRequest->Verb & KSPROPERTY_TYPE_GET)
  1347. {
  1348. pRequest->ValueSize = sizeof(m_lBoost);
  1349. *(PLONG)pRequest->Value = m_lBoost;
  1350. }
  1351. else
  1352. {
  1353. m_lBoost = *(PLONG)pRequest->Value;
  1354. m_pSynth->SetGainAdjust(m_lVolume + m_lBoost);
  1355. }
  1356. }
  1357. break;
  1358. case KSPROPERTY_SYNTH_CHANNELGROUPS:
  1359. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_CHANNELGROUPS"));
  1360. ntStatus = ValidatePropertyParams(pRequest, sizeof(m_PortParams.ChannelGroups), 0);
  1361. if (NT_SUCCESS(ntStatus))
  1362. {
  1363. if (pRequest->Verb & KSPROPERTY_TYPE_GET)
  1364. {
  1365. pRequest->ValueSize = sizeof(m_PortParams.ChannelGroups);
  1366. *(PULONG)pRequest->Value = m_PortParams.ChannelGroups;
  1367. }
  1368. else
  1369. {
  1370. hr = m_pSynth->SetNumChannelGroups(*(PULONG)pRequest->Value);
  1371. if (FAILED(hr))
  1372. {
  1373. ntStatus = MapHRESULT(hr);
  1374. }
  1375. else
  1376. {
  1377. m_PortParams.ChannelGroups = *(PULONG)pRequest->Value;
  1378. }
  1379. }
  1380. }
  1381. break;
  1382. case KSPROPERTY_SYNTH_VOICEPRIORITY:
  1383. _DbgPrintF(DEBUGLVL_VERBOSE,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_VOICEPRIORITY"));
  1384. ntStatus = ValidatePropertyParams(pRequest, sizeof(DWORD), 0);
  1385. if (NT_SUCCESS(ntStatus))
  1386. {
  1387. if (pRequest->InstanceSize < sizeof(SYNTHVOICEPRIORITY_INSTANCE))
  1388. {
  1389. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1390. pRequest->ValueSize = 0;
  1391. }
  1392. }
  1393. if (NT_SUCCESS(ntStatus))
  1394. {
  1395. if (pRequest->Verb & KSPROPERTY_TYPE_GET)
  1396. {
  1397. PSYNTHVOICEPRIORITY_INSTANCE pVoicePriority = (PSYNTHVOICEPRIORITY_INSTANCE)pRequest->Instance;
  1398. hr = m_pSynth->GetChannelPriority(pVoicePriority->ChannelGroup,
  1399. pVoicePriority->Channel,
  1400. (PULONG)pRequest->Value);
  1401. if (FAILED(hr))
  1402. {
  1403. pRequest->ValueSize = 0;
  1404. ntStatus = MapHRESULT(hr);
  1405. }
  1406. else
  1407. {
  1408. pRequest->ValueSize = sizeof(DWORD);
  1409. }
  1410. }
  1411. else
  1412. {
  1413. PSYNTHVOICEPRIORITY_INSTANCE pVoicePriority = (PSYNTHVOICEPRIORITY_INSTANCE)pRequest->Instance;
  1414. hr = m_pSynth->SetChannelPriority(pVoicePriority->ChannelGroup,
  1415. pVoicePriority->Channel,
  1416. *(PULONG)pRequest->Value);
  1417. if (FAILED(hr))
  1418. {
  1419. ntStatus = MapHRESULT(hr);
  1420. }
  1421. }
  1422. }
  1423. break;
  1424. case KSPROPERTY_SYNTH_LATENCYCLOCK:
  1425. // This returns the latency clock created by the output audio sink object,
  1426. // which handles the output audio stream.
  1427. // The latency clock returns the current render time whenever its
  1428. // IReferenceClock::GetTime method is called. This time is always relative
  1429. // to the time established by the master clock.
  1430. // The latency time is used by clients to identify the next available time
  1431. // to start playing a note.
  1432. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySynth KSPROPERTY_SYNTH_LATENCYCLOCK"));
  1433. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONGLONG), KSPROPERTY_TYPE_SET);
  1434. if (NT_SUCCESS(ntStatus))
  1435. {
  1436. REFERENCE_TIME rtLatency;
  1437. if (NT_SUCCESS(SampleToRefTime(m_llLastPosition, &rtLatency)))
  1438. {
  1439. if (m_pMasterClock)
  1440. {
  1441. REFERENCE_TIME rtMaster;
  1442. if (NT_SUCCESS(m_pMasterClock->GetTime(&rtMaster)))
  1443. {
  1444. #if DBG
  1445. static DWORD g_dwIn = 0;
  1446. #endif // DBG
  1447. if (rtLatency < rtMaster)
  1448. {
  1449. #if DBG
  1450. if (g_dwIn++ % 25 == 0)
  1451. {
  1452. _DbgPrintF(DEBUGLVL_VERBOSE,("Latency:%ld < Master:%ld",
  1453. long(rtLatency / 10000),
  1454. long(rtMaster / 10000)));
  1455. }
  1456. #endif // DBG
  1457. // REVIEW: rtLatency = rtMaster; // clamp it up
  1458. }
  1459. else if (rtLatency > rtMaster + 10000000)
  1460. {
  1461. #if DBG
  1462. if (g_dwIn++ % 25 == 0)
  1463. {
  1464. _DbgPrintF(DEBUGLVL_VERBOSE,("Latency:%ld > Master:%ld",
  1465. long(rtLatency / 10000),
  1466. long(rtMaster / 10000)));
  1467. }
  1468. #endif // DBG
  1469. // REVIEW: rtLatency = rtMaster + 10000000; // clamp it down
  1470. }
  1471. }
  1472. }
  1473. *((PULONGLONG)pRequest->Value) = rtLatency;
  1474. pRequest->ValueSize = sizeof(ULONGLONG);
  1475. }
  1476. else
  1477. {
  1478. ntStatus = STATUS_UNSUCCESSFUL;
  1479. }
  1480. }
  1481. break;
  1482. default:
  1483. _DbgPrintF(DEBUGLVL_TERSE,("CDmSynthStream::HandlePropertySynth unrecognized ID"));
  1484. ntStatus = STATUS_UNSUCCESSFUL;
  1485. break;
  1486. }
  1487. }
  1488. // We should return zero, if we fail.
  1489. //
  1490. if (STATUS_UNSUCCESSFUL == ntStatus || STATUS_INVALID_PARAMETER == ntStatus )
  1491. {
  1492. pRequest->ValueSize = 0;
  1493. }
  1494. return ntStatus;
  1495. }
  1496. /*****************************************************************************
  1497. * CDmSynthStream::HandleDownload()
  1498. *****************************************************************************
  1499. * Handle a download request. We carefully copy the data.
  1500. * Forward to the synth and add to our list.
  1501. */
  1502. NTSTATUS
  1503. CDmSynthStream::HandleDownload(IN PPCPROPERTY_REQUEST pRequest)
  1504. {
  1505. PAGED_CODE();
  1506. NTSTATUS ntStatus;
  1507. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandleDownload"));
  1508. ntStatus = ValidatePropertyParams(pRequest, sizeof(SYNTHDOWNLOAD), 0);
  1509. if (!NT_SUCCESS(ntStatus))
  1510. {
  1511. // We should return immediately. ValidatePropertyParams sets all
  1512. // error codes appropriately.
  1513. return ntStatus;
  1514. }
  1515. if (pRequest->InstanceSize < sizeof(SYNTH_BUFFER))
  1516. {
  1517. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload InstanceSize too small"));
  1518. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1519. }
  1520. if (pRequest->Instance == NULL)
  1521. {
  1522. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload Instance is NULL"));
  1523. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1524. }
  1525. if (pRequest->InstanceSize != sizeof(SYNTH_BUFFER) ||
  1526. pRequest->ValueSize != sizeof(SYNTHDOWNLOAD))
  1527. {
  1528. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload InstanceSize:%lu, ValueSize:%lu", pRequest->InstanceSize, pRequest->ValueSize));
  1529. }
  1530. PSYNTH_BUFFER pDlsBuffer;
  1531. if (NT_SUCCESS(ntStatus))
  1532. {
  1533. pDlsBuffer = (PSYNTH_BUFFER)pRequest->Instance;
  1534. if (!pDlsBuffer->BufferSize)
  1535. {
  1536. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload BufferSize is invalid"));
  1537. ntStatus = STATUS_UNSUCCESSFUL;
  1538. }
  1539. }
  1540. // lock and copy user data into paged pool
  1541. BOOL pagesLocked = FALSE;
  1542. PVOID pvData = NULL;
  1543. if (NT_SUCCESS(ntStatus))
  1544. {
  1545. PMDL pMdl = IoAllocateMdl(pDlsBuffer->BufferAddress, pDlsBuffer->BufferSize, FALSE, FALSE, NULL);
  1546. if (pMdl)
  1547. {
  1548. __try
  1549. {
  1550. MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
  1551. pagesLocked = TRUE;
  1552. PVOID pvUserData = KernHelpGetSysAddrForMdl(pMdl);
  1553. pvData = (PVOID)new BYTE[pDlsBuffer->BufferSize];
  1554. if (pvData && pvUserData)
  1555. {
  1556. RtlCopyMemory(pvData, pvUserData, pDlsBuffer->BufferSize);
  1557. ntStatus = STATUS_SUCCESS;
  1558. }
  1559. else
  1560. {
  1561. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload download allocate failed"));
  1562. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1563. }
  1564. }
  1565. __except (EXCEPTION_EXECUTE_HANDLER)
  1566. {
  1567. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload lock or copy failed"));
  1568. ntStatus = GetExceptionCode();
  1569. }
  1570. // cleanup
  1571. if (pagesLocked)
  1572. {
  1573. MmUnlockPages(pMdl);
  1574. }
  1575. IoFreeMdl(pMdl);
  1576. }
  1577. else
  1578. {
  1579. _DbgPrintF(DEBUGLVL_TERSE, ("CDmSynthStream::HandleDownload IoAllocateMdl failed"));
  1580. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1581. }
  1582. // download to synth
  1583. SYNTHDOWNLOAD SynthDownload;
  1584. if (SUCCEEDED(ntStatus))
  1585. {
  1586. HRESULT hr = m_pSynth->Download(&SynthDownload.DownloadHandle,
  1587. pvData,
  1588. &SynthDownload.Free);
  1589. if (SUCCEEDED(hr))
  1590. {
  1591. if (!SynthDownload.Free)
  1592. {
  1593. pvData = NULL; // prevent from being freed
  1594. }
  1595. if (SUCCEEDED(ntStatus))
  1596. {
  1597. SynthDownload.Free = TRUE; // client can always free user data
  1598. ASSERT(pRequest->ValueSize >= sizeof(SynthDownload));
  1599. RtlCopyMemory(pRequest->Value, &SynthDownload, sizeof(SynthDownload));
  1600. pRequest->ValueSize = sizeof(SynthDownload);
  1601. }
  1602. }
  1603. else
  1604. {
  1605. ntStatus = MapHRESULT(hr);
  1606. }
  1607. }
  1608. }
  1609. if (pvData)
  1610. {
  1611. delete [] pvData;
  1612. pvData = NULL;
  1613. }
  1614. if (!NT_SUCCESS(ntStatus))
  1615. {
  1616. pRequest->ValueSize = 0;
  1617. }
  1618. return ntStatus;
  1619. }
  1620. /*****************************************************************************
  1621. * CDmSynthStream::HandleUnload()
  1622. *****************************************************************************
  1623. * Handle an unload request. Forward to the synth and remove from our list.
  1624. */
  1625. NTSTATUS
  1626. CDmSynthStream::HandleUnload(IN PPCPROPERTY_REQUEST pRequest)
  1627. {
  1628. PAGED_CODE();
  1629. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandleUnload"));
  1630. NTSTATUS ntStatus;
  1631. ntStatus = ValidatePropertyParams(pRequest, sizeof(HANDLE), 0);
  1632. if (NT_SUCCESS(ntStatus))
  1633. {
  1634. HRESULT hr = m_pSynth->Unload(*(HANDLE*)pRequest->Value,NULL,NULL);
  1635. if (FAILED(hr))
  1636. {
  1637. pRequest->ValueSize = 0;
  1638. ntStatus = MapHRESULT(hr);
  1639. }
  1640. }
  1641. return ntStatus;
  1642. }
  1643. /*****************************************************************************
  1644. * CDmSynthStream::HandlePropertySynthDls()
  1645. *****************************************************************************
  1646. * Handles a property in the SynthDls set.
  1647. */
  1648. NTSTATUS
  1649. CDmSynthStream::HandlePropertySynthDls(IN PPCPROPERTY_REQUEST pRequest)
  1650. {
  1651. PAGED_CODE();
  1652. _DbgPrintF(DEBUGLVL_BLAB, ("CDmSynthStream::HandlePropertySynthDls"));
  1653. NTSTATUS ntStatus;
  1654. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1655. {
  1656. ntStatus = DefaultSynthBasicPropertyHandler(pRequest);
  1657. }
  1658. else
  1659. {
  1660. switch (pRequest->PropertyItem->Id)
  1661. {
  1662. case KSPROPERTY_SYNTH_DLS_DOWNLOAD:
  1663. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySynthDls KSPROPERTY_SYNTH_DLS_DOWNLOAD"));
  1664. ntStatus = HandleDownload(pRequest);
  1665. break;
  1666. case KSPROPERTY_SYNTH_DLS_UNLOAD:
  1667. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySynthDls KSPROPERTY_SYNTH_DLS_UNLOAD"));
  1668. ntStatus = HandleUnload(pRequest);
  1669. break;
  1670. case KSPROPERTY_SYNTH_DLS_APPEND:
  1671. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySynthDls KSPROPERTY_SYNTH_DLS_APPEND"));
  1672. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONG), KSPROPERTY_TYPE_SET);
  1673. if (NT_SUCCESS(ntStatus))
  1674. {
  1675. *(PULONG)(pRequest->Value) = 1;
  1676. pRequest->ValueSize = sizeof(ULONG);
  1677. }
  1678. break;
  1679. case KSPROPERTY_SYNTH_DLS_WAVEFORMAT:
  1680. _DbgPrintF(DEBUGLVL_BLAB,("CDmSynthStream::HandlePropertySynthDls KSPROPERTY_SYNTH_DLS_WAVEFORMAT"));
  1681. ntStatus = ValidatePropertyParams(pRequest, sizeof(WAVEFORMATEX), KSPROPERTY_TYPE_SET);
  1682. if (NT_SUCCESS(ntStatus))
  1683. {
  1684. WAVEFORMATEX *pwfex;
  1685. pwfex = (WAVEFORMATEX *)pRequest->Value;
  1686. RtlZeroMemory(pwfex, sizeof(WAVEFORMATEX));
  1687. pwfex->wFormatTag = WAVE_FORMAT_PCM;
  1688. pwfex->nChannels = 2;
  1689. pwfex->nSamplesPerSec = 22050L;
  1690. pwfex->nAvgBytesPerSec = 22050L * 2 * 2;
  1691. pwfex->nBlockAlign = 4;
  1692. pwfex->wBitsPerSample = 16;
  1693. pwfex->cbSize = 0;
  1694. pRequest->ValueSize = sizeof(WAVEFORMATEX);
  1695. }
  1696. break;
  1697. default:
  1698. _DbgPrintF(DEBUGLVL_TERSE,("CDmSynthStream::HandlePropertySynthDls unrecognized ID"));
  1699. pRequest->ValueSize = 0;
  1700. ntStatus = STATUS_UNSUCCESSFUL;
  1701. break;
  1702. }
  1703. }
  1704. return ntStatus;
  1705. }
  1706. /*****************************************************************************
  1707. * PropertyHandler_Support()
  1708. *****************************************************************************
  1709. * Redirect to the correct CDMSynthStream member.
  1710. */
  1711. NTSTATUS
  1712. PropertyHandler_Support(IN PPCPROPERTY_REQUEST pRequest)
  1713. {
  1714. PAGED_CODE();
  1715. _DbgPrintF(DEBUGLVL_BLAB, ("PropertyHandler_Support"));
  1716. ASSERT(pRequest);
  1717. if (!(pRequest->MinorTarget))
  1718. {
  1719. return(STATUS_INVALID_PARAMETER);
  1720. }
  1721. return (PDMSYNTHSTREAM(pRequest->MinorTarget))->HandlePropertySupport(pRequest);
  1722. }
  1723. /*****************************************************************************
  1724. * PropertyHandler_Effects()
  1725. *****************************************************************************
  1726. * Redirect to the correct CDMSynthStream member.
  1727. */
  1728. NTSTATUS
  1729. PropertyHandler_Effects(IN PPCPROPERTY_REQUEST pRequest)
  1730. {
  1731. PAGED_CODE();
  1732. _DbgPrintF(DEBUGLVL_BLAB, ("PropertyHandler_Effects"));
  1733. ASSERT(pRequest);
  1734. if (!(pRequest->MinorTarget))
  1735. {
  1736. return(STATUS_INVALID_PARAMETER);
  1737. }
  1738. return (PDMSYNTHSTREAM(pRequest->MinorTarget))->HandlePropertyEffects(pRequest);
  1739. }
  1740. /*****************************************************************************
  1741. * PropertyHandler_Synth()
  1742. *****************************************************************************
  1743. * Redirect to the correct CDMSynthStream member.
  1744. */
  1745. NTSTATUS
  1746. PropertyHandler_Synth(IN PPCPROPERTY_REQUEST pRequest)
  1747. {
  1748. PAGED_CODE();
  1749. _DbgPrintF(DEBUGLVL_BLAB, ("PropertyHandler_Synth"));
  1750. ASSERT(pRequest);
  1751. if (!(pRequest->MinorTarget))
  1752. {
  1753. return(STATUS_INVALID_PARAMETER);
  1754. }
  1755. return (PDMSYNTHSTREAM(pRequest->MinorTarget))->HandlePropertySynth(pRequest);
  1756. }
  1757. const WCHAR wszDescription[] = L"Microsoft DDK Kernel DLS Synthesizer";
  1758. /*****************************************************************************
  1759. * PropertyHandler_SynthCaps()
  1760. *****************************************************************************
  1761. * Redirect to the correct CDMSynthStream member.
  1762. */
  1763. NTSTATUS
  1764. PropertyHandler_SynthCaps(IN PPCPROPERTY_REQUEST pRequest)
  1765. {
  1766. PAGED_CODE();
  1767. _DbgPrintF(DEBUGLVL_BLAB, ("PropertyHandler_SynthCaps"));
  1768. ASSERT(pRequest);
  1769. NTSTATUS ntStatus;
  1770. if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1771. {
  1772. ntStatus = DefaultBasicPropertyHandler(
  1773. pRequest, KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET);
  1774. }
  1775. else
  1776. {
  1777. ntStatus = ValidatePropertyParams(pRequest, sizeof(SYNTHCAPS), KSPROPERTY_TYPE_SET);
  1778. if (NT_SUCCESS(ntStatus))
  1779. {
  1780. SYNTHCAPS Caps;
  1781. RtlZeroMemory(&Caps, sizeof(Caps));
  1782. Caps.Guid = CLSID_DDKWDMSynth;
  1783. Caps.Flags = SYNTH_PC_DLS | SYNTH_PC_SOFTWARESYNTH;
  1784. Caps.MemorySize = SYNTH_PC_SYSTEMMEMORY;
  1785. Caps.MaxChannelGroups = MAX_CHANNEL_GROUPS;
  1786. Caps.MaxVoices = MAX_VOICES;
  1787. Caps.MaxAudioChannels = 2;
  1788. RtlCopyMemory(Caps.Description, wszDescription, sizeof(wszDescription));
  1789. RtlCopyMemory(pRequest->Value, &Caps, sizeof(Caps));
  1790. pRequest->ValueSize = sizeof(Caps);
  1791. }
  1792. }
  1793. return ntStatus;
  1794. }
  1795. /*****************************************************************************
  1796. * PropertyHandler_SynthDls()
  1797. *****************************************************************************
  1798. * Redirect to the correct CDMSynthStream member.
  1799. */
  1800. NTSTATUS
  1801. PropertyHandler_SynthDls(IN PPCPROPERTY_REQUEST pRequest)
  1802. {
  1803. PAGED_CODE();
  1804. _DbgPrintF(DEBUGLVL_BLAB, ("PropertyHandler_SynthDls"));
  1805. ASSERT(pRequest);
  1806. if (!(pRequest->MinorTarget))
  1807. {
  1808. return(STATUS_INVALID_PARAMETER);
  1809. }
  1810. return (PDMSYNTHSTREAM(pRequest->MinorTarget))->HandlePropertySynthDls(pRequest);
  1811. }
  1812. /*****************************************************************************
  1813. * DefaultBasicPropertyHandler()
  1814. *****************************************************************************
  1815. * Finds the given property in SynthProperties and sets Support flags
  1816. * accordingly.
  1817. */
  1818. NTSTATUS
  1819. DefaultSynthBasicPropertyHandler
  1820. (
  1821. IN PPCPROPERTY_REQUEST pRequest
  1822. )
  1823. {
  1824. NTSTATUS ntStatus;
  1825. const WORD c_wMaxProps = SIZEOF_ARRAY(SynthProperties);
  1826. WORD wPropIdx;
  1827. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONG), 0);
  1828. if (NT_SUCCESS(ntStatus))
  1829. {
  1830. for (wPropIdx = 0; wPropIdx < c_wMaxProps; wPropIdx++)
  1831. {
  1832. if ( (SynthProperties[wPropIdx].Set == pRequest->PropertyItem->Set)
  1833. && (SynthProperties[wPropIdx].Id == pRequest->PropertyItem->Id) )
  1834. {
  1835. // if return buffer can hold a ULONG, return the access flags
  1836. PULONG AccessFlags = PULONG(pRequest->Value);
  1837. *AccessFlags = SynthProperties[wPropIdx].Flags;
  1838. // set the return value size
  1839. pRequest->ValueSize = sizeof(ULONG);
  1840. break;
  1841. }
  1842. }
  1843. if (wPropIdx == c_wMaxProps)
  1844. {
  1845. _DbgPrintF(DEBUGLVL_TERSE, ("DefaultSynthBasicPropertyHandler property ID not found"));
  1846. pRequest->ValueSize = 0;
  1847. ntStatus = STATUS_UNSUCCESSFUL;
  1848. }
  1849. }
  1850. return ntStatus;
  1851. } // DefaultSynthBasicPropertyHandler
  1852. /*****************************************************************************
  1853. * DefaultBasicPropertyHandler()
  1854. *****************************************************************************
  1855. * Basic support Handler
  1856. */
  1857. NTSTATUS DefaultBasicPropertyHandler
  1858. (
  1859. IN PPCPROPERTY_REQUEST pRequest,
  1860. IN DWORD dwSupportVerb
  1861. )
  1862. {
  1863. NTSTATUS ntStatus;
  1864. ntStatus = ValidatePropertyParams(pRequest, sizeof(ULONG), 0);
  1865. if (NT_SUCCESS(ntStatus))
  1866. {
  1867. pRequest->ValueSize = sizeof(ULONG);
  1868. *PULONG(pRequest->Value) = dwSupportVerb;
  1869. }
  1870. return ntStatus;
  1871. } // DefaultBasicPropertyHandler
  1872. /*****************************************************************************
  1873. * ValidatePropertyParams()
  1874. *****************************************************************************
  1875. * Checks whether the data size appropriate.
  1876. */
  1877. NTSTATUS
  1878. ValidatePropertyParams
  1879. (
  1880. IN PPCPROPERTY_REQUEST pRequest,
  1881. IN ULONG cbSize,
  1882. IN DWORD dwExcludeVerb
  1883. )
  1884. {
  1885. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  1886. if (pRequest && cbSize)
  1887. {
  1888. // If this is an invalid request.
  1889. //
  1890. if (pRequest->Verb & dwExcludeVerb)
  1891. {
  1892. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1893. }
  1894. // If the caller is asking for ValueSize.
  1895. //
  1896. else if (0 == pRequest->ValueSize)
  1897. {
  1898. pRequest->ValueSize = cbSize;
  1899. ntStatus = STATUS_BUFFER_OVERFLOW;
  1900. }
  1901. // If the caller passed an invalid ValueSize.
  1902. //
  1903. else if (pRequest->ValueSize < cbSize)
  1904. {
  1905. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1906. }
  1907. // If all parameters are OK.
  1908. //
  1909. else if (pRequest->ValueSize >= cbSize)
  1910. {
  1911. if (pRequest->Value)
  1912. {
  1913. ntStatus = STATUS_SUCCESS;
  1914. //
  1915. // Caller should set ValueSize, if the property
  1916. // call is successful.
  1917. //
  1918. }
  1919. }
  1920. }
  1921. // Clear the ValueSize if unsuccessful.
  1922. //
  1923. if (STATUS_SUCCESS != ntStatus &&
  1924. STATUS_BUFFER_OVERFLOW != ntStatus &&
  1925. pRequest != NULL)
  1926. {
  1927. pRequest->ValueSize = 0;
  1928. }
  1929. return ntStatus;
  1930. } // ValidatePropertyParams