Eingestellte Samplingrate, Bittiefe und Mono/Stereo von Aufnahmegerät ermitteln

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Eingestellte Samplingrate, Bittiefe und Mono/Stereo von Aufnahmegerät ermitteln

    Hallo liebe Community,

    ich möchte die eingestellte Samplingrate, Bittiefe und Kanalanzahl von Aufnahmegeräten ermitteln, wie in der Sound-Systemsteuerung eingestellt (s. Screenshot).

    Gibt es da eine Möglichkeit in .NET? Hab nix dazu ergoogeln können, und in den Docs der bass.dll von Un4Seeen Developments hab ich auch nix dazu gefunden...

    Ich gehe mal stark davon aus, dass da ohne C und Interfaces nix zu machen ist??
    Bilder
    • soundsystemsteuerung.png

      40,43 kB, 888×467, 33 mal angesehen

    kafffee schrieb:

    Ich gehe mal stark davon aus, dass da ohne C und Interfaces nix zu machen ist??

    Das fürchte ich auch. Die Core Audio APIs/Interfaces (WASAPI) wäre da die erste Anlaufstelle. Schätze das es dafür sogar Nuget-Pakete gibt. Über die WinRT wäre auch ein möglicher Weg um entsprechende Geräte und deren Properties aufzulisten.

    Edit: Die "Windows Media Foundation" als möglichen Weg hab ich glatt vergessen. ;)
    Mfg -Franky-
    Geht es nur darum zu schauen was eingestellt ist?

    Dann solltest du damit an die gewollten Daten kommen:
    un4seen.com/doc/#bass/BASS_GetInfo.html
    un4seen.com/doc/#bass/BASS_INFO.html

    Wird auch in der BassNet sein.(hab ja nun auf die C-Doku verwiesen)

    Mit der BassWasapi wirst du vermutlich auch da dran kommen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @kafffee Also wenn es nur um die Default Einstellung des Default Aufnahmegerätes geht, dürfte das mit COM Interfaces relativ einfach sein. Hab es selbst noch nicht ausprobiert, sollte aber so funktionieren. Grob überschlagen. Erzeuge ein IMMDeviceEnumerator -> IMMDeviceEnumerator::GetDefaultAudioEndpoint(EDataFlow.eCapture) -> IMMDevice -> IMMDevice::Activate(IID_IAudioClient) -> IAudioClient -> IAudioClient::GetMixFormat -> Structure WAVEFORMATEX. In der WAVEFORMATEX sollten dann die derzeit eingestellten Werte wie SampleRate, Channel usw stehen. Über IMMDevice::OpenPropertyStore -> IPropertyStore kommst an weitere Eigenschaften des Gerätes wie zB. den Namen des Gerätes. Du kannst auch alle Geräte, je nach DataFlow und DeviceState auflisten. Über den IMMDeviceEnumerator::EnumAudioEndpoints(EDataFlow, DeviceState) -> IMMDeviceCollection -> ::GetCount -> ::Item -> IMMDevice usw.
    Mfg -Franky-

    kafffee schrieb:

    Werd aber ggf. nochmal drauf zurückkommen

    Kein Problem. Wobei IAudioClient::GetMixFormat doch nicht das richtige wäre. Der gibt nur die interne WAVEFORMATEX zurück, nicht die eingestellten Default-Werte. Man müsste sich die anderen Interfaces anschauen die per IMMDevice::Activate erstellt werden können ob da was passendes bei ist, das entsprechende Informationen liefert.
    Mfg -Franky-

    kafffee schrieb:

    Überseh ich etwas?


    Quellcode

    1. DWORD speakers;
    2. DWORD freq;
    3. } BASS_INFO;


    Schau mal was da in der Doku steht. Allein schon speakers, 1 = Mono, 2 = Stereo, 3 = 2.1(L/R/LFE), 4 = quadrofonie, 6 = 5.1 (RR/RL/FR/FL/C/LFE) etc.....

    PS. Da scheint aber noch die Bittiefe zu fehlen, also doch Basswasapi:
    BASS_WASAPI_GetDeviceInfo und BASS_WASAPI_INFO
    bass.radio42.com/help/html/e0e…a2b-0787-2fdd26115c38.htm
    bass.radio42.com/help/html/689…3f9-5955-ef6edc5fce27.htm
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DTF“ ()

    Schaut mal Leute was ich gefunden hab, da gibts noch eine Funktion .BASS_RecordGetInfo:

    un4seen.com/doc/#bass/BASS_RecordGetInfo.html

    Hab das hier draus gemacht, aber ich bekomm für ParseDeviceInfo immer eine leere Liste zurück. Weiss jemand was ich falsch mach? Debug.Writeline gibt erstmal keinen Fehler zurück...

    VB.NET-Quellcode

    1. Private Sub GentInfo()
    2. Bass.BASS_RecordInit(GeraetIndex)
    3. Dim info As BASS_RECORDINFO = Bass.BASS_RecordGetInfo()
    4. Debug.WriteLine("recordinfo: " & Bass.BASS_ErrorGetCode.ToString)
    5. Qualitaet = ParseDeviceInfo(info)
    6. End Sub
    7. Private Function ParseDeviceInfo(argInfo As BASS_RECORDINFO) As List(Of String)
    8. Dim retList As New List(Of String)
    9. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_1M08) Then retList.Add("11025 Hz, Mono, 8 Bit")
    10. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_1S08) Then retList.Add("11025 Hz, Stereo, 8 Bit")
    11. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_1M16) Then retList.Add("11025 Hz, Mono, 16 Bit")
    12. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_1S16) Then retList.Add("11025 Hz, Stereo, 16 Bit")
    13. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_2M08) Then retList.Add("22050 Hz, Mono, 8 Bit")
    14. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_2S08) Then retList.Add("22050 Hz, Stereo, 8 Bit")
    15. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_2M16) Then retList.Add("22050 Hz, Mono, 16 Bit")
    16. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_2S16) Then retList.Add("22050 Hz, Stereo, 16 Bit")
    17. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_4M08) Then retList.Add("44100 Hz, Mono, 8 Bit")
    18. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_4S08) Then retList.Add("44100 Hz, Stereo, 8 Bit")
    19. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_4M16) Then retList.Add("44100 Hz, Mono, 16 Bit")
    20. If argInfo.WaveFormat.HasFlag(BASSRecordFormat.WAVE_FORMAT_4S16) Then retList.Add("44100 Hz, Stereo, 16 Bit")
    21. Return retList
    22. End Function

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Ja das hatte ich auch gedacht. Eigentlich hatte ich das geprüft, also nachgeschaut in der Soundsystemsteuerung, da hätte eigentlich zumindest das letzte matchen sollen.

    Ich hab zwar auch in den Docs von Radio42 nachgeschaut und mich gewundert, wo denn die Flags mit den "höheren" Samplingraten bleiben, da scheine ich eine veraltete Seite angeschaut zu haben, ich hab nämlich komplett alle Flags eigentlich in meine Sub übertragen....

    Ich probiers nochmal mit dem Flags von deiner Seite, vielleicht hab ich auch irgendwo einen DeviceIndex falsch....
    Auf die schnelle, weil Sonntag, zusammen gezimmert und alles in einer Form. Wie immer: Keine Referenzen oder NuGet-Pakete. Ermittelt die aktuell eingestellten Werte des Default Capture Devices. Interfaces, Enums, Structs usw sind teilweise unvollständig und enthalten nur das, was benötigt wird.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Private Const S_OK As Integer = 0
    4. Private Const CLSID_MMDeviceEnumerator As String = "bcde0395-e52f-467c-8e3d-c4579291692e"
    5. Private Const IID_IMMDeviceEnumerator As String = "a95664d2-9614-4f35-a746-de8db63617e6"
    6. Private Const IID_IMMDevice As String = "d666063f-1587-4e43-81f1-b948e807363f"
    7. Private Const IID_IPropertyStore As String = "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"
    8. Private Const PKEY_AudioEngine_DeviceFormat_FMTID As String = "f19f064d-082c-4e27-bc73-6882a1bb8e4c"
    9. Private Const PKEY_AudioEngine_DeviceFormat_PID As UInteger = 0
    10. Private Enum EDATAFLOW As Integer
    11. Render = 0
    12. Capture = 1
    13. All = 2
    14. End Enum
    15. Private Enum EROLE As Integer
    16. Console = 0
    17. Multimedia = 1
    18. Communications = 2
    19. End Enum
    20. Private Enum STGM_ACCESS As Integer
    21. Read = 0
    22. Write = 1
    23. ReadWrite = 2
    24. End Enum
    25. Private Enum VARENUM As UShort 'Unvollständig
    26. VT_BLOB = 65
    27. End Enum
    28. <StructLayout(LayoutKind.Sequential, Pack:=1)>
    29. Private Structure WAVEFORMATEX
    30. Dim wFormatTag As UShort
    31. Dim nChannels As UShort
    32. Dim nSamplesPerSec As UInteger
    33. Dim nAvgBytesPerSec As UInteger
    34. Dim nBlockAlign As UShort
    35. Dim wBitsPerSample As UShort
    36. Dim cbSize As UShort
    37. End Structure
    38. Private Structure PROPERTYKEY
    39. Dim fmtid As Guid
    40. Dim pid As UInteger
    41. End Structure
    42. Private Structure CArray
    43. Dim cElems As UInteger
    44. Dim pElems As IntPtr
    45. End Structure
    46. <StructLayout(LayoutKind.Explicit, Size:=16)> 'Unvollständig
    47. Private Structure PROPVARIANT
    48. <FieldOffset(0)> Dim vt As VARENUM
    49. <FieldOffset(2)> Dim wReserved1 As UShort
    50. <FieldOffset(4)> Dim wReserved2 As UShort
    51. <FieldOffset(6)> Dim wReserved3 As UShort
    52. <FieldOffset(8)> Dim cArray As CArray
    53. End Structure
    54. <DllImport("Ole32.dll", EntryPoint:="PropVariantClear")>
    55. <PreserveSig> Private Shared Function PropVariantClear(<[In]> ByRef pvar As PROPVARIANT) As Integer
    56. End Function
    57. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    58. Dim MMDeviceEnumerator As IMMDeviceEnumerator = CType(Activator.CreateInstance(Type.GetTypeFromCLSID(New Guid(CLSID_MMDeviceEnumerator))), IMMDeviceEnumerator)
    59. If MMDeviceEnumerator IsNot Nothing Then
    60. Dim MMDevice As IMMDevice = Nothing
    61. If MMDeviceEnumerator.GetDefaultAudioEndpoint(EDATAFLOW.Capture, EROLE.Multimedia, MMDevice) = S_OK Then
    62. Dim PropertyStore As IPropertyStore = Nothing
    63. If MMDevice.OpenPropertyStore(STGM_ACCESS.Read, PropertyStore) = S_OK Then
    64. Dim PropKey As New PROPERTYKEY With {
    65. .fmtid = New Guid(PKEY_AudioEngine_DeviceFormat_FMTID),
    66. .pid = PKEY_AudioEngine_DeviceFormat_PID
    67. }
    68. Dim PropVar As New PROPVARIANT
    69. If PropertyStore.GetValue(PropKey, PropVar) = S_OK Then
    70. If PropVar.vt = VARENUM.VT_BLOB Then
    71. Dim CurrentFormat As WAVEFORMATEX = CType(Marshal.PtrToStructure(PropVar.cArray.pElems,
    72. GetType(WAVEFORMATEX)),
    73. WAVEFORMATEX)
    74. Debug.Print("Current Channels = " & CurrentFormat.nChannels.ToString)
    75. Debug.Print("Current SamplesPerSec = " & CurrentFormat.nSamplesPerSec.ToString)
    76. Debug.Print("Current BitsPerSample = " & CurrentFormat.wBitsPerSample.ToString)
    77. End If
    78. PropVariantClear(PropVar)
    79. End If
    80. Marshal.ReleaseComObject(PropertyStore)
    81. End If
    82. Marshal.ReleaseComObject(MMDevice)
    83. End If
    84. Marshal.ReleaseComObject(MMDeviceEnumerator)
    85. End If
    86. End Sub
    87. <ComImport>
    88. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    89. <Guid(IID_IMMDeviceEnumerator)>
    90. Private Interface IMMDeviceEnumerator
    91. <PreserveSig> Function EnumAudioEndpoints() As Integer 'Dummy
    92. <PreserveSig> Function GetDefaultAudioEndpoint(<[In]> dataFlow As EDATAFLOW,
    93. <[In]> role As EROLE,
    94. <Out, MarshalAs(UnmanagedType.Interface)> ByRef ppEndpoint As IMMDevice) As Integer
    95. <PreserveSig> Function GetDevice() As Integer 'Dummy
    96. <PreserveSig> Function RegisterEndpointNotificationCallback() As Integer 'Dummy
    97. <PreserveSig> Function UnregisterEndpointNotificationCallback() As Integer 'Dummy
    98. End Interface
    99. <ComImport>
    100. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    101. <Guid(IID_IMMDevice)>
    102. Private Interface IMMDevice
    103. <PreserveSig> Function Activate() As Integer 'Dummy
    104. <PreserveSig> Function OpenPropertyStore(<[In]> stgmAccess As STGM_ACCESS,
    105. <Out, MarshalAs(UnmanagedType.Interface)> ByRef ppProperties As IPropertyStore) As Integer
    106. <PreserveSig> Function GetId() As Integer 'Dummy
    107. <PreserveSig> Function GetState() As Integer 'Dummy
    108. End Interface
    109. <ComImport>
    110. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    111. <Guid(IID_IPropertyStore)>
    112. Private Interface IPropertyStore
    113. <PreserveSig> Function GetCount() As Integer 'Dummy
    114. <PreserveSig> Function GetAt() As Integer 'Dummy
    115. <PreserveSig> Function GetValue(<[In]> ByRef pkey As PROPERTYKEY,
    116. <Out> ByRef pv As PROPVARIANT) As Integer
    117. <PreserveSig> Function SetValue() As Integer 'Dummy
    118. <PreserveSig> Function Commit() As Integer 'Dummy
    119. End Interface
    120. End Class


    Ansonsten: IMMDeviceEnumerator::EnumAudioEndpoints(EDataFlow, DeviceState) -> IMMDeviceCollection -> ::GetCount -> ::Item -> IMMDevice -> IMMDevice::OpenPropertyStore -> IPropertyStore -> ::GetCount -> ::GetAt falls Du alle Properties von allen Geräten, je nach DataFlow und DeviceState, auslesen möchtest.
    Mfg -Franky-
    @DTF

    Der Fehler scheint in der bass.dll zu liegen, s. Screenshot. Aber echt komisch, ich hab sechs Aufnahmegeräte und bei keinem davon funktioniert es, den GeraeteIndex hab ich auch nochmal gecheckt...

    @-Franky-

    Ja ich brauch tatsächlich alle Eigenschaften von allen Geräten. Ich poste obiges Problem mal noch bei Un4Seen und wenn sich da herausstellt, dass das so nicht geht, dann probier ichs mal mit deinem.
    Bilder
    • ErrorSampleRate.png

      76,91 kB, 910×435, 15 mal angesehen

    kafffee schrieb:

    Ja ich brauch tatsächlich alle Eigenschaften von allen Geräten.
    Über den IPropertyStore kann man schon diverse Eigenschaften, wie z.B. auch den Namen des Gerätes, auslesen. Ein paar PKeys dazu findest Du hier: learn.microsoft.com/en-us/wind…reaudio/device-properties bzw. hier: learn.microsoft.com/en-us/wind…audio-endpoint-properties Das was Du noch suchst könnte sich unter IMMDevice::Activate(IID_ISpatialAudioClient) -> ISpatialAudioClient -> ISpatialAudioClient::GetSupportedAudioObjectFormatEnumerator -> IAudioFormatEnumerator::GetCount/::GetFormat -> WAVEFORMATEX befinden. Hab das aber bisher selbst nicht benötigt. Daher keine Garantie das Du hier an alle möglichen Werte kommst, die Du auch unter Windows sehen kannst. Da hilft nur ausprobieren.
    Mfg -Franky-

    Neu

    Okay ich hab mal mit Un4Seen Rücksprache gehalten, man kann ja die Member .freq für die Samplingrate hernehmen und .Channels wenn man wissen will ob Mono oder Stereo.

    Die Bittiefe kann man wie ich das verstanden hab, selbst festlegen mit den Flags BASSFlag.BASS_DEFAULT (16 Bits) und BASSFlag.BASS_SAMPLE_8BITS (8 Bits).

    Das genügt für meine Ansprüche völlig, dass man vom ausgewählten Aufnahmegerät die in der Systemsteuerung gesetzten Eigenschaften abfragen kann.

    Das mit den WaveFormat-Flags funktioniert wohl nur auf sehr alten Windows-Versionen (Windows XP und älter).

    Danke :)