|
|
// Copyright (c) 1998 Microsoft Corporation
//
// DirectMusic Software Synthesizer
//
#include "common.h"
#include "private.h"
#include "dmusicks.h"
#define STR_MODULENAME "DmSynth: "
#pragma code_seg("PAGE")
// Property handlers
//
NTSTATUS PropertyHandler_SynthCaps(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_SynthPortParameters(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_SynthMasterClock(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_SynthPortChannelGroups(IN PPCPROPERTY_REQUEST);
NTSTATUS PropertyHandler_DlsDownload(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_DlsUnload(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_DlsCompact(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_DlsAppend(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_DlsVolume(IN PPCPROPERTY_REQUEST);
NTSTATUS PropertyHandler_GetLatency(IN PPCPROPERTY_REQUEST); NTSTATUS PropertyHandler_GetLatencyClock(IN PPCPROPERTY_REQUEST);
// CreateMiniportDirectMusic
//
//
NTSTATUS CreateMiniportDmSynth ( OUT PUNKNOWN * Unknown, IN PUNKNOWN UnknownOuter OPTIONAL, IN POOL_TYPE PoolType ) { PAGED_CODE(); ASSERT(Unknown);
_DbgPrintF(DEBUGLVL_TERSE, ("Creating DirectMusic synth miniport")); STD_CREATE_BODY(CMiniportDmSynth, Unknown, UnknownOuter, PoolType); }
STDMETHODIMP CMiniportDmSynth::NonDelegatingQueryInterface ( IN REFIID Interface, OUT PVOID* Object ) { PAGED_CODE();
ASSERT(Object);
if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { *Object = PVOID(PUNKNOWN(this)); } else if (IsEqualGUIDAligned(Interface, IID_IMiniport)) { *Object = PVOID(PMINIPORT(this)); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportSynthesizer)) { *Object = PVOID(PMINIPORTSYNTHESIZER(this)); } else { *Object = NULL; }
if (*Object) { PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; }
return STATUS_INVALID_PARAMETER; }
CMiniportDmSynth::~CMiniportDmSynth() { }
STDMETHODIMP CMiniportDmSynth::Init ( IN PUNKNOWN Unknown OPTIONAL, IN PRESOURCELIST ResourceList, IN PPORTSYNTHESIZER Port_, OUT PSERVICEGROUP* ServiceGroup ) { _DbgPrintF(DEBUGLVL_TERSE, ("[CMiniportDmSynth::Init]")); ASSERT(ResourceList); ASSERT(Port_); ASSERT(ServiceGroup);
Port = Port_; Port->AddRef();
Stream = NULL; *ServiceGroup = NULL; return STATUS_SUCCESS; }
STDMETHODIMP CMiniportDmSynth::NewStream ( OUT PMINIPORTSYNTHESIZERSTREAM * Stream_, IN PUNKNOWN OuterUnknown OPTIONAL, IN POOL_TYPE PoolType, IN ULONG Pin, IN BOOLEAN Capture, IN PKSDATAFORMAT DataFormat, OUT PSERVICEGROUP * ServiceGroup ) { _DbgPrintF(DEBUGLVL_TERSE, ("[CMiniportDmSynth::NewStream]")); NTSTATUS nt = STATUS_SUCCESS;
if (Stream) { // XXX Multiinstance!!!
//
nt = STATUS_INVALID_DEVICE_REQUEST; } else { CDmSynthStream *Stream = new(PoolType) CDmSynthStream(OuterUnknown);
if (Stream) { nt = Stream->Init(this); if (NT_SUCCESS(nt)) { Stream->AddRef(); *Stream_ = PMINIPORTSYNTHESIZERSTREAM(Stream); } else { Stream->Release(); Stream = NULL; } } else { nt = STATUS_INSUFFICIENT_RESOURCES; }
}
return nt; }
STDMETHODIMP_(void) CMiniportDmSynth::Service() { }
// ==============================================================================
// PinDataRangesStream
// Structures indicating range of valid format values for streaming pins.
// ==============================================================================
static KSDATARANGE_MUSIC PinDataRangesStream[] = { { { sizeof(KSDATARANGE_MUSIC), 0, 0, 0, STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC), STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DIRECTMUSIC), STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) }, STATICGUIDOF(KSMUSIC_TECHNOLOGY_WAVETABLE), 0, // Channels
0, // Notes
0x0000ffff // ChannelMask
} };
// ==============================================================================
// PinDataRangePointersStream
// List of pointers to structures indicating range of valid format values
// for streaming pins.
// ==============================================================================
static PKSDATARANGE PinDataRangePointersStream[] = { PKSDATARANGE(&PinDataRangesStream[0]) };
#if 0
// ==============================================================================
// PinDataRangesBridge
// Structures indicating range of valid format values for bridge pins.
// ==============================================================================
static KSDATARANGE PinDataRangesBridge[] = { { sizeof(KSDATARANGE), 0, 0, 0, STATICGUIDOF(KSDATAFORMAT_TYPE_MUSIC), STATICGUIDOF(KSDATAFORMAT_SUBTYPE_MIDI_BUS), STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE) } };
// ==============================================================================
// PinDataRangePointersBridge
// List of pointers to structures indicating range of valid format values
// for bridge pins.
// ==============================================================================
static PKSDATARANGE PinDataRangePointersBridge[] = { &PinDataRangesBridge[0] }; #endif
// ==============================================================================
// PinDataRangesAudio
// Structures indicating range of valid format values for audio pins.
// ==============================================================================
static KSDATARANGE_AUDIO PinDataRangesAudio[] = { { { sizeof(KSDATARANGE_AUDIO), 0, 0, 0, STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX), }, 2, 16, 16, 22050, 22050 } };
// ==============================================================================
// PinDataRangePointersAudio
// List of pointers to structures indicating range of valid format values
// for audio pins.
// ==============================================================================
static PKSDATARANGE PinDataRangePointersAudio[] = { (PKSDATARANGE)&PinDataRangesAudio };
static PCPROPERTY_ITEM SynthProperties[] = { ///////////////////////////////////////////////////////////////////
//
// Configuration items
//
// Global: Synth caps
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_CAPS, KSPROPERTY_TYPE_GET, PropertyHandler_SynthCaps }, // Per Stream: Synth port parameters
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_PORTPARAMETERS, KSPROPERTY_TYPE_GET, PropertyHandler_SynthPortParameters },
// Global: Master clock
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_MASTERCLOCK, KSPROPERTY_TYPE_SET, PropertyHandler_SynthMasterClock },
// Per Stream: Channel groups
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_CHANNELGROUPS, KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET, PropertyHandler_SynthPortChannelGroups },
///////////////////////////////////////////////////////////////////
//
// DLS items
//
// Per stream: Download DLS sample
//
{ &KSPROPSETID_Synth_Dls, KSPROPERTY_SYNTH_DOWNLOAD, KSPROPERTY_TYPE_GET, PropertyHandler_DlsDownload },
// Per stream: Unload DLS sample
//
{ &KSPROPSETID_Synth_Dls, KSPROPERTY_SYNTH_UNLOAD, KSPROPERTY_TYPE_SET, PropertyHandler_DlsUnload },
// Global: Compact DLS memory
//
{ &KSPROPSETID_Synth_Dls, KSPROPERTY_SYNTH_COMPACT, KSPROPERTY_TYPE_SET, PropertyHandler_DlsCompact },
// Per stream: append
//
{ &KSPROPSETID_Synth_Dls, KSPROPERTY_SYNTH_APPEND, KSPROPERTY_TYPE_SET, PropertyHandler_DlsAppend },
// Per stream: volume
//
{ &KSPROPSETID_Synth_Dls, KSPROPERTY_SYNTH_VOLUME, KSPROPERTY_TYPE_SET, PropertyHandler_DlsVolume },
///////////////////////////////////////////////////////////////////
//
// Clock items
//
// Per stream: Get desired latency
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_LATENCY, KSPROPERTY_TYPE_GET, PropertyHandler_GetLatency },
// Per stream: Get current latency time
//
{ &KSPROPSETID_Synth, KSPROPERTY_SYNTH_LatencyClock, KSPROPERTY_TYPE_GET, PropertyHandler_GetLatencyClock } };
DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSynth, SynthProperties);
// ==============================================================================
// MiniportPins
// List of pins.
// ==============================================================================
static PCPIN_DESCRIPTOR MiniportPins[] = { { 1,1,1, // InstanceCount
NULL, { // KsPinDescriptor
0, // InterfacesCount
NULL, // Interfaces
0, // MediumsCount
NULL, // Mediums
SIZEOF_ARRAY(PinDataRangePointersStream), // DataRangesCount
PinDataRangePointersStream, // DataRanges
KSPIN_DATAFLOW_IN, // DataFlow
KSPIN_COMMUNICATION_SINK, // Communication
(GUID *) &KSCATEGORY_AUDIO, // Category
NULL, // Name
0 // Reserved
} }, #if 0
{ 0,0,0, // InstanceCount
NULL, // AutomationTable
{ // KsPinDescriptor
0, // InterfacesCount
NULL, // Interfaces
0, // MediumsCount
NULL, // Mediums
SIZEOF_ARRAY(PinDataRangePointersBridge), // DataRangesCount
PinDataRangePointersBridge, // DataRanges
KSPIN_DATAFLOW_OUT, // DataFlow
KSPIN_COMMUNICATION_NONE, // Communication
(GUID *) &KSCATEGORY_AUDIO, // Category
NULL, // Name
0 // Reserved
} } #else
{ 1,1,1, // InstanceCount
NULL, // AutomationTable
{ // KsPinDescriptor
0, // InterfacesCount
NULL, // Interfaces
0, // MediumsCount
NULL, // Mediums
SIZEOF_ARRAY(PinDataRangePointersAudio), // DataRangesCount
PinDataRangePointersAudio, // DataRanges
KSPIN_DATAFLOW_OUT, // DataFlow
KSPIN_COMMUNICATION_SOURCE, // Communication
(GUID *) &KSCATEGORY_AUDIO, // Category
NULL, // Name
0 // Reserved
} } #endif
};
// ==============================================================================
// MiniportNodes
// List of nodes.
// ==============================================================================
#define CONST_PCNODE_DESCRIPTOR(n) { 0, NULL, &n, NULL }
#define CONST_PCNODE_DESCRIPTOR_AUTO(n,a) { 0, &a, &n, NULL }
static PCNODE_DESCRIPTOR MiniportNodes[] = { CONST_PCNODE_DESCRIPTOR_AUTO(KSNODETYPE_SYNTHESIZER, AutomationSynth) };
// ==============================================================================
// MiniportConnections
// List of connections.
// ==============================================================================
static PCCONNECTION_DESCRIPTOR MiniportConnections[] = { // From node From pin To node To pin
//
{ PCFILTER_NODE, 0, 0, 1 }, // Stream in to synth.
{ 0, 0, PCFILTER_NODE, 1 } // Synth to bridge out.
};
/*****************************************************************************
* MiniportFilterDescriptor ***************************************************************************** * Complete miniport description. */ static PCFILTER_DESCRIPTOR MiniportFilterDescriptor = { 0, // Version
NULL, // AutomationTable
sizeof(PCPIN_DESCRIPTOR), // PinSize
SIZEOF_ARRAY(MiniportPins), // PinCount
MiniportPins, // Pins
sizeof(PCNODE_DESCRIPTOR), // NodeSize
SIZEOF_ARRAY(MiniportNodes), // NodeCount
MiniportNodes, // Nodes
SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
MiniportConnections, // Connections
0, // CategoryCount
NULL // Categories
};
STDMETHODIMP CMiniportDmSynth::GetDescription ( OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor ) { PAGED_CODE(); ASSERT(OutFilterDescriptor);
_DbgPrintF(DEBUGLVL_VERBOSE, ("GetDescription"));
*OutFilterDescriptor = &MiniportFilterDescriptor; return STATUS_SUCCESS; }
STDMETHODIMP CMiniportDmSynth::DataRangeIntersection ( IN ULONG PinId, IN PKSDATARANGE DataRange, IN PKSDATARANGE MatchingDataRange, IN ULONG OutputBufferLength, OUT PVOID ResultantFormat OPTIONAL, OUT PULONG ResultantFormatLength ) { // XXX ???
//
return STATUS_SUCCESS; }
///////////////////////////////////////////////////////////////////////////////
//
// CDmSynthStream
//
CDmSynthStream::~CDmSynthStream() { _DbgPrintF(DEBUGLVL_TERSE, ("[CDmSynthStream destruct]"));
if (Miniport) { Miniport->Stream = NULL; Miniport->Release(); }
if (Synth) { delete Synth; }
if (Sink) { Sink->Release(); } }
NTSTATUS CDmSynthStream::Init ( CMiniportDmSynth *Miniport_ ) { _DbgPrintF(DEBUGLVL_TERSE, ("[CDmSynthStream::Init]")); _DbgPrintF(DEBUGLVL_TERSE, ("Stream IUnkown is %08X", DWORD(PVOID(PUNKNOWN(this)))));
Miniport = Miniport_; Miniport->AddRef();
Synth = new CSynth; if (Synth == NULL) { Miniport->Release(); return STATUS_NO_MEMORY; }
Sink = new CSysLink; if (Sink == NULL) { delete Synth; Synth = NULL; Miniport->Release(); return STATUS_NO_MEMORY; }
return STATUS_SUCCESS; }
STDMETHODIMP CDmSynthStream::NonDelegatingQueryInterface ( IN REFIID Interface, OUT PVOID* Object ) { PAGED_CODE(); ASSERT(Object);
if (IsEqualGUIDAligned(Interface, IID_IUnknown)) { *Object = PVOID(PUNKNOWN(this)); } else if (IsEqualGUIDAligned(Interface, IID_IMiniportSynthesizerStream)) { *Object = PVOID(PMINIPORTSYNTHESIZERSTREAM(this)); } else { *Object = NULL; }
if (*Object) { //
// We reference the interface for the caller.
//
PUNKNOWN(*Object)->AddRef(); return STATUS_SUCCESS; }
return STATUS_INVALID_PARAMETER; }
STDMETHODIMP CDmSynthStream::SetState ( IN KSSTATE NewState ) { PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE, ("[CDmSynthStream::SetState]"));
NTSTATUS nt = STATUS_SUCCESS;
// XXX Propogate to activate state
//
switch (NewState) { case KSSTATE_RUN: nt = Synth->Activate(PortParams.SampleRate, PortParams.Stereo ? 2 : 1); break;
case KSSTATE_ACQUIRE: case KSSTATE_STOP: case KSSTATE_PAUSE: nt = Synth->Deactivate(); break; }
return nt; }
STDMETHODIMP CDmSynthStream::ConnectOutput ( PMXFFILTER ConnectionPoint ) { return STATUS_NOT_IMPLEMENTED; }
STDMETHODIMP CDmSynthStream::DisconnectOutput ( PMXFFILTER ConnectionPoint ) { return STATUS_NOT_IMPLEMENTED; }
STDMETHODIMP CDmSynthStream::PutMessage ( IN PDMUS_KERNEL_EVENT Event ) { PBYTE Data = (Event->ByteCount <= sizeof(PBYTE) ? &Event->ActualData.Data[0] : Event->ActualData.DataPtr);
// This is just MIDI bytes
//
return Synth->PlayBuffer(Sink, Event->PresTime100Ns, Data, Event->ByteCount, (ULONG)Event->ChannelGroup); }
// CDmSynthStream::HandlePortParams
//
// Fix up the port params to include defaults. Cache the params as well
// as passing the updated version back.
//
STDMETHODIMP CDmSynthStream::HandlePortParams ( IN PPCPROPERTY_REQUEST pRequest ) { BOOL ValidParamChanged = FALSE;
SYNTH_PORTPARAMS *Params = (SYNTH_PORTPARAMS*)pRequest->Value; if (pRequest->ValueSize < sizeof(SYNTH_PORTPARAMS)) { return STATUS_BUFFER_TOO_SMALL; }
if (!(Params->ValidParams & SYNTH_PORTPARAMS_VOICES)) { Params->Voices = 32; } else if (Params->Voices > 32) { Params->Voices = 32; ValidParamChanged = TRUE; }
if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS)) { Params->ChannelGroups = 32; } else if (Params->ChannelGroups > 32) { Params->ChannelGroups = 32; ValidParamChanged = TRUE; }
if (!(Params->ValidParams & SYNTH_PORTPARAMS_SAMPLERATE)) { Params->SampleRate = 22050; } else if (Params->SampleRate != 11025 && Params->SampleRate != 22050 && Params->SampleRate != 44100) { Params->SampleRate = 22050; ValidParamChanged = TRUE; }
if (!(Params->ValidParams & SYNTH_PORTPARAMS_REVERB)) { Params->Reverb = FALSE; } else if (Params->Reverb) { Params->Reverb = FALSE; ValidParamChanged = TRUE; }
RtlCopyMemory(&PortParams, Params, sizeof(PortParams)); return ValidParamChanged ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS; }
///////////////////////////////////////////////////////////////////////////////
//
// Property dispatchers
//
// XXX All of these need to be connected
//
NTSTATUS PropertyHandler_SynthCaps ( IN PPCPROPERTY_REQUEST pRequest ) { SYNTHCAPS caps;
caps.Flags = SYNTH_PC_DLS | SYNTH_PC_SOFTWARESYNTH; caps.MemorySize = SYNTH_PC_SYSTEMMEMORY; caps.MaxChannelGroups = 32; caps.MaxVoices = 32;
pRequest->ValueSize = min(pRequest->ValueSize, sizeof(caps)); RtlCopyMemory(pRequest->Value, &caps, pRequest->ValueSize);
return STATUS_SUCCESS; }
// PropertyHandler_SynthPortParameters
//
NTSTATUS PropertyHandler_SynthPortParameters ( IN PPCPROPERTY_REQUEST pRequest ) { ASSERT(pRequest); ASSERT(pRequest->MinorTarget); return (PDMSYNTHSTREAM(pRequest->MinorTarget))->HandlePortParams(pRequest); }
// PropertyHandler_SynthMasterClock
//
NTSTATUS PropertyHandler_SynthMasterClock ( IN PPCPROPERTY_REQUEST pRequest ) { return STATUS_SUCCESS; }
// PropertyHandler_SynthPortChannelGroups
//
NTSTATUS PropertyHandler_SynthPortChannelGroups ( IN PPCPROPERTY_REQUEST pRequest ) { ASSERT(pRequest); ASSERT(pRequest->MinorTarget);
if (pRequest->ValueSize < sizeof(ULONG)) { return STATUS_BUFFER_TOO_SMALL; }
ULONG ChannelGroups = *(PULONG)(pRequest->Value);
return (PDMSYNTHSTREAM(pRequest->MinorTarget))->Synth->SetNumChannelGroups(ChannelGroups); }
// PropertyHandler_DlsDownload
//
NTSTATUS PropertyHandler_DlsDownload ( IN PPCPROPERTY_REQUEST pRequest ) { // XXX Lock down this memory
//
// XXX Validate entire buffer size???
//
HANDLE DownloadHandle; BOOL Free;
NTSTATUS Status = (PDMSYNTHSTREAM(pRequest->MinorTarget))->Synth->Download( &DownloadHandle, pRequest->Value, &Free);
if (SUCCEEDED(Status)) { ASSERT(pRequest->ValueSize >= sizeof(DownloadHandle)); RtlCopyMemory(pRequest->Value, &DownloadHandle, sizeof(DownloadHandle)); pRequest->ValueSize = sizeof(DownloadHandle); }
return Status; }
// PropertyHandler_DlsUnload
//
HRESULT CALLBACK UnloadComplete(HANDLE,HANDLE);
NTSTATUS PropertyHandler_DlsUnload ( IN PPCPROPERTY_REQUEST pRequest ) { ASSERT(pRequest); ASSERT(pRequest->MinorTarget);
if (pRequest->ValueSize < sizeof(HANDLE)) { return STATUS_BUFFER_TOO_SMALL; }
// XXX Need some concurrency control here
//
NTSTATUS Status = (PDMSYNTHSTREAM(pRequest->MinorTarget))->Synth->Unload( *(HANDLE*)pRequest->Value, UnloadComplete, (HANDLE)pRequest); return STATUS_SUCCESS; }
HRESULT CALLBACK UnloadComplete(HANDLE WhichDownload, HANDLE CallbackInstance) { PPCPROPERTY_REQUEST pRequest = (PPCPROPERTY_REQUEST)CallbackInstance; PcCompletePendingPropertyRequest(pRequest, STATUS_SUCCESS);
return STATUS_SUCCESS; }
// PropertyHandler_DlsCompact
//
// We don't care
//
NTSTATUS PropertyHandler_DlsCompact ( IN PPCPROPERTY_REQUEST pRequest ) { return STATUS_SUCCESS; }
NTSTATUS PropertyHandler_DlsAppend ( IN PPCPROPERTY_REQUEST pRequest ) { ASSERT(pRequest);
if (pRequest->ValueSize < sizeof(ULONG)) { return STATUS_BUFFER_TOO_SMALL; }
*(PULONG)(pRequest->Value) = 4; pRequest->ValueSize = sizeof(ULONG);
return STATUS_SUCCESS; }
NTSTATUS PropertyHandler_DlsVolume ( IN PPCPROPERTY_REQUEST pRequest ) { // XXX *Both* versions of the synth need this
//
return STATUS_SUCCESS; }
NTSTATUS PropertyHandler_GetLatency ( IN PPCPROPERTY_REQUEST pRequest ) { if (pRequest->ValueSize < sizeof(ULONGLONG)) { return STATUS_BUFFER_TOO_SMALL; }
*((PULONGLONG)pRequest->Value) = 0; pRequest->ValueSize = sizeof(ULONGLONG);
return STATUS_SUCCESS; }
NTSTATUS PropertyHandler_GetLatencyClock ( IN PPCPROPERTY_REQUEST pRequest ) { // XXX This depends on the synth sink
//
return STATUS_SUCCESS; }
|