gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pa_win_wdmks_utils.c (11563B)


      1 /*
      2  * PortAudio Portable Real-Time Audio Library
      3  * Windows WDM KS utilities
      4  *
      5  * Copyright (c) 1999 - 2007 Andrew Baldwin, Ross Bencina
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining
      8  * a copy of this software and associated documentation files
      9  * (the "Software"), to deal in the Software without restriction,
     10  * including without limitation the rights to use, copy, modify, merge,
     11  * publish, distribute, sublicense, and/or sell copies of the Software,
     12  * and to permit persons to whom the Software is furnished to do so,
     13  * subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be
     16  * included in all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     23  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  */
     26 
     27 /*
     28  * The text above constitutes the entire PortAudio license; however, 
     29  * the PortAudio community also makes the following non-binding requests:
     30  *
     31  * Any person wishing to distribute modifications to the Software is
     32  * requested to send the modifications to the original developer so that
     33  * they can be incorporated into the canonical version. It is also 
     34  * requested that these non-binding requests be included along with the 
     35  * license above.
     36  */
     37 
     38 #include <windows.h>
     39 #include <mmreg.h>
     40 #ifndef WAVE_FORMAT_IEEE_FLOAT
     41     #define WAVE_FORMAT_IEEE_FLOAT 0x0003   // MinGW32 does not define this
     42 #endif    
     43 #ifndef _WAVEFORMATEXTENSIBLE_
     44     #define _WAVEFORMATEXTENSIBLE_          // MinGW32 does not define this
     45 #endif
     46 #ifndef _INC_MMREG
     47     #define _INC_MMREG                      // for STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
     48 #endif
     49 #include <winioctl.h>						// MinGW32 does not define this automatically
     50 
     51 #if defined(__GNUC__)
     52 
     53 #include "../../hostapi/wasapi/mingw-include/ks.h"
     54 #include "../../hostapi/wasapi/mingw-include/ksmedia.h"
     55 
     56 #else
     57 
     58 #include <ks.h>
     59 #include <ksmedia.h>
     60 
     61 #endif
     62 
     63 #include <stdio.h>                          // just for some development printfs
     64 
     65 #include "portaudio.h"
     66 #include "pa_util.h"
     67 #include "pa_win_wdmks_utils.h"
     68 
     69 
     70 /* PortAudio-local instances of GUIDs previously sourced from ksguid.lib */
     71 
     72 /* GUID KSDATAFORMAT_TYPE_AUDIO */
     73 static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO };
     74 
     75 /* GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT */
     76 static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT };
     77 
     78 /* GUID KSDATAFORMAT_SUBTYPE_PCM */
     79 static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM };
     80 
     81 /* GUID KSDATAFORMAT_SUBTYPE_WAVEFORMATEX */
     82 static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX };
     83 
     84 /* GUID KSMEDIUMSETID_Standard */
     85 static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard };
     86 
     87 /* GUID KSINTERFACESETID_Standard */
     88 static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard };
     89 
     90 /* GUID KSPROPSETID_Pin */
     91 static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin };
     92 
     93 #define pa_IS_VALID_WAVEFORMATEX_GUID(Guid)\
     94     (!memcmp(((PUSHORT)&pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, ((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT)))
     95 
     96 
     97 static PaError WdmGetPinPropertySimple(
     98     HANDLE  handle,
     99     unsigned long pinId,
    100     unsigned long property,
    101     void* value,
    102     unsigned long valueSize )
    103 {
    104     DWORD bytesReturned;
    105     KSP_PIN ksPProp;
    106     ksPProp.Property.Set = pa_KSPROPSETID_Pin;
    107     ksPProp.Property.Id = property;
    108     ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
    109     ksPProp.PinId = pinId;
    110     ksPProp.Reserved = 0;
    111 
    112     if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN),
    113             value, valueSize, &bytesReturned, NULL ) == 0 || bytesReturned != valueSize )
    114     {
    115         return paUnanticipatedHostError;
    116     }
    117     else
    118     {
    119         return paNoError;
    120     }
    121 }
    122 
    123 
    124 static PaError WdmGetPinPropertyMulti(
    125     HANDLE handle,
    126     unsigned long pinId,
    127     unsigned long property,
    128     KSMULTIPLE_ITEM** ksMultipleItem)
    129 {
    130     unsigned long multipleItemSize = 0;
    131     KSP_PIN ksPProp;
    132     DWORD bytesReturned;
    133 
    134     *ksMultipleItem = 0;
    135 
    136     ksPProp.Property.Set = pa_KSPROPSETID_Pin;
    137     ksPProp.Property.Id = property;
    138     ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
    139     ksPProp.PinId = pinId;
    140     ksPProp.Reserved = 0;
    141 
    142     if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property,
    143             sizeof(KSP_PIN), NULL, 0, &multipleItemSize, NULL ) == 0 && GetLastError() != ERROR_MORE_DATA )
    144     {
    145         return paUnanticipatedHostError;
    146     }
    147 
    148     *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
    149     if( !*ksMultipleItem )
    150     {
    151         return paInsufficientMemory;
    152     }
    153 
    154     if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN),
    155             (void*)*ksMultipleItem,  multipleItemSize, &bytesReturned, NULL ) == 0 || bytesReturned != multipleItemSize )
    156     {
    157         PaUtil_FreeMemory( ksMultipleItem );
    158         return paUnanticipatedHostError;
    159     }
    160 
    161     return paNoError;
    162 }
    163 
    164 
    165 static int GetKSFilterPinCount( HANDLE deviceHandle )
    166 {
    167     DWORD result;
    168 
    169     if( WdmGetPinPropertySimple( deviceHandle, 0, KSPROPERTY_PIN_CTYPES, &result, sizeof(result) ) == paNoError ){
    170         return result;
    171     }else{
    172         return 0;
    173     }
    174 }
    175 
    176 
    177 static KSPIN_COMMUNICATION GetKSFilterPinPropertyCommunication( HANDLE deviceHandle, int pinId )
    178 {
    179     KSPIN_COMMUNICATION result;
    180 
    181     if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_COMMUNICATION, &result, sizeof(result) ) == paNoError ){
    182         return result;
    183     }else{
    184         return KSPIN_COMMUNICATION_NONE;
    185     }
    186 }
    187 
    188 
    189 static KSPIN_DATAFLOW GetKSFilterPinPropertyDataflow( HANDLE deviceHandle, int pinId )
    190 {
    191     KSPIN_DATAFLOW result;
    192 
    193     if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_DATAFLOW, &result, sizeof(result) ) == paNoError ){
    194         return result;
    195     }else{
    196         return (KSPIN_DATAFLOW)0;
    197     }
    198 }
    199 
    200 
    201 static int KSFilterPinPropertyIdentifiersInclude( 
    202         HANDLE deviceHandle, int pinId, unsigned long property, const GUID *identifierSet, unsigned long identifierId  )
    203 {
    204     KSMULTIPLE_ITEM* item = NULL;
    205     KSIDENTIFIER* identifier;
    206     int i;
    207     int result = 0;
    208 
    209     if( WdmGetPinPropertyMulti( deviceHandle, pinId, property, &item) != paNoError )
    210         return 0;
    211     
    212     identifier = (KSIDENTIFIER*)(item+1);
    213 
    214     for( i = 0; i < (int)item->Count; i++ )
    215     {
    216         if( !memcmp( (void*)&identifier[i].Set, (void*)identifierSet, sizeof( GUID ) ) &&
    217            ( identifier[i].Id == identifierId ) )
    218         {
    219             result = 1;
    220             break;
    221         }
    222     }
    223 
    224     PaUtil_FreeMemory( item );
    225 
    226     return result;
    227 }
    228 
    229 
    230 /* return the maximum channel count supported by any pin on the device. 
    231    if isInput is non-zero we query input pins, otherwise output pins.
    232 */
    233 int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput )
    234 {
    235     HANDLE deviceHandle;
    236 	ULONG i;
    237     int pinCount, pinId;
    238     int result = 0;
    239     KSPIN_DATAFLOW requiredDataflowDirection = (isInput ? KSPIN_DATAFLOW_OUT : KSPIN_DATAFLOW_IN );
    240     
    241     if( !wcharDevicePath )
    242         return 0;
    243 
    244     deviceHandle = CreateFileW( (LPCWSTR)wcharDevicePath, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
    245     if( deviceHandle == INVALID_HANDLE_VALUE )
    246         return 0;
    247 
    248     pinCount = GetKSFilterPinCount( deviceHandle );
    249     for( pinId = 0; pinId < pinCount; ++pinId )
    250     {
    251         KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication( deviceHandle, pinId );
    252         KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow( deviceHandle, pinId );
    253         if( ( dataflow == requiredDataflowDirection ) &&
    254                 (( communication == KSPIN_COMMUNICATION_SINK) ||
    255                  ( communication == KSPIN_COMMUNICATION_BOTH)) 
    256              && ( KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 
    257                     KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING )
    258                 || KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 
    259                     KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING ) )
    260              && KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 
    261                     KSPROPERTY_PIN_MEDIUMS, &pa_KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO ) )
    262          {
    263             KSMULTIPLE_ITEM* item = NULL;
    264             if( WdmGetPinPropertyMulti( deviceHandle, pinId, KSPROPERTY_PIN_DATARANGES, &item ) == paNoError )
    265             {
    266                 KSDATARANGE *dataRange = (KSDATARANGE*)(item+1);
    267 
    268                 for( i=0; i < item->Count; ++i ){
    269 
    270                     if( pa_IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat)
    271                             || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0
    272                             || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0
    273                             || ( ( memcmp( (void*)&dataRange->MajorFormat, (void*)&pa_KSDATAFORMAT_TYPE_AUDIO, sizeof(GUID) ) == 0 )
    274                                 && ( memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof(GUID) ) == 0 ) ) )
    275                     {
    276                         KSDATARANGE_AUDIO *dataRangeAudio = (KSDATARANGE_AUDIO*)dataRange;
    277                         
    278                         /*
    279                         printf( ">>> %d %d %d %d %S\n", isInput, dataflow, communication, dataRangeAudio->MaximumChannels, devicePath );
    280                        
    281                         if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, sizeof(GUID) ) == 0 )
    282                             printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WAVEFORMATEX\n" );
    283                         else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_DSOUND, sizeof(GUID) ) == 0 )
    284                             printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_DSOUND\n" );
    285                         else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WILDCARD, sizeof(GUID) ) == 0 )
    286                             printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WILDCARD\n" );
    287                         else
    288                             printf( "\tspecifier: ?\n" );
    289                         */
    290 
    291                         /*
    292                             We assume that very high values for MaximumChannels are not useful and indicate
    293                             that the driver isn't prepared to tell us the real number of channels which it supports.
    294                         */
    295                         if( dataRangeAudio->MaximumChannels  < 0xFFFFUL && (int)dataRangeAudio->MaximumChannels > result )
    296                             result = (int)dataRangeAudio->MaximumChannels;
    297                     }
    298                     
    299                     dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
    300                 }
    301 
    302                 PaUtil_FreeMemory( item );
    303             }
    304         }
    305     }
    306     
    307     CloseHandle( deviceHandle );
    308     return result;
    309 }