Browse Source

Implemented classes for some missing interfaces needed to navigate device topology

pull/1016/head
Kirill Gribunin 2 years ago
parent
commit
76dc69e4e4
  1. 31
      NAudio.Wasapi/CoreAudioApi/AudioMute.cs
  2. 58
      NAudio.Wasapi/CoreAudioApi/AudioVolumeLevel.cs
  3. 8
      NAudio.Wasapi/CoreAudioApi/Connector.cs
  4. 21
      NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioAutoGainControl.cs
  5. 22
      NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioMute.cs
  6. 15
      NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioVolumeLevel.cs
  7. 18
      NAudio.Wasapi/CoreAudioApi/Interfaces/IControlChangeNotify.cs
  8. 14
      NAudio.Wasapi/CoreAudioApi/Interfaces/IControlInterface.cs
  9. 17
      NAudio.Wasapi/CoreAudioApi/Interfaces/IKsJackDescription.cs
  10. 83
      NAudio.Wasapi/CoreAudioApi/Interfaces/IPart.cs
  11. 20
      NAudio.Wasapi/CoreAudioApi/Interfaces/IPerChannelDbLevel.cs
  12. 17
      NAudio.Wasapi/CoreAudioApi/Interfaces/PartType.cs
  13. 35
      NAudio.Wasapi/CoreAudioApi/KsJackDescription.cs
  14. 150
      NAudio.Wasapi/CoreAudioApi/Part.cs
  15. 45
      NAudio.Wasapi/CoreAudioApi/PartsList.cs
  16. 87
      NAudioDemo/DeviceTopology/DeviceTopologyPanel.Designer.cs
  17. 189
      NAudioDemo/DeviceTopology/DeviceTopologyPanel.cs
  18. 60
      NAudioDemo/DeviceTopology/DeviceTopologyPanel.resx
  19. 22
      NAudioDemo/DeviceTopology/DeviceTopologyPlugin.cs

31
NAudio.Wasapi/CoreAudioApi/AudioMute.cs

@ -0,0 +1,31 @@
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Wasapi.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
public class AudioMute
{
private IAudioMute audioMuteInterface;
internal AudioMute(IAudioMute audioMute)
{
audioMuteInterface = audioMute;
}
public bool IsMuted
{
get
{
audioMuteInterface.GetMute(out var result);
return result;
}
set
{
var guid = Guid.Empty;
audioMuteInterface.SetMute(value, guid);
}
}
}
}

58
NAudio.Wasapi/CoreAudioApi/AudioVolumeLevel.cs

@ -0,0 +1,58 @@
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Wasapi.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.Wasapi.CoreAudioApi
{
public class AudioVolumeLevel
{
private readonly IAudioVolumeLevel audioVolumeLevelInterface;
private bool isLevelRangeRead = false;
private float minLevelDb, maxLevelDb, stepping;
internal AudioVolumeLevel(IAudioVolumeLevel audioVolumeLevel)
{
audioVolumeLevelInterface = audioVolumeLevel;
}
public uint ChannelCount
{
get
{
audioVolumeLevelInterface.GetChannelCount(out uint result);
return result;
}
}
public void GetLevelRange(uint channel, out float minLevelDb, out float maxLevelDb, out float stepping)
{
audioVolumeLevelInterface.GetLevelRange(channel, out minLevelDb, out maxLevelDb, out stepping);
}
public float GetLevel(uint channel)
{
audioVolumeLevelInterface.GetLevel(channel, out float result);
return result;
}
public void SetLevel(uint channel, float value)
{
var guid = Guid.Empty;
audioVolumeLevelInterface.SetLevel(channel, value, ref guid);
}
public void SetLevelUniform(float value)
{
var guid = Guid.Empty;
audioVolumeLevelInterface.SetLevelUniform(value, ref guid);
}
public void SetLevelAllChannel(float[] values, uint channels)
{
var guid = Guid.Empty;
audioVolumeLevelInterface.SetLevelAllChannel(values, channels, ref guid);
}
}
}

8
NAudio.Wasapi/CoreAudioApi/Connector.cs

@ -100,6 +100,14 @@ namespace NAudio.CoreAudioApi
connectorInterface.GetDeviceIdConnectedTo(out var result);
return result;
}
}
public Part Part
{
get
{
return new Part(connectorInterface as IPart);
}
}
}
}

