From df244d01b119586ee7763241891d34be39703022 Mon Sep 17 00:00:00 2001 From: Maxx53 Date: Sat, 11 Apr 2020 20:30:45 +0300 Subject: [PATCH] AsioDriver class import Minor updates --- README.md | 4 + src/RS_ASIO_GUI/ASIODriver.cs | 274 +++++++++++++++++++++ src/RS_ASIO_GUI/Form1.Designer.cs | 26 +- src/RS_ASIO_GUI/Form1.cs | 48 +++- src/RS_ASIO_GUI/RS_ASIO_GUI.csproj | 1 + src/RS_ASIO_GUI/RegHelper.cs | 17 +- src/RS_ASIO_GUI/SettingControl.Designer.cs | 64 ++++- src/RS_ASIO_GUI/SettingControl.cs | 63 ++++- src/RS_ASIO_GUI/SettingControl.resx | 3 + 9 files changed, 460 insertions(+), 40 deletions(-) create mode 100644 src/RS_ASIO_GUI/ASIODriver.cs diff --git a/README.md b/README.md index af1cd63..dbd90c5 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,16 @@ Simple GUI for https://github.com/mdias/rs_asio ## Features * Provides simple GUI that allows you edit RS_ASIO settings easy without opening RS_ASIO.ini in text editor. * Reads ASIO drivers names from registry, no need to look into RS_ASIO-log.txt anymore. +* Uses [AsioDriver class from NAudio project](https://github.com/naudio/NAudio/blob/master/NAudio/Wave/Asio/ASIODriver.cs) to reading driver info and opening control panel. + ## Tips * Place EXE-file into Rocksmith directory, near RS_ASIO.ini +* ASIO driver control panel can be opened by "Config" button * Button "OK" is for saving RS_ASIO.ini and closing RS_ASIO_GUI * Button "Cancel" is for closing RS_ASIO_GUI without saving RS_ASIO.ini * Button "Run Rocksmith" saving RS_ASIO.ini, running Steam version of Rocksmith 2014 and closing RS_ASIO_GUI + ## Screenshot ![Steam Icon](https://maxx.illuzor.com/img/rsgui.png) diff --git a/src/RS_ASIO_GUI/ASIODriver.cs b/src/RS_ASIO_GUI/ASIODriver.cs new file mode 100644 index 0000000..c307722 --- /dev/null +++ b/src/RS_ASIO_GUI/ASIODriver.cs @@ -0,0 +1,274 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace NAudio.Wave.Asio +{ + /// + /// Main AsioDriver Class. To use this class, you need to query first the GetAsioDriverNames() and + /// then use the GetAsioDriverByName to instantiate the correct AsioDriver. + /// This is the first AsioDriver binding fully implemented in C#! + /// + /// Contributor: Alexandre Mutel - email: alexandre_mutel at yahoo.fr + /// + /// + + public class AsioDriver + { + private IntPtr pAsioComObject; + private AsioDriverVTable asioDriverVTable; + + private AsioDriver() + { + } + + /// + /// Instantiate the ASIO driver by GUID. + /// + /// The GUID. + /// an AsioDriver instance + public static AsioDriver GetAsioDriverByGuid(Guid guid) + { + var driver = new AsioDriver(); + driver.InitFromGuid(guid); + return driver; + } + + /// + /// Inits the AsioDriver.. + /// + /// The sys handle. + /// + public bool Init(IntPtr sysHandle) + { + int ret = asioDriverVTable.init(pAsioComObject, sysHandle); + return ret == 1; + } + + /// + /// Gets the name of the driver. + /// + /// + public string GetDriverName() + { + var name = new StringBuilder(256); + asioDriverVTable.getDriverName(pAsioComObject, name); + return name.ToString(); + } + + /// + /// Gets the driver version. + /// + /// + public int GetDriverVersion() + { + return asioDriverVTable.getDriverVersion(pAsioComObject); + } + + /// + /// Gets the number of channels. + /// + /// The num input channels. + /// The num output channels. + public void GetChannels(out int numInputChannels, out int numOutputChannels) + { + asioDriverVTable.getChannels(pAsioComObject, out numInputChannels, out numOutputChannels); + } + + /// + /// Gets the latencies (n.b. does not throw an exception) + /// + /// The input latency. + /// The output latency. + public int GetLatencies(out int inputLatency, out int outputLatency) + { + return asioDriverVTable.getLatencies(pAsioComObject, out inputLatency, out outputLatency); + } + + /// + /// Gets the size of the buffer. + /// + /// Size of the min. + /// Size of the max. + /// Size of the preferred. + /// The granularity. + public void GetBufferSize(out int minSize, out int maxSize, out int preferredSize, out int granularity) + { + asioDriverVTable.getBufferSize(pAsioComObject, out minSize, out maxSize, out preferredSize, out granularity); + } + + /// + /// Gets the sample rate. + /// + /// + public double GetSampleRate() + { + double sampleRate; + asioDriverVTable.getSampleRate(pAsioComObject, out sampleRate); + return sampleRate; + } + + /// + /// Controls the panel. + /// + public void ControlPanel() + { + asioDriverVTable.controlPanel(pAsioComObject); + } + + + /// + /// Releases this instance. + /// + public void ReleaseComAsioDriver() + { + Marshal.Release(pAsioComObject); + } + + + /// + /// Inits the vTable method from GUID. This is a tricky part of this class. + /// + /// The ASIO GUID. + private void InitFromGuid(Guid asioGuid) + { + const uint CLSCTX_INPROC_SERVER = 1; + // Start to query the virtual table a index 3 (init method of AsioDriver) + const int INDEX_VTABLE_FIRST_METHOD = 3; + + // Pointer to the ASIO object + // USE CoCreateInstance instead of builtin COM-Class instantiation, + // because the AsioDriver expect to have the ASIOGuid used for both COM Object and COM interface + // The CoCreateInstance is working only in STAThread mode. + int hresult = CoCreateInstance(ref asioGuid, IntPtr.Zero, CLSCTX_INPROC_SERVER, ref asioGuid, out pAsioComObject); + if (hresult != 0) + { + throw new COMException("Unable to instantiate ASIO. Check if STAThread is set", hresult); + } + + // The first pointer at the adress of the ASIO Com Object is a pointer to the + // C++ Virtual table of the object. + // Gets a pointer to VTable. + IntPtr pVtable = Marshal.ReadIntPtr(pAsioComObject); + + // Instantiate our Virtual table mapping + asioDriverVTable = new AsioDriverVTable(); + + // This loop is going to retrieve the pointer from the C++ VirtualTable + // and attach an internal delegate in order to call the method on the COM Object. + FieldInfo[] fieldInfos = typeof(AsioDriverVTable).GetFields(); + for (int i = 0; i < fieldInfos.Length; i++) + { + FieldInfo fieldInfo = fieldInfos[i]; + // Read the method pointer from the VTable + IntPtr pPointerToMethodInVTable = Marshal.ReadIntPtr(pVtable, (i + INDEX_VTABLE_FIRST_METHOD) * IntPtr.Size); + // Instantiate a delegate + object methodDelegate = Marshal.GetDelegateForFunctionPointer(pPointerToMethodInVTable, fieldInfo.FieldType); + // Store the delegate in our C# VTable + fieldInfo.SetValue(asioDriverVTable, methodDelegate); + } + } + + /// + /// Internal VTable structure to store all the delegates to the C++ COM method. + /// + [StructLayout(LayoutKind.Sequential, Pack = 2)] + private class AsioDriverVTable + { + //3 virtual ASIOBool init(void *sysHandle) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOInit(IntPtr _pUnknown, IntPtr sysHandle); + public ASIOInit init = null; + //4 virtual void getDriverName(char *name) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate void ASIOgetDriverName(IntPtr _pUnknown, StringBuilder name); + public ASIOgetDriverName getDriverName = null; + //5 virtual long getDriverVersion() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetDriverVersion(IntPtr _pUnknown); + public ASIOgetDriverVersion getDriverVersion = null; + //6 virtual void getErrorMessage(char *string) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate void ASIOgetErrorMessage(IntPtr _pUnknown, StringBuilder errorMessage); + public ASIOgetErrorMessage getErrorMessage = null; + //7 virtual ASIOError start() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOstart(IntPtr _pUnknown); + public ASIOstart start = null; + //8 virtual ASIOError stop() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOstop(IntPtr _pUnknown); + public ASIOstop stop = null; + //9 virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetChannels(IntPtr _pUnknown, out int numInputChannels, out int numOutputChannels); + public ASIOgetChannels getChannels = null; + //10 virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetLatencies(IntPtr _pUnknown, out int inputLatency, out int outputLatency); + public ASIOgetLatencies getLatencies = null; + //11 virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetBufferSize(IntPtr _pUnknown, out int minSize, out int maxSize, out int preferredSize, out int granularity); + public ASIOgetBufferSize getBufferSize = null; + //12 virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOcanSampleRate(IntPtr _pUnknown, double sampleRate); + public ASIOcanSampleRate canSampleRate = null; + //13 virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetSampleRate(IntPtr _pUnknown, out double sampleRate); + public ASIOgetSampleRate getSampleRate = null; + //14 virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOsetSampleRate(IntPtr _pUnknown, double sampleRate); + public ASIOsetSampleRate setSampleRate = null; + //15 virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetClockSources(IntPtr _pUnknown, out long clocks, int numSources); + public ASIOgetClockSources getClockSources = null; + //16 virtual ASIOError setClockSource(long reference) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOsetClockSource(IntPtr _pUnknown, int reference); + public ASIOsetClockSource setClockSource = null; + //17 virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetSamplePosition(IntPtr _pUnknown, out long samplePos, ref object timeStamp); + public ASIOgetSamplePosition getSamplePosition = null; + //18 virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOgetChannelInfo(IntPtr _pUnknown, ref object info); + public ASIOgetChannelInfo getChannelInfo = null; + //19 virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + //public delegate ASIOError ASIOcreateBuffers(IntPtr _pUnknown, ref ASIOBufferInfo[] bufferInfos, int numChannels, int bufferSize, ref ASIOCallbacks callbacks); + public delegate int ASIOcreateBuffers(IntPtr _pUnknown, IntPtr bufferInfos, int numChannels, int bufferSize, IntPtr callbacks); + public ASIOcreateBuffers createBuffers = null; + //20 virtual ASIOError disposeBuffers() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOdisposeBuffers(IntPtr _pUnknown); + public ASIOdisposeBuffers disposeBuffers = null; + //21 virtual ASIOError controlPanel() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOcontrolPanel(IntPtr _pUnknown); + public ASIOcontrolPanel controlPanel = null; + //22 virtual ASIOError future(long selector,void *opt) = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOfuture(IntPtr _pUnknown, int selector, IntPtr opt); + public ASIOfuture future = null; + //23 virtual ASIOError outputReady() = 0; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + public delegate int ASIOoutputReady(IntPtr _pUnknown); + public ASIOoutputReady outputReady = null; + + } + + [DllImport("ole32.Dll")] + private static extern int CoCreateInstance(ref Guid clsid, + IntPtr inner, + uint context, + ref Guid uuid, + out IntPtr rReturnedComObject); + } +} diff --git a/src/RS_ASIO_GUI/Form1.Designer.cs b/src/RS_ASIO_GUI/Form1.Designer.cs index 0d2bda2..48a91bc 100644 --- a/src/RS_ASIO_GUI/Form1.Designer.cs +++ b/src/RS_ASIO_GUI/Form1.Designer.cs @@ -94,7 +94,7 @@ private void InitializeComponent() this.groupBox2.Controls.Add(this.bufferModeCombo); this.groupBox2.Location = new System.Drawing.Point(12, 96); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(295, 120); + this.groupBox2.Size = new System.Drawing.Size(295, 130); this.groupBox2.TabIndex = 3; this.groupBox2.TabStop = false; this.groupBox2.Text = "ASIO"; @@ -156,7 +156,7 @@ private void InitializeComponent() this.groupBox3.Controls.Add(this.OutputControl); this.groupBox3.Location = new System.Drawing.Point(324, 12); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(295, 204); + this.groupBox3.Size = new System.Drawing.Size(295, 214); this.groupBox3.TabIndex = 4; this.groupBox3.TabStop = false; this.groupBox3.Text = "Asio.Output"; @@ -164,9 +164,9 @@ private void InitializeComponent() // groupBox4 // this.groupBox4.Controls.Add(this.Input0Control); - this.groupBox4.Location = new System.Drawing.Point(12, 222); + this.groupBox4.Location = new System.Drawing.Point(12, 232); this.groupBox4.Name = "groupBox4"; - this.groupBox4.Size = new System.Drawing.Size(295, 201); + this.groupBox4.Size = new System.Drawing.Size(295, 214); this.groupBox4.TabIndex = 4; this.groupBox4.TabStop = false; this.groupBox4.Text = "Asio.Input.0"; @@ -174,9 +174,9 @@ private void InitializeComponent() // groupBox5 // this.groupBox5.Controls.Add(this.Input1Control); - this.groupBox5.Location = new System.Drawing.Point(324, 222); + this.groupBox5.Location = new System.Drawing.Point(324, 232); this.groupBox5.Name = "groupBox5"; - this.groupBox5.Size = new System.Drawing.Size(295, 201); + this.groupBox5.Size = new System.Drawing.Size(295, 214); this.groupBox5.TabIndex = 4; this.groupBox5.TabStop = false; this.groupBox5.Text = "Asio.Input.1"; @@ -184,7 +184,7 @@ private void InitializeComponent() // OkButton // this.OkButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.OkButton.Location = new System.Drawing.Point(463, 429); + this.OkButton.Location = new System.Drawing.Point(465, 452); this.OkButton.Name = "OkButton"; this.OkButton.Size = new System.Drawing.Size(75, 23); this.OkButton.TabIndex = 5; @@ -194,7 +194,7 @@ private void InitializeComponent() // // ExitButton // - this.ExitButton.Location = new System.Drawing.Point(544, 429); + this.ExitButton.Location = new System.Drawing.Point(546, 452); this.ExitButton.Name = "ExitButton"; this.ExitButton.Size = new System.Drawing.Size(75, 23); this.ExitButton.TabIndex = 5; @@ -204,7 +204,7 @@ private void InitializeComponent() // // runRsButton // - this.runRsButton.Location = new System.Drawing.Point(12, 429); + this.runRsButton.Location = new System.Drawing.Point(12, 452); this.runRsButton.Name = "runRsButton"; this.runRsButton.Size = new System.Drawing.Size(96, 23); this.runRsButton.TabIndex = 5; @@ -216,7 +216,7 @@ private void InitializeComponent() // this.Input1Control.Location = new System.Drawing.Point(6, 19); this.Input1Control.Name = "Input1Control"; - this.Input1Control.Size = new System.Drawing.Size(285, 175); + this.Input1Control.Size = new System.Drawing.Size(285, 189); this.Input1Control.TabIndex = 0; this.Input1Control.Tag = "Asio.Input.1"; // @@ -224,7 +224,7 @@ private void InitializeComponent() // this.Input0Control.Location = new System.Drawing.Point(4, 20); this.Input0Control.Name = "Input0Control"; - this.Input0Control.Size = new System.Drawing.Size(285, 175); + this.Input0Control.Size = new System.Drawing.Size(285, 188); this.Input0Control.TabIndex = 0; this.Input0Control.Tag = "Asio.Input.0"; // @@ -232,7 +232,7 @@ private void InitializeComponent() // this.OutputControl.Location = new System.Drawing.Point(4, 19); this.OutputControl.Name = "OutputControl"; - this.OutputControl.Size = new System.Drawing.Size(285, 175); + this.OutputControl.Size = new System.Drawing.Size(285, 189); this.OutputControl.TabIndex = 0; this.OutputControl.Tag = "Asio.Output"; // @@ -240,7 +240,7 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(633, 460); + this.ClientSize = new System.Drawing.Size(633, 483); this.Controls.Add(this.ExitButton); this.Controls.Add(this.runRsButton); this.Controls.Add(this.OkButton); diff --git a/src/RS_ASIO_GUI/Form1.cs b/src/RS_ASIO_GUI/Form1.cs index 37ac71c..a2b27c1 100644 --- a/src/RS_ASIO_GUI/Form1.cs +++ b/src/RS_ASIO_GUI/Form1.cs @@ -1,4 +1,6 @@ -using System; +using NAudio.Wave; +using NAudio.Wave.Asio; +using System; using System.Diagnostics; using System.Windows.Forms; @@ -22,15 +24,16 @@ public Form1() private void Form1_Load(object sender, EventArgs e) { //Getting ASIO device list from registry - var devs = RegHelper.GetAsioDevices(); + //Also you can return one object such array of tuple or keyvalue but it complicate further work + RegHelper.GetAsioDevices(out string[] devNames, out Guid[] devGuids); //Hiding channel from OutputControl, there's no such setting OutputControl.Controls["channelPanel"].Visible = false; //Filling up device combos for all usercontrols - (OutputControl.Controls["deviceCombo"] as ComboBox).Items.AddRange(devs); - (Input0Control.Controls["deviceCombo"] as ComboBox).Items.AddRange(devs); - (Input1Control.Controls["deviceCombo"] as ComboBox).Items.AddRange(devs); + OutputControl.PassArrays(devNames, devGuids); + Input0Control.PassArrays(devNames, devGuids); + Input1Control.PassArrays(devNames, devGuids); ReadSettings(); } @@ -60,7 +63,8 @@ private void ReadSettingControl(SettingControl setCtrl) var section = setCtrl.Tag.ToString(); //Reading values to combobox - (setCtrl.Controls["deviceCombo"] as ComboBox).SelectedItem = RSIni.Read("Driver", section); + var devName = RSIni.Read("Driver", section); + (setCtrl.Controls["deviceCombo"] as ComboBox).SelectedItem = devName != string.Empty ? devName : "None"; //Reading values to checkboxes (setCtrl.Controls["enableEndpointCheck"] as CheckBox).Checked = RSIni.Read("EnableSoftwareEndpointVolumeControl", section) == "1"; @@ -70,9 +74,13 @@ private void ReadSettingControl(SettingControl setCtrl) decimal.TryParse(RSIni.Read("SoftwareMasterVolumePercent", section), out decimal volumePercent); (setCtrl.Controls["volumeNumeric"] as NumericUpDown).Value = volumePercent; - decimal.TryParse(RSIni.Read("Channel", section), out decimal channelValue); - (setCtrl.Controls["channelPanel"].Controls["channelNumeric"] as NumericUpDown).Value = channelValue; + //Exclude reading from Output section, there's no channel setting + if (section != "Asio.Output") + { + decimal.TryParse(RSIni.Read("Channel", section), out decimal channelValue); + (setCtrl.Controls["channelPanel"].Controls["channelNumeric"] as NumericUpDown).Value = channelValue; + } } private void SaveSettings() @@ -93,13 +101,26 @@ private void SaveSettings() WriteSettingControl(Input1Control); } + + //Prevent saving with using one channel of one device on different inputs + private bool CheckChannels() + { + var input1Dev = (Input0Control.Controls["deviceCombo"] as ComboBox).Text; + var input2Dev = (Input1Control.Controls["deviceCombo"] as ComboBox).Text; + var input1Ch = (Input0Control.Controls["channelPanel"].Controls["channelNumeric"] as NumericUpDown).Value; + var input2Ch = (Input1Control.Controls["channelPanel"].Controls["channelNumeric"] as NumericUpDown).Value; + + return !((input1Dev == input2Dev) && (input1Ch == input2Ch)); + } + private void WriteSettingControl(SettingControl setCtrl) { //Info about section stored in Tag property var section = setCtrl.Tag.ToString(); //Saving values from combobox - RSIni.Write("Driver", (setCtrl.Controls["deviceCombo"] as ComboBox).Text, section); + var devName = (setCtrl.Controls["deviceCombo"] as ComboBox).Text; + RSIni.Write("Driver", devName != "None" ? devName : string.Empty, section); //Saving values from checkboxes RSIni.Write("EnableSoftwareEndpointVolumeControl", (setCtrl.Controls["enableEndpointCheck"] as CheckBox).Checked ? "1" : "0", section); @@ -130,8 +151,13 @@ private void ExitButton_Click(object sender, EventArgs e) private void OkButton_Click(object sender, EventArgs e) { - SaveSettings(); - Application.Exit(); + if (CheckChannels()) + { + SaveSettings(); + Application.Exit(); + } + else + MessageBox.Show("You have one channel on different inputs. Settings NOT saved!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } private void RunRsButton_Click(object sender, EventArgs e) diff --git a/src/RS_ASIO_GUI/RS_ASIO_GUI.csproj b/src/RS_ASIO_GUI/RS_ASIO_GUI.csproj index 6d8ee94..64dad19 100644 --- a/src/RS_ASIO_GUI/RS_ASIO_GUI.csproj +++ b/src/RS_ASIO_GUI/RS_ASIO_GUI.csproj @@ -40,6 +40,7 @@ + Form diff --git a/src/RS_ASIO_GUI/RegHelper.cs b/src/RS_ASIO_GUI/RegHelper.cs index 4e2c822..f085924 100644 --- a/src/RS_ASIO_GUI/RegHelper.cs +++ b/src/RS_ASIO_GUI/RegHelper.cs @@ -1,10 +1,11 @@ using Microsoft.Win32; +using System; namespace RS_ASIO_GUI { class RegHelper { - public static string[] GetAsioDevices() + public static void GetAsioDevices(out string[] devNames, out Guid[] devGuids) { var asioKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default).OpenSubKey(@"Software\ASIO"); var clsidKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Default).OpenSubKey(@"CLSID"); @@ -14,7 +15,9 @@ public static string[] GetAsioDevices() if (devices != null) { - var result = new string[devices.Length]; + devNames = new string[devices.Length]; + devGuids = new Guid[devices.Length]; + for (int i = 0; i < devices.Length; i++) { string devName = null; @@ -25,13 +28,15 @@ public static string[] GetAsioDevices() if (clcid != null) devName = clsidKey.OpenSubKey(clcid)?.GetValue(string.Empty).ToString(); - result[i] = devName ?? "undefined"; + devNames[i] = devName ?? "undefined"; + devGuids[i] = new Guid(clcid); } - - return result; } else - return new string[0]; + { + devNames = new string[0]; + devGuids = new Guid[0]; + } } } } diff --git a/src/RS_ASIO_GUI/SettingControl.Designer.cs b/src/RS_ASIO_GUI/SettingControl.Designer.cs index a76d365..6380f0b 100644 --- a/src/RS_ASIO_GUI/SettingControl.Designer.cs +++ b/src/RS_ASIO_GUI/SettingControl.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.volumeTrackBar = new System.Windows.Forms.TrackBar(); @@ -38,6 +39,10 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.channelNumeric = new System.Windows.Forms.NumericUpDown(); this.channelPanel = new System.Windows.Forms.Panel(); + this.configButton = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.DriverInfoLabel = new System.Windows.Forms.Label(); + this.InfoUpdTimer = new System.Windows.Forms.Timer(this.components); ((System.ComponentModel.ISupportInitialize)(this.volumeTrackBar)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.volumeNumeric)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.channelNumeric)).BeginInit(); @@ -56,7 +61,7 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(59, 118); + this.label1.Location = new System.Drawing.Point(59, 143); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(153, 13); this.label1.TabIndex = 12; @@ -64,7 +69,7 @@ private void InitializeComponent() // // volumeTrackBar // - this.volumeTrackBar.Location = new System.Drawing.Point(59, 140); + this.volumeTrackBar.Location = new System.Drawing.Point(59, 165); this.volumeTrackBar.Maximum = 100; this.volumeTrackBar.Name = "volumeTrackBar"; this.volumeTrackBar.Size = new System.Drawing.Size(149, 45); @@ -77,16 +82,17 @@ private void InitializeComponent() this.deviceCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.deviceCombo.FormattingEnabled = true; this.deviceCombo.Items.AddRange(new object[] { - ""}); + "None"}); this.deviceCombo.Location = new System.Drawing.Point(60, 12); this.deviceCombo.Name = "deviceCombo"; - this.deviceCombo.Size = new System.Drawing.Size(189, 21); + this.deviceCombo.Size = new System.Drawing.Size(164, 21); this.deviceCombo.TabIndex = 8; + this.deviceCombo.SelectedIndexChanged += new System.EventHandler(this.DeviceCombo_SelectedIndexChanged); // // enableMasterCheck // this.enableMasterCheck.AutoSize = true; - this.enableMasterCheck.Location = new System.Drawing.Point(59, 92); + this.enableMasterCheck.Location = new System.Drawing.Point(59, 117); this.enableMasterCheck.Name = "enableMasterCheck"; this.enableMasterCheck.Size = new System.Drawing.Size(201, 17); this.enableMasterCheck.TabIndex = 7; @@ -96,7 +102,7 @@ private void InitializeComponent() // enableEndpointCheck // this.enableEndpointCheck.AutoSize = true; - this.enableEndpointCheck.Location = new System.Drawing.Point(59, 69); + this.enableEndpointCheck.Location = new System.Drawing.Point(59, 94); this.enableEndpointCheck.Name = "enableEndpointCheck"; this.enableEndpointCheck.Size = new System.Drawing.Size(211, 17); this.enableEndpointCheck.TabIndex = 6; @@ -105,7 +111,7 @@ private void InitializeComponent() // // volumeNumeric // - this.volumeNumeric.Location = new System.Drawing.Point(215, 140); + this.volumeNumeric.Location = new System.Drawing.Point(215, 165); this.volumeNumeric.Name = "volumeNumeric"; this.volumeNumeric.Size = new System.Drawing.Size(55, 20); this.volumeNumeric.TabIndex = 13; @@ -131,15 +137,51 @@ private void InitializeComponent() // this.channelPanel.Controls.Add(this.channelNumeric); this.channelPanel.Controls.Add(this.label3); - this.channelPanel.Location = new System.Drawing.Point(0, 36); + this.channelPanel.Location = new System.Drawing.Point(0, 61); this.channelPanel.Name = "channelPanel"; this.channelPanel.Size = new System.Drawing.Size(121, 32); this.channelPanel.TabIndex = 14; // + // configButton + // + this.configButton.Location = new System.Drawing.Point(230, 10); + this.configButton.Name = "configButton"; + this.configButton.Size = new System.Drawing.Size(52, 23); + this.configButton.TabIndex = 15; + this.configButton.Text = "Config"; + this.configButton.UseVisualStyleBackColor = true; + this.configButton.Click += new System.EventHandler(this.ConfigButton_Click); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(29, 43); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(25, 13); + this.label4.TabIndex = 16; + this.label4.Text = "Info"; + // + // DriverInfoLabel + // + this.DriverInfoLabel.AutoSize = true; + this.DriverInfoLabel.Location = new System.Drawing.Point(57, 43); + this.DriverInfoLabel.Name = "DriverInfoLabel"; + this.DriverInfoLabel.Size = new System.Drawing.Size(33, 13); + this.DriverInfoLabel.TabIndex = 17; + this.DriverInfoLabel.Text = "None"; + // + // InfoUpdTimer + // + this.InfoUpdTimer.Interval = 1000; + this.InfoUpdTimer.Tick += new System.EventHandler(this.InfoUpdTimer_Tick); + // // SettingControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.DriverInfoLabel); + this.Controls.Add(this.label4); + this.Controls.Add(this.configButton); this.Controls.Add(this.channelPanel); this.Controls.Add(this.volumeNumeric); this.Controls.Add(this.label2); @@ -149,7 +191,7 @@ private void InitializeComponent() this.Controls.Add(this.enableMasterCheck); this.Controls.Add(this.enableEndpointCheck); this.Name = "SettingControl"; - this.Size = new System.Drawing.Size(285, 175); + this.Size = new System.Drawing.Size(285, 196); ((System.ComponentModel.ISupportInitialize)(this.volumeTrackBar)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.volumeNumeric)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.channelNumeric)).EndInit(); @@ -172,5 +214,9 @@ private void InitializeComponent() private System.Windows.Forms.Label label3; private System.Windows.Forms.NumericUpDown channelNumeric; private System.Windows.Forms.Panel channelPanel; + private System.Windows.Forms.Button configButton; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label DriverInfoLabel; + private System.Windows.Forms.Timer InfoUpdTimer; } } diff --git a/src/RS_ASIO_GUI/SettingControl.cs b/src/RS_ASIO_GUI/SettingControl.cs index 48721fe..bd7bc2e 100644 --- a/src/RS_ASIO_GUI/SettingControl.cs +++ b/src/RS_ASIO_GUI/SettingControl.cs @@ -1,10 +1,14 @@ -using System; +using NAudio.Wave.Asio; +using System; using System.Windows.Forms; namespace RS_ASIO_GUI { public partial class SettingControl : UserControl { + private Guid[] DevGuids; + private AsioDriver Driver; + public SettingControl() { InitializeComponent(); @@ -19,5 +23,62 @@ private void VolumeNumeric_ValueChanged(object sender, EventArgs e) { volumeTrackBar.Value = (int)volumeNumeric.Value; } + + private void DeviceCombo_SelectedIndexChanged(object sender, EventArgs e) + { + if (Driver != null) + { + Driver.ReleaseComAsioDriver(); + Driver = null; + } + + //First item is "None" with 0 index + if (deviceCombo.SelectedIndex > 0) + { + var currGuid = DevGuids[deviceCombo.SelectedIndex - 1]; + Driver = AsioDriver.GetAsioDriverByGuid(currGuid); + + //Limiting channel numeric by real channel number + Driver.GetChannels(out int inputCh, out _); + channelNumeric.Maximum = inputCh - 1; + + UpdateDriverInfo(); + InfoUpdTimer.Start(); + } + else + { + DriverInfoLabel.Text = "None"; + InfoUpdTimer.Stop(); + } + } + + private void UpdateDriverInfo() + { + if (Driver != null) + { + //Buffer size not updating in this instance of Driver. Too Sad. + Driver.GetBufferSize(out _, out _, out int prefBuff, out _); + DriverInfoLabel.Text = $"BufferSize {prefBuff}, SampleRate {Driver.GetSampleRate()} Hz"; + } + } + + internal void PassArrays(string[] devNames, Guid[] devGuids) + { + deviceCombo.Items.AddRange(devNames); + DevGuids = devGuids; + } + + private void ConfigButton_Click(object sender, EventArgs e) + { + if (Driver != null) + { + Driver.ControlPanel(); + } + } + + private void InfoUpdTimer_Tick(object sender, EventArgs e) + { + UpdateDriverInfo(); + } } } diff --git a/src/RS_ASIO_GUI/SettingControl.resx b/src/RS_ASIO_GUI/SettingControl.resx index 1af7de1..41780a7 100644 --- a/src/RS_ASIO_GUI/SettingControl.resx +++ b/src/RS_ASIO_GUI/SettingControl.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file