2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/midi.c
5 * PURPOSE: Midi Support Functions
6 * PROGRAMMER: Johannes Anderwald
12 MMixerGetPinDataFlowAndCommunication(
13 IN PMIXER_CONTEXT MixerContext
,
16 OUT PKSPIN_DATAFLOW DataFlow
,
17 OUT PKSPIN_COMMUNICATION Communication
)
26 Pin
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
27 Pin
.Property
.Id
= KSPROPERTY_PIN_DATAFLOW
;
28 Pin
.Property
.Set
= KSPROPSETID_Pin
;
30 /* get pin dataflow */
31 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)DataFlow
, sizeof(KSPIN_DATAFLOW
), &BytesReturned
);
32 if (Status
!= MM_STATUS_SUCCESS
)
34 /* failed to retrieve dataflow */
38 /* setup communication request */
39 Pin
.Property
.Id
= KSPROPERTY_PIN_COMMUNICATION
;
41 /* get pin communication */
42 Status
= MixerContext
->Control(hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Pin
, sizeof(KSP_PIN
), (PVOID
)Communication
, sizeof(KSPIN_COMMUNICATION
), &BytesReturned
);
49 IN PMIXER_CONTEXT MixerContext
,
50 IN PMIXER_LIST MixerList
,
58 /* allocate midi info */
59 MidiInfo
= MixerContext
->Alloc(sizeof(MIDI_INFO
));
64 return MM_STATUS_NO_MEMORY
;
67 /* initialize midi info */
68 MidiInfo
->DeviceId
= DeviceId
;
69 MidiInfo
->PinId
= PinId
;
72 ASSERT(wcslen(DeviceName
) + 1 < MAXPNAMELEN
);
74 /* copy device name */
75 if (bInput
&& DeviceName
)
77 wcscpy(MidiInfo
->u
.InCaps
.szPname
, DeviceName
);
79 else if (!bInput
&& DeviceName
)
81 wcscpy(MidiInfo
->u
.OutCaps
.szPname
, DeviceName
);
84 /* FIXME determine manufacturer / product id */
87 MidiInfo
->u
.InCaps
.dwSupport
= 0;
88 MidiInfo
->u
.InCaps
.wMid
= MM_MICROSOFT
;
89 MidiInfo
->u
.InCaps
.wPid
= MM_PID_UNMAPPED
;
90 MidiInfo
->u
.InCaps
.vDriverVersion
= 1;
94 MidiInfo
->u
.OutCaps
.dwSupport
= 0;
95 MidiInfo
->u
.OutCaps
.wMid
= MM_MICROSOFT
;
96 MidiInfo
->u
.OutCaps
.wPid
= MM_PID_UNMAPPED
;
97 MidiInfo
->u
.OutCaps
.vDriverVersion
= 1;
102 /* insert into list */
103 InsertTailList(&MixerList
->MidiInList
, &MidiInfo
->Entry
);
104 MixerList
->MidiInListCount
++;
108 /* insert into list */
109 InsertTailList(&MixerList
->MidiOutList
, &MidiInfo
->Entry
);
110 MixerList
->MidiOutListCount
++;
113 return MM_STATUS_SUCCESS
;
117 MMixerCheckFilterPinMidiSupport(
118 IN PMIXER_CONTEXT MixerContext
,
119 IN PMIXER_LIST MixerList
,
120 IN LPMIXER_DATA MixerData
,
122 IN PKSMULTIPLE_ITEM MultipleItem
,
126 PKSDATARANGE DataRange
;
127 KSPIN_COMMUNICATION Communication
;
128 KSPIN_DATAFLOW DataFlow
;
130 /* get first datarange */
131 DataRange
= (PKSDATARANGE
)(MultipleItem
+ 1);
133 /* alignment assert */
134 ASSERT(((ULONG_PTR
)DataRange
& 0x7) == 0);
136 /* iterate through all data ranges */
137 for(Index
= 0; Index
< MultipleItem
->Count
; Index
++)
139 if (IsEqualGUIDAligned(&DataRange
->MajorFormat
, &KSDATAFORMAT_TYPE_MUSIC
) &&
140 IsEqualGUIDAligned(&DataRange
->SubFormat
, &KSDATAFORMAT_SUBTYPE_MIDI
) &&
141 IsEqualGUIDAligned(&DataRange
->Specifier
, &KSDATAFORMAT_SPECIFIER_NONE
))
143 /* pin supports midi datarange */
144 if (MMixerGetPinDataFlowAndCommunication(MixerContext
, MixerData
->hDevice
, PinId
, &DataFlow
, &Communication
) == MM_STATUS_SUCCESS
)
146 if (DataFlow
== KSPIN_DATAFLOW_IN
&& Communication
== KSPIN_COMMUNICATION_SINK
)
148 MMixerAddMidiPin(MixerContext
, MixerList
, MixerData
->DeviceId
, PinId
, FALSE
, szPname
);
150 else if (DataFlow
== KSPIN_DATAFLOW_OUT
&& Communication
== KSPIN_COMMUNICATION_SOURCE
)
152 MMixerAddMidiPin(MixerContext
, MixerList
, MixerData
->DeviceId
, PinId
, TRUE
, szPname
);
157 /* move to next datarange */
158 DataRange
= (PKSDATARANGE
)((ULONG_PTR
)DataRange
+ DataRange
->FormatSize
);
160 /* alignment assert */
161 ASSERT(((ULONG_PTR
)DataRange
& 0x7) == 0);
163 /* data ranges are 64-bit aligned */
164 DataRange
= (PVOID
)(((ULONG_PTR
)DataRange
+ 0x7) & ~0x7);
169 MMixerInitializeMidiForFilter(
170 IN PMIXER_CONTEXT MixerContext
,
171 IN PMIXER_LIST MixerList
,
172 IN LPMIXER_DATA MixerData
,
173 IN PTOPOLOGY Topology
)
175 ULONG PinCount
, Index
;
177 PKSMULTIPLE_ITEM MultipleItem
;
178 WCHAR szPname
[MAXPNAMELEN
];
180 /* get filter pin count */
181 MMixerGetTopologyPinCount(Topology
, &PinCount
);
184 if (MMixerGetDeviceName(MixerContext
, szPname
, MixerData
->hDeviceInterfaceKey
) != MM_STATUS_SUCCESS
)
190 /* iterate all pins and check for KSDATARANGE_MUSIC support */
191 for(Index
= 0; Index
< PinCount
; Index
++)
193 /* get audio pin data ranges */
194 Status
= MMixerGetAudioPinDataRanges(MixerContext
, MixerData
->hDevice
, Index
, &MultipleItem
);
196 /* check for success */
197 if (Status
== MM_STATUS_SUCCESS
)
199 /* check if there is support KSDATARANGE_MUSIC */
200 MMixerCheckFilterPinMidiSupport(MixerContext
, MixerList
, MixerData
, Index
, MultipleItem
, szPname
);
207 IN PMIXER_CONTEXT MixerContext
,
208 IN PMIXER_LIST MixerList
,
211 IN ACCESS_MASK DesiredAccess
,
212 IN PIN_CREATE_CALLBACK CreateCallback
,
214 OUT PHANDLE PinHandle
)
216 PKSPIN_CONNECT PinConnect
;
217 PKSDATAFORMAT DataFormat
;
218 LPMIXER_DATA MixerData
;
220 MIXER_STATUS MixerStatus
;
222 MixerData
= MMixerGetDataByDeviceId(MixerList
, DeviceId
);
224 return MM_STATUS_INVALID_PARAMETER
;
226 /* allocate pin connect */
227 PinConnect
= MMixerAllocatePinConnect(MixerContext
, sizeof(KSDATAFORMAT
));
231 return MM_STATUS_NO_MEMORY
;
234 /* initialize pin connect struct */
235 MMixerInitializePinConnect(PinConnect
, PinId
);
237 /* get offset to dataformat */
238 DataFormat
= (PKSDATAFORMAT
) (PinConnect
+ 1);
240 /* initialize data format */
241 RtlMoveMemory(&DataFormat
->MajorFormat
, &KSDATAFORMAT_TYPE_MUSIC
, sizeof(GUID
));
242 RtlMoveMemory(&DataFormat
->SubFormat
, &KSDATAFORMAT_SUBTYPE_MIDI
, sizeof(GUID
));
243 RtlMoveMemory(&DataFormat
->Specifier
, &KSDATAFORMAT_SPECIFIER_NONE
, sizeof(GUID
));
247 /* let the callback handle the creation */
248 MixerStatus
= CreateCallback(Context
, DeviceId
, PinId
, MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
252 /* now create the pin */
253 Status
= KsCreatePin(MixerData
->hDevice
, PinConnect
, DesiredAccess
, PinHandle
);
255 /* normalize status */
256 if (Status
== STATUS_SUCCESS
)
257 MixerStatus
= MM_STATUS_SUCCESS
;
259 MixerStatus
= MM_STATUS_UNSUCCESSFUL
;
262 /* free create info */
263 MixerContext
->Free(PinConnect
);
270 MMixerGetMidiInfoByIndexAndType(
271 IN PMIXER_LIST MixerList
,
272 IN ULONG DeviceIndex
,
273 IN ULONG bMidiInputType
,
274 OUT LPMIDI_INFO
*OutMidiInfo
)
277 PLIST_ENTRY Entry
, ListHead
;
278 LPMIDI_INFO MidiInfo
;
281 ListHead
= &MixerList
->MidiInList
;
283 ListHead
= &MixerList
->MidiOutList
;
285 /* get first entry */
286 Entry
= ListHead
->Flink
;
288 while(Entry
!= ListHead
)
290 MidiInfo
= (LPMIDI_INFO
)CONTAINING_RECORD(Entry
, MIDI_INFO
, Entry
);
292 if (Index
== DeviceIndex
)
294 *OutMidiInfo
= MidiInfo
;
295 return MM_STATUS_SUCCESS
;
298 Entry
= Entry
->Flink
;
301 return MM_STATUS_INVALID_PARAMETER
;
305 MMixerMidiOutCapabilities(
306 IN PMIXER_CONTEXT MixerContext
,
307 IN ULONG DeviceIndex
,
308 OUT LPMIDIOUTCAPSW Caps
)
310 PMIXER_LIST MixerList
;
312 LPMIDI_INFO MidiInfo
;
314 /* verify mixer context */
315 Status
= MMixerVerifyContext(MixerContext
);
317 if (Status
!= MM_STATUS_SUCCESS
)
319 /* invalid context passed */
323 /* grab mixer list */
324 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
326 /* find destination midi */
327 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, FALSE
, &MidiInfo
);
328 if (Status
!= MM_STATUS_SUCCESS
)
330 /* failed to find midi info */
331 return MM_STATUS_UNSUCCESSFUL
;
334 /* copy capabilities */
335 MixerContext
->Copy(Caps
, &MidiInfo
->u
.OutCaps
, sizeof(MIDIOUTCAPSW
));
337 return MM_STATUS_SUCCESS
;
341 MMixerMidiInCapabilities(
342 IN PMIXER_CONTEXT MixerContext
,
343 IN ULONG DeviceIndex
,
344 OUT LPMIDIINCAPSW Caps
)
346 PMIXER_LIST MixerList
;
348 LPMIDI_INFO MidiInfo
;
350 /* verify mixer context */
351 Status
= MMixerVerifyContext(MixerContext
);
353 if (Status
!= MM_STATUS_SUCCESS
)
355 /* invalid context passed */
359 /* grab mixer list */
360 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
362 /* find destination midi */
363 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, TRUE
, &MidiInfo
);
364 if (Status
!= MM_STATUS_SUCCESS
)
366 /* failed to find midi info */
367 return MM_STATUS_UNSUCCESSFUL
;
370 /* copy capabilities */
371 MixerContext
->Copy(Caps
, &MidiInfo
->u
.InCaps
, sizeof(MIDIINCAPSW
));
373 return MM_STATUS_SUCCESS
;
377 MMixerGetMidiDevicePath(
378 IN PMIXER_CONTEXT MixerContext
,
381 OUT LPWSTR
* DevicePath
)
383 PMIXER_LIST MixerList
;
384 LPMIXER_DATA MixerData
;
385 LPMIDI_INFO MidiInfo
;
389 /* verify mixer context */
390 Status
= MMixerVerifyContext(MixerContext
);
392 if (Status
!= MM_STATUS_SUCCESS
)
394 /* invalid context passed */
398 /* grab mixer list */
399 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
401 /* find destination midi */
402 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceId
, bMidiIn
, &MidiInfo
);
403 if (Status
!= MM_STATUS_SUCCESS
)
405 /* failed to find midi info */
406 return MM_STATUS_INVALID_PARAMETER
;
409 /* get associated device id */
410 MixerData
= MMixerGetDataByDeviceId(MixerList
, MidiInfo
->DeviceId
);
412 return MM_STATUS_INVALID_PARAMETER
;
414 /* calculate length */
415 Length
= wcslen(MixerData
->DeviceName
)+1;
417 /* allocate destination buffer */
418 *DevicePath
= MixerContext
->Alloc(Length
* sizeof(WCHAR
));
423 return MM_STATUS_NO_MEMORY
;
426 /* copy device path */
427 MixerContext
->Copy(*DevicePath
, MixerData
->DeviceName
, Length
* sizeof(WCHAR
));
430 return MM_STATUS_SUCCESS
;
435 IN PMIXER_CONTEXT MixerContext
,
442 /* setup property request */
443 Property
.Set
= KSPROPSETID_Connection
;
444 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
445 Property
.Flags
= KSPROPERTY_TYPE_SET
;
447 return MixerContext
->Control(PinHandle
, IOCTL_KS_PROPERTY
, &Property
, sizeof(KSPROPERTY
), &State
, sizeof(KSSTATE
), &Length
);
452 IN PMIXER_CONTEXT MixerContext
,
453 IN ULONG DeviceIndex
,
455 IN PIN_CREATE_CALLBACK CreateCallback
,
457 OUT PHANDLE PinHandle
)
459 PMIXER_LIST MixerList
;
461 LPMIDI_INFO MidiInfo
;
462 ACCESS_MASK DesiredAccess
= 0;
464 /* verify mixer context */
465 Status
= MMixerVerifyContext(MixerContext
);
467 if (Status
!= MM_STATUS_SUCCESS
)
469 /* invalid context passed */
473 /* grab mixer list */
474 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
476 /* find destination midi */
477 Status
= MMixerGetMidiInfoByIndexAndType(MixerList
, DeviceIndex
, bMidiIn
, &MidiInfo
);
478 if (Status
!= MM_STATUS_SUCCESS
)
480 /* failed to find midi info */
481 return MM_STATUS_INVALID_PARAMETER
;
484 /* get desired access */
487 DesiredAccess
|= GENERIC_READ
;
491 DesiredAccess
|= GENERIC_WRITE
;
494 /* now try open the pin */
495 return MMixerOpenMidiPin(MixerContext
, MixerList
, MidiInfo
->DeviceId
, MidiInfo
->PinId
, DesiredAccess
, CreateCallback
, Context
, PinHandle
);
499 MMixerGetMidiInCount(
500 IN PMIXER_CONTEXT MixerContext
)
502 PMIXER_LIST MixerList
;
505 /* verify mixer context */
506 Status
= MMixerVerifyContext(MixerContext
);
508 if (Status
!= MM_STATUS_SUCCESS
)
510 /* invalid context passed */
514 /* grab mixer list */
515 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
517 return MixerList
->MidiInListCount
;
521 MMixerGetMidiOutCount(
522 IN PMIXER_CONTEXT MixerContext
)
524 PMIXER_LIST MixerList
;
527 /* verify mixer context */
528 Status
= MMixerVerifyContext(MixerContext
);
530 if (Status
!= MM_STATUS_SUCCESS
)
532 /* invalid context passed */
536 /* grab mixer list */
537 MixerList
= (PMIXER_LIST
)MixerContext
->MixerContext
;
539 return MixerList
->MidiOutListCount
;