From 99b73f710aa49f6a067e1c8561261be5bf79441a Mon Sep 17 00:00:00 2001 From: poprhythm Date: Sat, 9 May 2026 03:17:07 +0000 Subject: [PATCH] =?UTF-8?q?Initial=20commit=20=E2=80=94=20WPF=20guitar=20n?= =?UTF-8?q?ote=20name=20tutor=20using=20FFT=20frequency=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + FftGuitarTuner_license.txt | 22 ++ .../FrequencyDetectedEventArgs.cs | 19 ++ FrequencyDetection/FrequencyDetection.csproj | 71 +++++++ FrequencyDetection/FrequencyInfoSource.cs | 20 ++ FrequencyDetection/Properties/AssemblyInfo.cs | 36 ++++ .../SoundFrequencyInfoSource.cs | 69 +++++++ GuitarNoteNameTutor.sln | 38 ++++ GuitarNoteNameTutor/App.xaml | 8 + GuitarNoteNameTutor/App.xaml.cs | 16 ++ .../GuitarNoteNameTutor.csproj | 128 ++++++++++++ GuitarNoteNameTutor/GuitarNoteNameTutor.sln | 20 ++ .../Properties/AssemblyInfo.cs | 55 +++++ .../Properties/Resources.Designer.cs | 71 +++++++ GuitarNoteNameTutor/Properties/Resources.resx | 117 +++++++++++ .../Properties/Settings.Designer.cs | 30 +++ .../Properties/Settings.settings | 7 + GuitarNoteNameTutor/SelectDevice.xaml | 11 + GuitarNoteNameTutor/SelectDevice.xaml.cs | 57 +++++ GuitarNoteNameTutor/Window.xaml | 38 ++++ GuitarNoteNameTutor/Window.xaml.cs | 156 ++++++++++++++ SoundAnalysis/ComplexNumber.cs | 72 +++++++ SoundAnalysis/FftCalc.cs | 121 +++++++++++ SoundAnalysis/Properties/AssemblyInfo.cs | 36 ++++ SoundAnalysis/SoundAnalysis.csproj | 49 +++++ SoundCapture/Properties/AssemblyInfo.cs | 37 ++++ SoundCapture/SoundCapture.csproj | 54 +++++ SoundCapture/SoundCaptureBase.cs | 194 ++++++++++++++++++ SoundCapture/SoundCaptureDevice.cs | 68 ++++++ SoundCapture/SoundCaptureException.cs | 12 ++ 30 files changed, 1637 insertions(+) create mode 100644 .gitignore create mode 100644 FftGuitarTuner_license.txt create mode 100644 FrequencyDetection/FrequencyDetectedEventArgs.cs create mode 100644 FrequencyDetection/FrequencyDetection.csproj create mode 100644 FrequencyDetection/FrequencyInfoSource.cs create mode 100644 FrequencyDetection/Properties/AssemblyInfo.cs create mode 100644 FrequencyDetection/SoundFrequencyInfoSource.cs create mode 100644 GuitarNoteNameTutor.sln create mode 100644 GuitarNoteNameTutor/App.xaml create mode 100644 GuitarNoteNameTutor/App.xaml.cs create mode 100644 GuitarNoteNameTutor/GuitarNoteNameTutor.csproj create mode 100644 GuitarNoteNameTutor/GuitarNoteNameTutor.sln create mode 100644 GuitarNoteNameTutor/Properties/AssemblyInfo.cs create mode 100644 GuitarNoteNameTutor/Properties/Resources.Designer.cs create mode 100644 GuitarNoteNameTutor/Properties/Resources.resx create mode 100644 GuitarNoteNameTutor/Properties/Settings.Designer.cs create mode 100644 GuitarNoteNameTutor/Properties/Settings.settings create mode 100644 GuitarNoteNameTutor/SelectDevice.xaml create mode 100644 GuitarNoteNameTutor/SelectDevice.xaml.cs create mode 100644 GuitarNoteNameTutor/Window.xaml create mode 100644 GuitarNoteNameTutor/Window.xaml.cs create mode 100644 SoundAnalysis/ComplexNumber.cs create mode 100644 SoundAnalysis/FftCalc.cs create mode 100644 SoundAnalysis/Properties/AssemblyInfo.cs create mode 100644 SoundAnalysis/SoundAnalysis.csproj create mode 100644 SoundCapture/Properties/AssemblyInfo.cs create mode 100644 SoundCapture/SoundCapture.csproj create mode 100644 SoundCapture/SoundCaptureBase.cs create mode 100644 SoundCapture/SoundCaptureDevice.cs create mode 100644 SoundCapture/SoundCaptureException.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4b600d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +*.suo +*.user +.vs/ diff --git a/FftGuitarTuner_license.txt b/FftGuitarTuner_license.txt new file mode 100644 index 0000000..c293399 --- /dev/null +++ b/FftGuitarTuner_license.txt @@ -0,0 +1,22 @@ +Copyright (c) 2009 notmasteryet + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/FrequencyDetection/FrequencyDetectedEventArgs.cs b/FrequencyDetection/FrequencyDetectedEventArgs.cs new file mode 100644 index 0000000..6b7ba66 --- /dev/null +++ b/FrequencyDetection/FrequencyDetectedEventArgs.cs @@ -0,0 +1,19 @@ +using System; + +namespace FrequencyDetection +{ + public class FrequencyDetectedEventArgs : EventArgs + { + readonly double _frequency; + + public double Frequency + { + get { return _frequency; } + } + + public FrequencyDetectedEventArgs(double frequency) + { + _frequency = frequency; + } + } +} \ No newline at end of file diff --git a/FrequencyDetection/FrequencyDetection.csproj b/FrequencyDetection/FrequencyDetection.csproj new file mode 100644 index 0000000..4fa967c --- /dev/null +++ b/FrequencyDetection/FrequencyDetection.csproj @@ -0,0 +1,71 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {72165201-B9EA-45BD-96F9-9E81094C9BF0} + Library + Properties + FrequencyDetection + FrequencyDetection + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + {ABA54DC3-324B-49DE-B79E-C4F573306E4F} + SoundAnalysis + + + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE} + SoundCapture + + + + + \ No newline at end of file diff --git a/FrequencyDetection/FrequencyInfoSource.cs b/FrequencyDetection/FrequencyInfoSource.cs new file mode 100644 index 0000000..5f00be9 --- /dev/null +++ b/FrequencyDetection/FrequencyInfoSource.cs @@ -0,0 +1,20 @@ +using System; + +namespace FrequencyDetection +{ + public abstract class FrequencyInfoSource + { + public abstract void Listen(); + public abstract void Stop(); + + public event EventHandler FrequencyDetected; + + protected void OnFrequencyDetected(FrequencyDetectedEventArgs e) + { + if (FrequencyDetected != null) + { + FrequencyDetected(this, e); + } + } + } +} \ No newline at end of file diff --git a/FrequencyDetection/Properties/AssemblyInfo.cs b/FrequencyDetection/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..352e957 --- /dev/null +++ b/FrequencyDetection/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FrequencyDetection")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FrequencyDetection")] +[assembly: AssemblyCopyright("Copyright © 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cad84e03-98ea-4500-98e4-eef0b4e47094")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FrequencyDetection/SoundFrequencyInfoSource.cs b/FrequencyDetection/SoundFrequencyInfoSource.cs new file mode 100644 index 0000000..0936d3c --- /dev/null +++ b/FrequencyDetection/SoundFrequencyInfoSource.cs @@ -0,0 +1,69 @@ +using System; +using SoundAnalysis; +using SoundCapture; + +namespace FrequencyDetection +{ + public class SoundFrequencyInfoSource : FrequencyInfoSource + { + readonly SoundCaptureDevice _device; + Adapter _adapter; + + public SoundFrequencyInfoSource(SoundCaptureDevice device) + { + _device = device; + } + + public override void Listen() + { + _adapter = new Adapter(this, _device); + _adapter.Start(); + } + + public override void Stop() + { + _adapter.Stop(); + } + + class Adapter : SoundCaptureBase + { + readonly SoundFrequencyInfoSource _owner; + + const double MinFreq = 60; + const double MaxFreq = 1300; + + internal Adapter(SoundFrequencyInfoSource owner, SoundCaptureDevice device) + : base(device) + { + _owner = owner; + } + + protected override void ProcessData(short[] data) + { + double[] x = new double[data.Length]; + for (int i = 0; i < x.Length; i++) + { + x[i] = data[i]; + } + + double[] spectr = FftAlgorithm.Calculate(x); + int index = 0; + double max = spectr[0]; + int usefullMaxSpectr = Math.Min(spectr.Length, + (int)(MaxFreq * spectr.Length / SampleRate) + 1); + for (int i = 1; i < usefullMaxSpectr; i++) + { + if (max < spectr[i]) + { + max = spectr[i]; index = i; + } + } + + double freq = (double)SampleRate * index / spectr.Length; + if (freq < MinFreq) freq = 0; + + _owner.OnFrequencyDetected(new FrequencyDetectedEventArgs(freq)); + } + } + } +} \ No newline at end of file diff --git a/GuitarNoteNameTutor.sln b/GuitarNoteNameTutor.sln new file mode 100644 index 0000000..07b7035 --- /dev/null +++ b/GuitarNoteNameTutor.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuitarNoteNameTutor", "GuitarNoteNameTutor\GuitarNoteNameTutor.csproj", "{5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoundAnalysis", "SoundAnalysis\SoundAnalysis.csproj", "{ABA54DC3-324B-49DE-B79E-C4F573306E4F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoundCapture", "SoundCapture\SoundCapture.csproj", "{DAE12676-B26C-4487-A1A5-D7FE2E64E6CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrequencyDetection", "FrequencyDetection\FrequencyDetection.csproj", "{72165201-B9EA-45BD-96F9-9E81094C9BF0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E}.Release|Any CPU.Build.0 = Release|Any CPU + {ABA54DC3-324B-49DE-B79E-C4F573306E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABA54DC3-324B-49DE-B79E-C4F573306E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABA54DC3-324B-49DE-B79E-C4F573306E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABA54DC3-324B-49DE-B79E-C4F573306E4F}.Release|Any CPU.Build.0 = Release|Any CPU + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE}.Release|Any CPU.Build.0 = Release|Any CPU + {72165201-B9EA-45BD-96F9-9E81094C9BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72165201-B9EA-45BD-96F9-9E81094C9BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72165201-B9EA-45BD-96F9-9E81094C9BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72165201-B9EA-45BD-96F9-9E81094C9BF0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GuitarNoteNameTutor/App.xaml b/GuitarNoteNameTutor/App.xaml new file mode 100644 index 0000000..04934bd --- /dev/null +++ b/GuitarNoteNameTutor/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/GuitarNoteNameTutor/App.xaml.cs b/GuitarNoteNameTutor/App.xaml.cs new file mode 100644 index 0000000..80fc3ff --- /dev/null +++ b/GuitarNoteNameTutor/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace GuitarNoteNameTutor +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/GuitarNoteNameTutor/GuitarNoteNameTutor.csproj b/GuitarNoteNameTutor/GuitarNoteNameTutor.csproj new file mode 100644 index 0000000..f40b7a6 --- /dev/null +++ b/GuitarNoteNameTutor/GuitarNoteNameTutor.csproj @@ -0,0 +1,128 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {5C2AEEC3-B46A-4A40-B900-3C23CAD3FD7E} + WinExe + Properties + GuitarNoteNameTutor + GuitarNoteNameTutor + v3.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + 3.0 + + + 3.0 + + + 3.0 + + + 3.0 + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + Window.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + SelectDevice.xaml + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {72165201-B9EA-45BD-96F9-9E81094C9BF0} + FrequencyDetection + + + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE} + SoundCapture + + + + + \ No newline at end of file diff --git a/GuitarNoteNameTutor/GuitarNoteNameTutor.sln b/GuitarNoteNameTutor/GuitarNoteNameTutor.sln new file mode 100644 index 0000000..f617d6c --- /dev/null +++ b/GuitarNoteNameTutor/GuitarNoteNameTutor.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuitarNoteNameTutor", "GuitarNoteNameTutor.csproj", "{3B809A99-9D4C-4C38-9EB6-FE7259757543}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3B809A99-9D4C-4C38-9EB6-FE7259757543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B809A99-9D4C-4C38-9EB6-FE7259757543}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B809A99-9D4C-4C38-9EB6-FE7259757543}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B809A99-9D4C-4C38-9EB6-FE7259757543}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GuitarNoteNameTutor/Properties/AssemblyInfo.cs b/GuitarNoteNameTutor/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0e34710 --- /dev/null +++ b/GuitarNoteNameTutor/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GuitarNoteNameTutor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GuitarNoteNameTutor")] +[assembly: AssemblyCopyright("Copyright © 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GuitarNoteNameTutor/Properties/Resources.Designer.cs b/GuitarNoteNameTutor/Properties/Resources.Designer.cs new file mode 100644 index 0000000..409c982 --- /dev/null +++ b/GuitarNoteNameTutor/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3082 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GuitarNoteNameTutor.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GuitarNoteNameTutor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/GuitarNoteNameTutor/Properties/Resources.resx b/GuitarNoteNameTutor/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/GuitarNoteNameTutor/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GuitarNoteNameTutor/Properties/Settings.Designer.cs b/GuitarNoteNameTutor/Properties/Settings.Designer.cs new file mode 100644 index 0000000..713b014 --- /dev/null +++ b/GuitarNoteNameTutor/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3082 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GuitarNoteNameTutor.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/GuitarNoteNameTutor/Properties/Settings.settings b/GuitarNoteNameTutor/Properties/Settings.settings new file mode 100644 index 0000000..8f2fd95 --- /dev/null +++ b/GuitarNoteNameTutor/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/GuitarNoteNameTutor/SelectDevice.xaml b/GuitarNoteNameTutor/SelectDevice.xaml new file mode 100644 index 0000000..558a518 --- /dev/null +++ b/GuitarNoteNameTutor/SelectDevice.xaml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/GuitarNoteNameTutor/SelectDevice.xaml.cs b/GuitarNoteNameTutor/SelectDevice.xaml.cs new file mode 100644 index 0000000..247ccb3 --- /dev/null +++ b/GuitarNoteNameTutor/SelectDevice.xaml.cs @@ -0,0 +1,57 @@ +using System.Windows; +using SoundCapture; + +namespace GuitarNoteNameTutor +{ + /// + /// Interaction logic for SelectDevice.xaml + /// + public partial class SelectDevice + { + SoundCaptureDevice[] _devices; + + public SoundCaptureDevice SelectedDevice + { + get { return _devices[devicesListBox.SelectedIndex]; } + } + + public SelectDevice() + { + InitializeComponent(); + } + + private void LoadDevices() + { + devicesListBox.Items.Clear(); + + int defaultDeviceIndex = 0; + + _devices = SoundCaptureDevice.GetDevices(); + for (int i = 0; i < _devices.Length; i++) + { + devicesListBox.Items.Add(_devices[i].Name); + if (_devices[i].IsDefault) + defaultDeviceIndex = i; + } + + devicesListBox.SelectedIndex = defaultDeviceIndex; + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + LoadDevices(); + } + + private void okButton_Click(object sender, RoutedEventArgs e) + { + DialogResult = true; + Close(); + } + + private void lbi_MouseDoubleClick(object sender, RoutedEventArgs e) + { + DialogResult = true; + Close(); + } + } +} diff --git a/GuitarNoteNameTutor/Window.xaml b/GuitarNoteNameTutor/Window.xaml new file mode 100644 index 0000000..221be68 --- /dev/null +++ b/GuitarNoteNameTutor/Window.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/GuitarNoteNameTutor/Window.xaml.cs b/GuitarNoteNameTutor/Window.xaml.cs new file mode 100644 index 0000000..24f1b5e --- /dev/null +++ b/GuitarNoteNameTutor/Window.xaml.cs @@ -0,0 +1,156 @@ +using System; +using System.Diagnostics; +using System.Windows; +using System.Collections.Generic; +using System.Windows.Threading; +using FrequencyDetection; +using SoundCapture; + +namespace GuitarNoteNameTutor +{ + /// + /// Interaction logic for Window1.xaml + /// + public partial class Window + { + private bool IsListenning { get; set; } + + private static readonly Dictionary HalfNoteSharpNames = + new Dictionary + { + {0, "A"}, + {1, "A\u266F"}, + {2, "B"}, + {3, "C"}, + {4, "C\u266F"}, + {5, "D"}, + {6, "D\u266F"}, + {7, "E"}, + {8, "F"}, + {9, "F\u266F"}, + {10, "G"}, + {11, "G\u266F"}, + }; + + private static readonly Dictionary HalfNoteFlatNames = + new Dictionary + { + {0, "A"}, + {1, "B\u266D"}, + {2, "B"}, + {3, "C"}, + {4, "D\u266D"}, + {5, "D"}, + {6, "E\u266D"}, + {7, "E"}, + {8, "F"}, + {9, "G\u266D"}, + {10, "G"}, + {11, "A\u266D"}, + }; + + static readonly double ToneStep = Math.Pow(2, 1.0 / 12); + + private readonly Random _rand = new Random(); + + FrequencyInfoSource _frequencyInfoSource; + + public Window() + { + InitializeComponent(); + + //timer = new DispatcherTimer {Interval = TimeSpan.FromSeconds(2)}; + //timer.Tick += timer_Tick; + //timer.Start(); + } + + private void StopListenning() + { + IsListenning = false; + _frequencyInfoSource.FrequencyDetected -= FrequencyInfoSource_FrequencyDetected; + _frequencyInfoSource.Stop(); + _frequencyInfoSource = null; + } + + private void StartListenning(SoundCaptureDevice device) + { + IsListenning = true; + _frequencyInfoSource = new SoundFrequencyInfoSource(device); + _frequencyInfoSource.FrequencyDetected += FrequencyInfoSource_FrequencyDetected; + _frequencyInfoSource.Listen(); + } + + void FrequencyInfoSource_FrequencyDetected(object sender, FrequencyDetectedEventArgs e) + { + if (!Dispatcher.CheckAccess()) + { + Dispatcher.BeginInvoke( + new EventHandler(FrequencyInfoSource_FrequencyDetected), sender, e); + } + else + { + if (e.Frequency <= 0) + { + unknownFreqLabel.Visibility = Visibility.Visible; + frequencyLabel.Content = "?"; + return; + } + unknownFreqLabel.Visibility = Visibility.Hidden; + + NoteFrequency closestNote = FindClosestNote(e.Frequency); + label.Content = HalfNoteSharpNames[closestNote.HalfStepsFromA]; + frequencyLabel.Content = string.Format("{0:0.0}Hz", e.Frequency); + } + } + + private class NoteFrequency + { + public int HalfStepsFromA; + public double Frequency; + } + + private static NoteFrequency FindClosestNote(double frequency) + { + const double aFrequency = 440.0; + const int toneIndexOffsetToPositives = 120; + + int toneIndex = (int)Math.Round(Math.Log(frequency / aFrequency, ToneStep)); + int toneHalfStep = (toneIndexOffsetToPositives + toneIndex) % HalfNoteSharpNames.Count; + Debug.WriteLine(string.Format("{0}, {1}", toneIndexOffsetToPositives + toneIndex, (toneIndexOffsetToPositives + toneIndex) / 12 - 7)); + NoteFrequency noteFrequency = new NoteFrequency + { + HalfStepsFromA = toneHalfStep, + Frequency = Math.Pow(ToneStep, toneIndex)*aFrequency, + }; + + return noteFrequency; + } + + private DispatcherTimer timer; + + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + if (IsListenning) + { + StopListenning(); + } + } + + private void startButton_Click(object sender, RoutedEventArgs e) + { + SoundCaptureDevice device = null; + SelectDevice form = new SelectDevice {Owner = this}; + bool? dialogResponse = form.ShowDialog(); + if (dialogResponse.HasValue && dialogResponse == true) + { + device = form.SelectedDevice; + } + + if (device != null) + { + label.Content = string.Empty; + StartListenning(device); + } + } + } +} diff --git a/SoundAnalysis/ComplexNumber.cs b/SoundAnalysis/ComplexNumber.cs new file mode 100644 index 0000000..82fd281 --- /dev/null +++ b/SoundAnalysis/ComplexNumber.cs @@ -0,0 +1,72 @@ +using System; + +namespace SoundAnalysis +{ + /// + /// Complex number. + /// + struct ComplexNumber + { + public double Re; + public double Im; + + public ComplexNumber(double re) + { + Re = re; + Im = 0; + } + + public ComplexNumber(double re, double im) + { + Re = re; + Im = im; + } + + public static ComplexNumber operator *(ComplexNumber n1, ComplexNumber n2) + { + return new ComplexNumber(n1.Re * n2.Re - n1.Im * n2.Im, + n1.Im * n2.Re + n1.Re * n2.Im); + } + + public static ComplexNumber operator +(ComplexNumber n1, ComplexNumber n2) + { + return new ComplexNumber(n1.Re + n2.Re, n1.Im + n2.Im); + } + + public static ComplexNumber operator -(ComplexNumber n1, ComplexNumber n2) + { + return new ComplexNumber(n1.Re - n2.Re, n1.Im - n2.Im); + } + + public static ComplexNumber operator -(ComplexNumber n) + { + return new ComplexNumber(-n.Re, -n.Im); + } + + public static implicit operator ComplexNumber(double n) + { + return new ComplexNumber(n, 0); + } + + public ComplexNumber PoweredE() + { + double e = Math.Exp(Re); + return new ComplexNumber(e * Math.Cos(Im), e * Math.Sin(Im)); + } + + public double Power2() + { + return Re * Re - Im * Im; + } + + public double AbsPower2() + { + return Re * Re + Im * Im; + } + + public override string ToString() + { + return String.Format("{0}+i*{1}", Re, Im); + } + } +} diff --git a/SoundAnalysis/FftCalc.cs b/SoundAnalysis/FftCalc.cs new file mode 100644 index 0000000..de1ac6c --- /dev/null +++ b/SoundAnalysis/FftCalc.cs @@ -0,0 +1,121 @@ +using System; + +namespace SoundAnalysis +{ + /// + /// Cooley-Tukey FFT algorithm. + /// + public static class FftAlgorithm + { + /// + /// Calculates FFT using Cooley-Tukey FFT algorithm. + /// + /// input data + /// spectrogram of the data + /// + /// If amount of data items not equal a power of 2, then algorithm + /// automatically pad with 0s to the lowest amount of power of 2. + /// + public static double[] Calculate(double[] x) + { + int length; + int bitsInLength; + if (IsPowerOfTwo(x.Length)) + { + length = x.Length; + bitsInLength = Log2(length) - 1; + } + else + { + bitsInLength = Log2(x.Length); + length = 1 << bitsInLength; + // the items will be pad with zeros + } + + // bit reversal + ComplexNumber[] data = new ComplexNumber[length]; + for (int i = 0; i < x.Length; i++) + { + int j = ReverseBits(i, bitsInLength); + data[j] = new ComplexNumber(x[i]); + } + + // Cooley-Turkey + for (int i = 0; i < bitsInLength; i++) + { + int m = 1 << i; + int n = m * 2; + double alpha = -(2 * Math.PI / n); + + for (int k = 0; k < m; k++) + { + // e^(-2*pi*i/N*k) + ComplexNumber oddPartMultiplier = new ComplexNumber(0, alpha * k).PoweredE(); + + for (int j = k; j < length; j += n) + { + ComplexNumber evenPart = data[j]; + ComplexNumber oddPart = oddPartMultiplier * data[j + m]; + data[j] = evenPart + oddPart; + data[j + m] = evenPart - oddPart; + } + } + } + + // calculate spectrogram + double[] spectrogram = new double[length]; + for (int i = 0; i < spectrogram.Length; i++) + { + spectrogram[i] = data[i].AbsPower2(); + } + return spectrogram; + } + + /// + /// Gets number of significat bytes. + /// + /// Number + /// Amount of minimal bits to store the number. + private static int Log2(int n) + { + int i = 0; + while (n > 0) + { + ++i; n >>= 1; + } + return i; + } + + /// + /// Reverses bits in the number. + /// + /// Number + /// Significant bits in the number. + /// Reversed binary number. + private static int ReverseBits(int n, int bitsCount) + { + int reversed = 0; + for (int i = 0; i < bitsCount; i++) + { + int nextBit = n & 1; + n >>= 1; + + reversed <<= 1; + reversed |= nextBit; + } + return reversed; + } + + /// + /// Checks if number is power of 2. + /// + /// number + /// true if n=2^k and k is positive integer + private static bool IsPowerOfTwo(int n) + { + return n > 1 && (n & (n - 1)) == 0; + } + } + +} + diff --git a/SoundAnalysis/Properties/AssemblyInfo.cs b/SoundAnalysis/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2f405f5 --- /dev/null +++ b/SoundAnalysis/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SoundAnalysis")] +[assembly: AssemblyDescription("Sound anslysis library: FFT")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("notmasteryet")] +[assembly: AssemblyProduct("FftGuitarTuner")] +[assembly: AssemblyCopyright("Copyright © notmasteryet 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("52c3b811-84a7-4a5b-92e6-64f3c16752bb")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SoundAnalysis/SoundAnalysis.csproj b/SoundAnalysis/SoundAnalysis.csproj new file mode 100644 index 0000000..d2d776a --- /dev/null +++ b/SoundAnalysis/SoundAnalysis.csproj @@ -0,0 +1,49 @@ + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {ABA54DC3-324B-49DE-B79E-C4F573306E4F} + Library + Properties + SoundAnalysis + SoundAnalysis + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + \ No newline at end of file diff --git a/SoundCapture/Properties/AssemblyInfo.cs b/SoundCapture/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c4d5f2b --- /dev/null +++ b/SoundCapture/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SoundCapture")] +[assembly: AssemblyDescription("Sound capture library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("notmasteryet")] +[assembly: AssemblyProduct("FftGuitarTuner")] +[assembly: AssemblyCopyright("Copyright © notmasteryet 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b12d1bc8-57d3-464f-9286-b1456655872a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SoundCapture/SoundCapture.csproj b/SoundCapture/SoundCapture.csproj new file mode 100644 index 0000000..ca77c47 --- /dev/null +++ b/SoundCapture/SoundCapture.csproj @@ -0,0 +1,54 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {DAE12676-B26C-4487-A1A5-D7FE2E64E6CE} + Library + Properties + SoundCapture + SoundCapture + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/SoundCapture/SoundCaptureBase.cs b/SoundCapture/SoundCaptureBase.cs new file mode 100644 index 0000000..13b6eb9 --- /dev/null +++ b/SoundCapture/SoundCaptureBase.cs @@ -0,0 +1,194 @@ +using System; +using System.Threading; +using Microsoft.DirectX.DirectSound; +using Microsoft.Win32.SafeHandles; + +namespace SoundCapture +{ + /// + /// Base class to capture audio samples. + /// + public abstract class SoundCaptureBase : IDisposable + { + const int BufferSeconds = 3; + const int NotifyPointsInSecond = 2; + + // change in next two will require also code change + const int BitsPerSample = 16; + const int ChannelCount = 1; + + int _sampleRate = 44100; + bool _disposed; + + private bool IsCapturing { get; set; } + + protected int SampleRate + { + get { return _sampleRate; } + set + { + if (_sampleRate <= 0) throw new ArgumentOutOfRangeException(); + + EnsureIdle(); + + _sampleRate = value; + } + } + + Capture _capture; + CaptureBuffer _buffer; + Notify _notify; + int _bufferLength; + readonly AutoResetEvent _positionEvent; + readonly SafeWaitHandle _positionEventHandle; + readonly ManualResetEvent _terminated; + Thread _thread; + readonly SoundCaptureDevice _device; + + protected SoundCaptureBase() + : this(SoundCaptureDevice.GetDefaultDevice()) + { + + } + + protected SoundCaptureBase(SoundCaptureDevice device) + { + _device = device; + + _positionEvent = new AutoResetEvent(false); + _positionEventHandle = _positionEvent.SafeWaitHandle; + _terminated = new ManualResetEvent(true); + } + + private void EnsureIdle() + { + if (IsCapturing) + throw new SoundCaptureException("Capture is in process"); + } + + /// + /// Starts capture process. + /// + public void Start() + { + EnsureIdle(); + + IsCapturing = true; + + WaveFormat format = new WaveFormat + { + Channels = ChannelCount, + BitsPerSample = BitsPerSample, + SamplesPerSecond = SampleRate, + FormatTag = WaveFormatTag.Pcm, + }; + format.BlockAlign = (short)((format.Channels * format.BitsPerSample + 7) / 8); + format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond; + + _bufferLength = format.AverageBytesPerSecond * BufferSeconds; + CaptureBufferDescription desciption = new CaptureBufferDescription + { + Format = format, + BufferBytes = _bufferLength + }; + + _capture = new Capture(_device.Id); + _buffer = new CaptureBuffer(desciption, _capture); + + const int waitHandleCount = BufferSeconds * NotifyPointsInSecond; + BufferPositionNotify[] positions = new BufferPositionNotify[waitHandleCount]; + for (int i = 0; i < waitHandleCount; i++) + { + BufferPositionNotify position = new BufferPositionNotify + { + Offset = (i + 1)*_bufferLength/positions.Length - 1, + EventNotifyHandle = _positionEventHandle.DangerousGetHandle() + }; + positions[i] = position; + } + + _notify = new Notify(_buffer); + _notify.SetNotificationPositions(positions); + + _terminated.Reset(); + _thread = new Thread(ThreadLoop) {Name = "Sound capture"}; + _thread.Start(); + } + + private void ThreadLoop() + { + _buffer.Start(true); + try + { + int nextCapturePosition = 0; + WaitHandle[] handles = new WaitHandle[] { _terminated, _positionEvent }; + while (WaitHandle.WaitAny(handles) > 0) + { + int capturePosition, readPosition; + _buffer.GetCurrentPosition(out capturePosition, out readPosition); + + int lockSize = readPosition - nextCapturePosition; + if (lockSize < 0) lockSize += _bufferLength; + if((lockSize & 1) != 0) lockSize--; + + int itemsCount = lockSize >> 1; + + short[] data = (short[])_buffer.Read(nextCapturePosition, typeof(short), LockFlag.None, itemsCount); + ProcessData(data); + nextCapturePosition = (nextCapturePosition + lockSize) % _bufferLength; + } + } + finally + { + _buffer.Stop(); + } + } + + /// + /// Processes the captured data. + /// + /// Captured data + protected abstract void ProcessData(short[] data); + + /// + /// Stops capture process. + /// + public void Stop() + { + if (IsCapturing) + { + IsCapturing = false; + + _terminated.Set(); + //_thread. + _thread.Join(); + + _notify.Dispose(); + _buffer.Dispose(); + _capture.Dispose(); + } + } + + void IDisposable.Dispose() + { + Dispose(true); + } + + ~SoundCaptureBase() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (_disposed) return; + + _disposed = true; + GC.SuppressFinalize(this); + if (IsCapturing) Stop(); + _positionEventHandle.Dispose(); + _positionEvent.Close(); + _terminated.Close(); + } + } +} diff --git a/SoundCapture/SoundCaptureDevice.cs b/SoundCapture/SoundCaptureDevice.cs new file mode 100644 index 0000000..c1cf2b1 --- /dev/null +++ b/SoundCapture/SoundCaptureDevice.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Microsoft.DirectX.DirectSound; + +namespace SoundCapture +{ + /// + /// Capture device. + /// + public class SoundCaptureDevice + { + readonly Guid _id; + + readonly string _name; + + public bool IsDefault + { + get { return _id == Guid.Empty; } + } + + /// + /// Name of the device. + /// + public string Name + { + get { return _name; } + } + + internal Guid Id + { + get { return _id; } + } + + internal SoundCaptureDevice(Guid id, string name) + { + _id = id; + _name = name; + } + + public static SoundCaptureDevice[] GetDevices() + { + CaptureDevicesCollection captureDevices = new CaptureDevicesCollection(); + List devices = new List(); + foreach (DeviceInformation captureDevice in captureDevices) + { + devices.Add(new SoundCaptureDevice(captureDevice.DriverGuid, captureDevice.Description)); + } + return devices.ToArray(); + } + + public static SoundCaptureDevice GetDefaultDevice() + { + CaptureDevicesCollection captureDevices = new CaptureDevicesCollection(); + SoundCaptureDevice device = null; + foreach (DeviceInformation captureDevice in captureDevices) + { + if(captureDevice.DriverGuid == Guid.Empty) + { + device = new SoundCaptureDevice(captureDevice.DriverGuid, captureDevice.Description); + break; + } + } + if (device == null) + throw new SoundCaptureException("Default capture device is not found"); + return device; + } + } +} diff --git a/SoundCapture/SoundCaptureException.cs b/SoundCapture/SoundCaptureException.cs new file mode 100644 index 0000000..057ad64 --- /dev/null +++ b/SoundCapture/SoundCaptureException.cs @@ -0,0 +1,12 @@ +using System; + +namespace SoundCapture +{ + public class SoundCaptureException : Exception + { + public SoundCaptureException(string message) + : base(message) + { + } + } +}