21
NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioAutoGainControl.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("85401FD4-6DE4-4b9d-9869-2D6753A82F3C"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IAudioAutoGainControl
{
[PreserveSig]
int GetEnabled(
[Out, MarshalAs(UnmanagedType.Bool)] out bool enabled);
[PreserveSig]
int SetEnabled(
[In, MarshalAs(UnmanagedType.Bool)] bool enabled);
}
}

22
NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioMute.cs

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("DF45AEEA-B74A-4B6B-AFAD-2366B6AA012E"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IAudioMute
{
[PreserveSig]
int GetMute(
[Out, MarshalAs(UnmanagedType.Bool)] out bool mute);
[PreserveSig]
int SetMute(
[In, MarshalAs(UnmanagedType.Bool)] bool mute,
[In] ref Guid eventContext);
}
}

15
NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioVolumeLevel.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IAudioVolumeLevel : IPerChannelDbLevel
{
}
}

18
NAudio.Wasapi/CoreAudioApi/Interfaces/IControlChangeNotify.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.Wasapi.CoreAudioApi.Interfaces
{
[Guid("9c2c4058-23f5-41de-877a-df3af236a09e"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
interface IControlChangeNotify
{
[PreserveSig]
int OnNotify(
[In] uint controlId,
[In] IntPtr context);
}
}

14
NAudio.Wasapi/CoreAudioApi/Interfaces/IControlInterface.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("45d37c3f-5140-444a-ae24-400789f3cbf3"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
public interface IControlInterface
{
}
}

17
NAudio.Wasapi/CoreAudioApi/Interfaces/IKsJackDescription.cs

@ -0,0 +1,17 @@
using NAudio.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("4509F757-2D46-4637-8E62-CE7DB944F57B"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IKsJackDescription
{
int GetJackCount([Out] out uint jacks);
int GetJackDescription([In] uint jack, [Out, MarshalAs(UnmanagedType.LPWStr)] out string description);
};
}

83
NAudio.Wasapi/CoreAudioApi/Interfaces/IPart.cs

@ -1,19 +1,64 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// Windows CoreAudio IPart interface
/// Defined in devicetopology.h
/// </summary>
[Guid("AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IPart
{
// Stub, Not implemented
}
}
using NAudio.Wasapi.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// Windows CoreAudio IPart interface
/// Defined in devicetopology.h
/// </summary>
[Guid("AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IPart
{
int GetName(
[Out, MarshalAs(UnmanagedType.LPWStr)] out string name);
int GetLocalId(
[Out] out uint id);
int GetGlobalId(
[Out, MarshalAs(UnmanagedType.LPWStr)] out string id);
int GetPartType(
[Out] out PartTypeEnum partType);
int GetSubType(
out Guid subType);
int GetControlInterfaceCount(
[Out] out uint count);
int GetControlInterface(
[In] uint index,
[Out, MarshalAs(UnmanagedType.IUnknown)] out IControlInterface controlInterface);
[PreserveSig]
int EnumPartsIncoming(
[Out] out IPartsList parts);
[PreserveSig]
int EnumPartsOutgoing(
[Out] out IPartsList parts);
int GetTopologyObject(
[Out] out object topologyObject);
[PreserveSig]
int Activate(
[In] ClsCtx dwClsContext,
[In] ref Guid refiid,
[MarshalAs(UnmanagedType.IUnknown)] out object interfacePointer);
int RegisterControlChangeCallback(
[In] ref Guid refiid,
[In] IControlChangeNotify notify);
int UnregisterControlChangeCallback(
[In] IControlChangeNotify notify);
}
}

20
NAudio.Wasapi/CoreAudioApi/Interfaces/IPerChannelDbLevel.cs

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
[Guid("7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComImport]
internal interface IPerChannelDbLevel
{
int GetChannelCount(out uint channels);
int GetLevelRange(uint channel, out float minLevelDb, out float maxLevelDb, out float stepping);
int GetLevel(uint channel, out float levelDb);
int SetLevel(uint channel, float levelDb, ref Guid eventGuidContext);
int SetLevelUniform(float levelDb, ref Guid eventGuidContext);
int SetLevelAllChannel(float[] levelsDb, uint channels, ref Guid eventGuidContext);
}
}

17
NAudio.Wasapi/CoreAudioApi/Interfaces/PartType.cs

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
public enum PartTypeEnum
{
Connector = 0,
Subunit = 1,
HardwarePeriphery = 2,
SoftwareDriver = 3,
Splitter = 4,
Category = 5,
Other = 6
}
}

35
NAudio.Wasapi/CoreAudioApi/KsJackDescription.cs

@ -0,0 +1,35 @@
using NAudio.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
public class KsJackDescription
{
private readonly IKsJackDescription ksJackDescriptionInterface;
internal KsJackDescription(IKsJackDescription ksJackDescription)
{
ksJackDescriptionInterface = ksJackDescription;
}
public uint Count
{
get
{
ksJackDescriptionInterface.GetJackCount(out var result);
return result;
}
}
public string this[uint index]
{
get
{
ksJackDescriptionInterface.GetJackDescription(index, out var result);
return result;
}
}
}
}

150
NAudio.Wasapi/CoreAudioApi/Part.cs

@ -0,0 +1,150 @@
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Wasapi.CoreAudioApi;
using NAudio.Wasapi.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace NAudio.CoreAudioApi
{
public class Part
{
private const int E_NOTFOUND = unchecked((int)0x80070490);
private readonly IPart partInterface;
private DeviceTopology deviceTopology;
private static Guid IID_IAudioVolumeLevel = new Guid("7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC");
private static Guid IID_IAudioMute = new Guid("DF45AEEA-B74A-4B6B-AFAD-2366B6AA012E");
private static Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A");
private static Guid IID_IKsJackDescription = new Guid("4509F757-2D46-4637-8E62-CE7DB944F57B");
internal Part(IPart part)
{
partInterface = part;
}
public string Name
{
get
{
partInterface.GetName(out var result);
return result;
}
}
public uint LocalId
{
get
{
partInterface.GetLocalId(out var result);
return result;
}
}
public string GlobalId
{
get
{
partInterface.GetGlobalId(out var result);
return result;
}
}
public PartTypeEnum PartType
{
get
{
partInterface.GetPartType(out var result);
return result;
}
}
public Guid GetSubType
{
get
{
partInterface.GetSubType(out var result);
return result;
}
}
public uint ControlInterfaceCount
{
get
{
partInterface.GetControlInterfaceCount(out var result);
return result;
}
}
public IControlInterface GetControlInterface(uint index)
{
partInterface.GetControlInterface(index, out var result);
return result;
}
public PartsList PartsIncoming
{
get
{
var hr = partInterface.EnumPartsIncoming(out var result);
return hr == 0 ? new PartsList(result) : hr == E_NOTFOUND ? new PartsList(null) : throw new COMException(nameof(IPart.EnumPartsIncoming), hr);
}
}
public PartsList PartsOutgoing
{
get
{
var hr = partInterface.EnumPartsOutgoing(out var result);
return hr == 0 ? new PartsList(result) : hr == E_NOTFOUND ? new PartsList(null) : throw new COMException(nameof(IPart.EnumPartsOutgoing), hr);
}
}
public DeviceTopology DeviceTopology
{
get
{
if (deviceTopology == null)
{
GetDeviceTopology();
}
return deviceTopology;
}
}
public AudioVolumeLevel AudioVolumeLevel
{
get
{
var hr = partInterface.Activate(ClsCtx.ALL, ref IID_IAudioVolumeLevel, out var result);
return hr == 0 ? new AudioVolumeLevel(result as IAudioVolumeLevel) : null;
}
}
public AudioMute AudioMute
{
get
{
var hr = partInterface.Activate(ClsCtx.ALL, ref IID_IAudioMute, out var result);
return hr == 0 ? new AudioMute(result as IAudioMute) : null;
}
}
public KsJackDescription JackDescription
{
get
{
var hr = partInterface.Activate(ClsCtx.ALL, ref IID_IKsJackDescription, out var result);
return hr == 0 ? new KsJackDescription(result as IKsJackDescription) : null;
}
}
private void GetDeviceTopology()
{
Marshal.ThrowExceptionForHR(partInterface.GetTopologyObject(out var result));
deviceTopology = new DeviceTopology(result as IDeviceTopology);
}
}
}

45
NAudio.Wasapi/CoreAudioApi/PartsList.cs

@ -0,0 +1,45 @@
using NAudio.CoreAudioApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
public class PartsList
{
private IPartsList partsListInterface;
internal PartsList(IPartsList partsList)
{
partsListInterface = partsList;
}
public uint Count
{
get
{
uint result = 0;
if (partsListInterface != null)
{
partsListInterface.GetCount(out result);
}
return result;
}
}
public Part this[uint index]
{
get
{
if (partsListInterface == null)
{
throw new IndexOutOfRangeException();
}
partsListInterface.GetPart(index, out IPart part);
return new Part(part);
}
}
}
}

87
NAudioDemo/DeviceTopology/DeviceTopologyPanel.Designer.cs

@ -0,0 +1,87 @@
namespace NAudioDemo.DeviceTopology
{
partial class DeviceTopologyPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lblSelectDevice = new System.Windows.Forms.Label();
this.cbDevices = new System.Windows.Forms.ComboBox();
this.tbTopology = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// lblSelectDevice
//
this.lblSelectDevice.AutoSize = true;
this.lblSelectDevice.Dock = System.Windows.Forms.DockStyle.Top;
this.lblSelectDevice.Location = new System.Drawing.Point(0, 0);
this.lblSelectDevice.Name = "lblSelectDevice";
this.lblSelectDevice.Size = new System.Drawing.Size(111, 15);
this.lblSelectDevice.TabIndex = 0;
this.lblSelectDevice.Text = "Select audio device:";
//
// cbDevices
//
this.cbDevices.Dock = System.Windows.Forms.DockStyle.Top;
this.cbDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cbDevices.FormattingEnabled = true;
this.cbDevices.Location = new System.Drawing.Point(0, 15);
this.cbDevices.Name = "cbDevices";
this.cbDevices.Size = new System.Drawing.Size(1013, 23);
this.cbDevices.TabIndex = 1;
this.cbDevices.SelectedValueChanged += new System.EventHandler(this.cbDevices_SelectedValueChanged);
//
// tbTopology
//
this.tbTopology.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbTopology.Location = new System.Drawing.Point(0, 38);
this.tbTopology.Multiline = true;
this.tbTopology.Name = "tbTopology";
this.tbTopology.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.tbTopology.Size = new System.Drawing.Size(1013, 483);
this.tbTopology.TabIndex = 2;
//
// DeviceTopologyPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tbTopology);
this.Controls.Add(this.cbDevices);
this.Controls.Add(this.lblSelectDevice);
this.Name = "DeviceTopologyPanel";
this.Size = new System.Drawing.Size(1013, 521);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lblSelectDevice;
private System.Windows.Forms.ComboBox cbDevices;
private System.Windows.Forms.TextBox tbTopology;
}
}

189
NAudioDemo/DeviceTopology/DeviceTopologyPanel.cs

@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NAudio.CoreAudioApi;
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Wasapi.CoreAudioApi;
namespace NAudioDemo.DeviceTopology
{
public partial class DeviceTopologyPanel : UserControl
{
class AudioVolumeWrapper
{
public uint Channel { get; set; }
public AudioVolumeLevel AudioVolumeLevel { get; set; }
}
public DeviceTopologyPanel()
{
InitializeComponent();
foreach (var device in GetCaptureDevices())
{
cbDevices.Items.Add(device);
}
foreach (var device in GetRenderDevices())
{
cbDevices.Items.Add(device);
}
if (cbDevices.Items.Count > 0)
{
cbDevices.SelectedIndex = 0;
}
}
public IEnumerable<MMDevice> GetCaptureDevices()
{
using (var enumerator = new MMDeviceEnumerator())
{
var audioEndPoints = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);
foreach (var device in audioEndPoints)
{
yield return device;
}
}
}
public IEnumerable<MMDevice> GetRenderDevices()
{
using (var enumerator = new MMDeviceEnumerator())
{
var audioEndPoints = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active);
foreach (var device in audioEndPoints)
{
yield return device;
}
}
}
private void cbDevices_SelectedValueChanged(object sender, EventArgs e)
{
var device = (MMDevice)cbDevices.SelectedItem;
var topology = device.DeviceTopology;
var connector = topology.GetConnector(0);
var deviceConnector = connector.ConnectedTo;
tbTopology.Text = "";
_superMixBox = null;
WalkParts(deviceConnector.Part, device.DataFlow == DataFlow.Render, "");
}
private bool HasVolumeOrMuteParts(Part part)
{
if (part.Name == "Volume" || part.Name == "Mute")
{
return true;
}
for (uint i = 0; i < part.PartsIncoming.Count; i++)
{
if (HasVolumeOrMuteParts(part.PartsIncoming[i]))
{
return true;
}
}
return false;
}
private void WalkParts(Part part, bool isRenderDevice, string indent)
{
var audioVolumeLevel = part.AudioVolumeLevel;
var audioMute = part.AudioMute;
var jackDescription = part.JackDescription;
var s = "\r\n";
if (audioVolumeLevel != null)
{
s = $" (audio volume level)\r\n";
for (uint i = 0; i < audioVolumeLevel.ChannelCount; i++)
{
audioVolumeLevel.GetLevelRange(i, out var minLevelDb, out var maxLevelDb, out var stepping);
var volume = audioVolumeLevel.GetLevel(i);
s += $"{indent}Channel: {i}, Min {minLevelDb:0.##} dB, Max {maxLevelDb:0.##} dB, stepping {stepping:0.##} dB: {volume:0.##} dB\r\n";
}
}
else if (audioMute != null)
{
s = $" (audio mute. Muted: {audioMute.IsMuted})\r\n";
} if (jackDescription != null)
{
s = $" (Jacks: {jackDescription.Count})\r\n";
}
tbTopology.AppendText($"{indent}{part.PartType}: {part.Name}{s}");
if (part.Name.ToLowerInvariant() == "supermix")
{
if (isRenderDevice && HasVolumeOrMuteParts(part))
{
_superMixBox = new GroupBox
{
Text = $"Supermix",
Dock = DockStyle.Top
};
}
}
var parts = isRenderDevice ? part.PartsIncoming : part.PartsOutgoing;
for (uint i = 0; i < parts.Count; i++)
{
var outgoingPart = parts[i];
WalkParts(outgoingPart, isRenderDevice, indent + " ");
}
}
private void Tb_ValueChanged(object sender, EventArgs e)
{
var trackBar = (TrackBar)sender;
var wrapper = (AudioVolumeWrapper)trackBar.Tag;
wrapper.AudioVolumeLevel.GetLevelRange(wrapper.Channel, out var minLevelDb, out float maxLevelDb, out float _);
wrapper.AudioVolumeLevel.SetLevel(wrapper.Channel, (float)LinearToDecibels(trackBar.Value, minLevelDb, maxLevelDb));
}
private static double LinearToDecibels(double linearValue, double minDb, double maxDb)
{
// Calculate the minimum and maximum values in linear scale
double minLinearValue = Math.Pow(10, minDb / 10.0);
double maxLinearValue = Math.Pow(10, maxDb / 10.0);
// Convert the percentage to a linear value within the given range
double linearRangeValue = (linearValue / 100.0) * (maxLinearValue - minLinearValue) + minLinearValue;
// Convert the linear value to decibels
return 10.0 * Math.Log10(linearRangeValue);
}
private static double DecibelsToLinear(double valueInDb, double minDb, double maxDb)
{
// Convert the value from decibels to linear scale
double linearValue = Math.Pow(10, valueInDb / 10.0);
// Calculate the minimum and maximum values in linear scale
double minLinearValue = Math.Pow(10, minDb / 10.0);
double maxLinearValue = Math.Pow(10, maxDb / 10.0);
// Convert the linear value to a percentage within the given range
double percentage = (linearValue - minLinearValue) / (maxLinearValue - minLinearValue) * 100.0;
// Ensure the percentage is within the valid range from 0 to 100
return Math.Max(Math.Min(percentage, 100.0), 0.0);
}
private GroupBox _superMixBox;
}
}

60
NAudioDemo/DeviceTopology/DeviceTopologyPanel.resx

@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

22
NAudioDemo/DeviceTopology/DeviceTopologyPlugin.cs

@ -0,0 +1,22 @@
using NAudioDemo.FadeInOutDemo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NAudioDemo.DeviceTopology
{
class DeviceTopologyPlugin : INAudioDemoPlugin
{
public string Name
{
get { return "Device Topology"; }
}
public System.Windows.Forms.Control CreatePanel()
{
return new DeviceTopologyPanel();
}
}
}
Loading…
Cancel
Save