diff --git a/CUE.NET.sln b/CUE.NET.sln
index 30ce44c..8183f2b 100644
--- a/CUE.NET.sln
+++ b/CUE.NET.sln
@@ -28,6 +28,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "x64", "x64", "{2F99124B-FAE
libs\x64\CUESDK_2013.dll = libs\x64\CUESDK_2013.dll
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AudioAnalyzer", "AudioAnalyzer", "{BE16A0BF-6794-4718-AF27-F2A50078D880}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example_AudioAnalyzer_full", "Examples\AudioAnalyzer\Example_AudioAnalyzer_full\Example_AudioAnalyzer_full.csproj", "{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -42,6 +46,10 @@ Global
{7FD88256-5E14-4D7C-862B-7BC2CD04081A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FD88256-5E14-4D7C-862B-7BC2CD04081A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FD88256-5E14-4D7C-862B-7BC2CD04081A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -51,5 +59,7 @@ Global
{D69EF6D8-68FF-4C56-B5CB-253971B1DF91} = {FF50AF6A-D2AC-4772-B013-C10D127DBE29}
{0525D895-E706-4920-8733-DABD9194BFB1} = {D69EF6D8-68FF-4C56-B5CB-253971B1DF91}
{2F99124B-FAED-432D-B797-45566D373411} = {D69EF6D8-68FF-4C56-B5CB-253971B1DF91}
+ {BE16A0BF-6794-4718-AF27-F2A50078D880} = {1F52DDC9-E9D0-4A7B-8E78-930528203EE6}
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972} = {BE16A0BF-6794-4718-AF27-F2A50078D880}
EndGlobalSection
EndGlobal
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/App.config b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/App.config
new file mode 100644
index 0000000..8324aa6
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs
new file mode 100644
index 0000000..ff20d31
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using CUE.NET;
+using CUE.NET.Brushes;
+using CUE.NET.Devices.Keyboard;
+using CUE.NET.Exceptions;
+using CUE.NET.Gradients;
+using Example_AudioAnalyzer_full.TakeAsIs;
+
+namespace Example_AudioAnalyzer_full
+{
+ /* ##################################################################################################
+ * # #
+ * # This example demonstrates how to write a simple Spectrograph for your keyboard using CUE.NET #
+ * # making extensive use of CUE.NET features (mostly own effects and brushes). #
+ * # Code in the TakeAsIs-folder and -regions is logic not related to CUE.NET -> ignore it #
+ * # #
+ * # Most of the audio-analysis stuff is taken from AterialDawn's project: #
+ * # https://github.com/AterialDawn/CUEAudioVisualizer/tree/master/CUEAudioVisualizer #
+ * # #
+ * ##################################################################################################
+ */
+ public class AudioAnalyzerExample
+ {
+ #region Constants
+
+ // This value will vertical scale the spectrum. Since it highly depends on the music which value looks good, feel free to tweak it until you like it.
+ private const float VOLUME_SCALAR = 0.5f;
+
+ #endregion
+
+ #region Properties & Fields
+
+ private SoundDataProcessor _soundDataProcessor; // Take as is
+
+ private CorsairKeyboard _keyboard;
+
+ #endregion
+
+ #region Methods
+
+ public void Initialize()
+ {
+ // Initialize everything
+ CueSDK.Initialize();
+
+ _keyboard = CueSDK.KeyboardSDK;
+ if (_keyboard == null)
+ throw new WrapperException("No keyboard found ...");
+
+ // With this you could set the update frequency - the default (30 updates per second) should be fine for the most things
+ //_keyboard.UpdateFrequency = 1f / 60f; // 60 updates per second
+
+ // This is useful for debugging-purposes
+ _keyboard.OnException += (sender, args) => Console.WriteLine(args.Exception.Message);
+
+ Console.WriteLine("CUE.NET initialized!");
+ }
+
+ public void Run()
+ {
+ // Add a lack background. We want this to be semi-transparent to add some sort of fade-effect - this will smooth everything out a bit
+ // Note that this isn't a 'real effect' since it's update-rate dependent. A real effect would do always the same thing not mather how fast the keyboard updates.
+ _keyboard.Brush = new SolidColorBrush(Color.FromArgb(96, 0, 0, 0));
+
+ // Add our song-beat-effect. Remember to uncomment the update in the spectrum effect if you want to remove this.
+ _keyboard.AttachEffect(new SongBeatEffect(_soundDataProcessor, Color.FromArgb(127, 164, 164, 164)));
+
+ // Add our spectrum-effect using the soundDataProcessor and a rainbow from purple to red as gradient
+ _keyboard.AttachEffect(new AudioSpectrumEffect(_soundDataProcessor, new RainbowGradient(300, -14)));
+
+ // If you don't like rainbows replace the gradient with anything you like. For example:
+ //_keyboard.AttachEffect(new AudioSpectrumEffect(_soundDataProcessor, new LinearGradient(new GradientStop(0f, Color.Blue), new GradientStop(1f, Color.Red))));
+
+ // We need something to block since the keyboard-effect-update-loop is running async and the console-app would exit otherwise.
+ Console.WriteLine("Press any key to exit ...");
+ Console.ReadKey();
+ }
+
+ #endregion
+
+ #region TakeAsIs
+
+ private void InitBass()
+ {
+ BassHelper.InitializeBass();
+
+ // Ask for device to use
+ List> bassDevices = BassHelper.GetBassDevices();
+ int? selectedIndex = null;
+ do
+ {
+ Console.Clear();
+ Console.WriteLine("Select device:");
+
+ for (int i = 0; i < bassDevices.Count && i < 10; i++)
+ Console.WriteLine($" {i}. {bassDevices[i].Item1}");
+
+ char input = Console.ReadKey().KeyChar;
+ int tmp;
+ if (int.TryParse(input.ToString(), out tmp) && tmp < bassDevices.Count)
+ selectedIndex = tmp;
+
+ } while (!selectedIndex.HasValue);
+ Console.WriteLine();
+
+ _soundDataProcessor = new SoundDataProcessor(bassDevices[selectedIndex.Value].Item2) { VolumeScalar = VOLUME_SCALAR };
+ }
+
+ public static void Main(string[] args)
+ {
+ try
+ {
+ AudioAnalyzerExample aae = new AudioAnalyzerExample();
+ aae.InitBass();
+ aae.Initialize();
+ aae.Run();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error while running the Audio-Analyzer-Example: {ex.Message}");
+ Console.ReadKey();
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs
new file mode 100644
index 0000000..933d2f5
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Drawing;
+using CUE.NET.Brushes;
+using CUE.NET.Gradients;
+using Example_AudioAnalyzer_full.TakeAsIs;
+
+namespace Example_AudioAnalyzer_full
+{
+ // Extending from LinearGradientBrush since this is all we want to draw - of course you could implement everything on your own
+ public class AudioSpectrumBrush : LinearGradientBrush
+ {
+ #region Properties & Fields
+
+ public float[] BarData { get; set; }
+
+ #endregion
+
+ #region Constructors
+
+ // default values for start/end are fine
+ public AudioSpectrumBrush(IGradient gradient)
+ : base(gradient)
+ { }
+
+ #endregion
+
+ #region Methods
+
+ public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
+ {
+ if (BarData == null) return Color.Transparent;
+
+ // This logic is also stolen from AterialDawn
+ int barSampleIndex = (int)Math.Floor(BarData.Length * (point.X / (rectangle.X + rectangle.Width))); // Calculate bar sampling index
+ float curBarHeight = 1f - Utility.Clamp(BarData[barSampleIndex], 0f, 1f); // Invert this value since the keyboard is laid out with topleft being point 0,0
+ float verticalPos = (point.Y / rectangle.Height);
+
+ // If the barHeight is lower than the vertical pos currently calculated return the brush value. Otherwise do nothing by returning transparent.
+ return curBarHeight <= verticalPos ? base.GetColorAtPoint(rectangle, point) : Color.Transparent;
+ }
+
+ #endregion
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumEffect.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumEffect.cs
new file mode 100644
index 0000000..d14b736
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumEffect.cs
@@ -0,0 +1,45 @@
+using CUE.NET.Brushes;
+using CUE.NET.Effects;
+using CUE.NET.Gradients;
+using Example_AudioAnalyzer_full.TakeAsIs;
+
+namespace Example_AudioAnalyzer_full
+{
+ public class AudioSpectrumEffect : AbstractEffect
+ {
+ #region Properties & Fields
+
+ private SoundDataProcessor _dataProcessor;
+
+ private AudioSpectrumBrush _audioSpectrumBrush;
+ public override IBrush EffectBrush => _audioSpectrumBrush;
+
+ #endregion
+
+ #region Constructors
+
+ public AudioSpectrumEffect(SoundDataProcessor dataProcessor, IGradient gradient)
+ {
+ this._dataProcessor = dataProcessor;
+ _audioSpectrumBrush = new AudioSpectrumBrush(gradient);
+
+ // Give this effect a high Z-Index to keep it in the foreground
+ ZIndex = 10;
+ }
+
+ #endregion
+
+ #region Methods
+
+ public override void Update(float deltaTime)
+ {
+ // calculate new data ... - we don't need to do this, since we know that the song beat-effect already calculated them
+ //_dataProcessor.Process();
+
+ // ... and update the brush
+ _audioSpectrumBrush.BarData = _dataProcessor.BarValues;
+ }
+
+ #endregion
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Bass.Net.dll b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Bass.Net.dll
new file mode 100644
index 0000000..24dad7c
Binary files /dev/null and b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Bass.Net.dll differ
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj
new file mode 100644
index 0000000..7983309
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj
@@ -0,0 +1,105 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}
+ Exe
+ Properties
+ Example_AudioAnalyzer_full
+ Example_AudioAnalyzer_full
+ v4.6
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+ False
+ .\Bass.Net.dll
+
+
+
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Code
+
+
+
+
+
+
+
+
+ {70a266b5-e9d4-4eaa-a91a-947c0039ffb6}
+ CUE.NET
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+ xcopy "$(SolutionDir)libs\x86\CUESDK_2013.dll" "$(TargetDir)x86\" /y
+
+
+
\ No newline at end of file
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj.DotSettings b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj.DotSettings
new file mode 100644
index 0000000..b35dc7e
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Example_AudioAnalyzer_full.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Properties/AssemblyInfo.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..51ec5e3
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+using System.Reflection;
+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("Example_AudioAnalyzer_full")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Wyrez")]
+[assembly: AssemblyProduct("Example_AudioAnalyzer_full")]
+[assembly: AssemblyCopyright("Copyright © Wyrez 2015")]
+[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/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/SongBeatEffect.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/SongBeatEffect.cs
new file mode 100644
index 0000000..c47f066
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/SongBeatEffect.cs
@@ -0,0 +1,59 @@
+using System.Drawing;
+using CUE.NET.Brushes;
+using CUE.NET.Effects;
+using Example_AudioAnalyzer_full.TakeAsIs;
+
+namespace Example_AudioAnalyzer_full
+{
+ public class SongBeatEffect : AbstractEffect
+ {
+ #region Constants
+
+ // This value is really hard to tweak since it highly depends on the music played ... But hey, this is a example after all - feel free to change this until it looks good for you
+ private const float SONG_BEAT_THRESHOLD = 0.9f;
+
+ private const float FLASH_DURATION = 0.15f;
+
+ #endregion
+
+ #region Properties & Fields
+
+ private SoundDataProcessor _dataProcessor;
+
+ private float _currentEffect = -1f;
+
+ private SolidColorBrush _brush;
+ public override IBrush EffectBrush => _brush;
+
+ #endregion
+
+ #region Constructors
+
+ public SongBeatEffect(SoundDataProcessor dataProcessor, Color color)
+ {
+ this._dataProcessor = dataProcessor;
+ _brush = new SolidColorBrush(color);
+ }
+
+ #endregion
+
+ #region Methods
+
+ public override void Update(float deltaTime)
+ {
+ // calculate new data ...
+ _dataProcessor.Process();
+
+ // ... update the effect-data ...
+ if (_dataProcessor.SongBeat >= SONG_BEAT_THRESHOLD)
+ _currentEffect = FLASH_DURATION;
+ else
+ _currentEffect -= deltaTime;
+
+ // and set the current brush-opacity
+ _brush.Opacity = _currentEffect > 0f ? (_currentEffect / FLASH_DURATION) : 0f;
+ }
+
+ #endregion
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/BassHelper.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/BassHelper.cs
new file mode 100644
index 0000000..1150919
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/BassHelper.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using Un4seen.Bass;
+using Un4seen.BassWasapi;
+
+namespace Example_AudioAnalyzer_full.TakeAsIs
+{
+ public static class BassHelper
+ {
+ public static void InitializeBass()
+ {
+ BassNet.Registration("trial@trial.com", "2X1837515183722");
+ BassNet.OmitCheckVersion = true;
+ if (!Bass.LoadMe())
+ throw new WASAPIInitializationException("Unable to load bass.dll!");
+
+ if (!Bass.BASS_Init(0, 48000, 0, IntPtr.Zero))
+ throw new WASAPIInitializationException("Unable to initialize the BASS library!");
+
+ if (!BassWasapi.LoadMe())
+ throw new WASAPIInitializationException("Unable to load BassWasapi.dll!");
+
+ Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0);
+ }
+
+ public static List> GetBassDevices()
+ {
+ List> deviceList = new List>();
+
+ BASS_WASAPI_DEVICEINFO[] devices = BassWasapi.BASS_WASAPI_GetDeviceInfos();
+ for (int i = 0; i < devices.Length; i++)
+ {
+ BASS_WASAPI_DEVICEINFO device = devices[i];
+ if (!device.IsEnabled || !device.SupportsRecording) continue;
+
+ string deviceName = device.name;
+ if (device.IsLoopback)
+ deviceName += " (Loopback)";
+
+ deviceList.Add(new Tuple(deviceName, i));
+ }
+
+ return deviceList;
+ }
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/SoundDataProcessor.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/SoundDataProcessor.cs
new file mode 100644
index 0000000..2dea3d7
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/SoundDataProcessor.cs
@@ -0,0 +1,176 @@
+/*
+ * ###################################################################################################################
+ * # Thanks to AterialDawn #
+ * # #
+ * # Source: https://github.com/AterialDawn/CUEAudioVisualizer/blob/master/CUEAudioVisualizer/SoundDataProcessor.cs #
+ * # Date: 23.10.2015 #
+ * # Commit: 9106ab777d70a23254872455c6f3cefbe9bef6ca #
+ * # #
+ * ###################################################################################################################
+ *
+ * > Note < This code is refactored and all parts not used inb this tutorial are removed.
+ */
+
+using System;
+using Un4seen.Bass;
+using Un4seen.BassWasapi;
+
+namespace Example_AudioAnalyzer_full.TakeAsIs
+{
+ public class SoundDataProcessor
+ {
+ private const int BAR_COUNT = 1000;
+
+ public float[] BarValues = new float[BAR_COUNT];
+ public float VolumeScalar = 1f;
+ public float SongBeat = 0;
+
+ private float _averagedVolume = 0;
+ private int _wasapiDeviceIndex = -1;
+ private BASSData _maxFft = (BASSData.BASS_DATA_FFT8192);
+ private float[] _fftData = new float[4096];
+ private float[] _freqVolScalar = new float[BAR_COUNT];
+ private float[] _barValues = new float[BAR_COUNT];
+ private int _sampleFrequency = 48000;
+ private int _maximumFrequency = 21000;
+ private int _minimumFrequency = 0;
+ private int _maximumFrequencyIndex;
+ private int _minimumFrequencyIndex;
+ private int _deviceNumber;
+ private int[] _logIndex = new int[BAR_COUNT];
+ private bool _deviceInitialized = false;
+ private WASAPIPROC _wasapiProc;
+
+ public SoundDataProcessor(int deviceIndex)
+ {
+ this._wasapiDeviceIndex = deviceIndex;
+
+ BuildLookupTables();
+ _wasapiProc = IgnoreDataProc;
+ }
+
+ public void Process()
+ {
+ if (_deviceNumber != _wasapiDeviceIndex || !_deviceInitialized)
+ {
+ UpdateDevice();
+ _deviceNumber = BassWasapi.BASS_WASAPI_GetDevice();
+ }
+
+ if (!_deviceInitialized) return;
+
+ GetBarData();
+ float curVol = BassWasapi.BASS_WASAPI_GetDeviceLevel(_deviceNumber, -1) * VolumeScalar;
+ _averagedVolume = Utility.Clamp(Utility.LinearInterpolate(_averagedVolume, curVol, 0.02f), 0f, 1f);
+ }
+
+ private void UpdateDevice()
+ {
+ if (_wasapiDeviceIndex == -1) return;
+ if (_deviceInitialized)
+ {
+ Console.WriteLine("Deinitializing WASAPI device");
+ BassWasapi.BASS_WASAPI_Stop(true);
+ BassWasapi.BASS_WASAPI_Free();
+ _deviceInitialized = false;
+ }
+ BASS_WASAPI_DEVICEINFO devInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(_wasapiDeviceIndex);
+ if (devInfo == null)
+ throw new WASAPIInitializationException("Device " + _wasapiDeviceIndex + " is invalid!");
+
+ if (!BassWasapi.BASS_WASAPI_Init(_wasapiDeviceIndex, devInfo.mixfreq, 2, BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_BUFFER, 0f, 0f, _wasapiProc, IntPtr.Zero))
+ {
+ BASSError error = Bass.BASS_ErrorGetCode();
+ throw new WASAPIInitializationException("Unable to initialize WASAPI device " + _wasapiDeviceIndex, error);
+ }
+
+ if (!BassWasapi.BASS_WASAPI_Start())
+ {
+ BASSError error = Bass.BASS_ErrorGetCode();
+ throw new WASAPIInitializationException("Unable to start WASAPI!", error);
+ }
+
+ Console.WriteLine("WASAPI device initialized");
+ _deviceNumber = _wasapiDeviceIndex;
+ _sampleFrequency = devInfo.mixfreq;
+ BuildLookupTables();
+ _deviceInitialized = true;
+ }
+
+ private void BuildLookupTables()
+ {
+ _maximumFrequencyIndex = Math.Min(Utils.FFTFrequency2Index(_maximumFrequency, 8192, _sampleFrequency) + 1, 4095);
+ _minimumFrequencyIndex = Math.Min(Utils.FFTFrequency2Index(_minimumFrequency, 8192, _sampleFrequency), 4095);
+ _freqVolScalar[0] = 1f;
+ for (int i = 1; i < BAR_COUNT; i++)
+ {
+ _logIndex[i] = (int)((Math.Log(BAR_COUNT, BAR_COUNT) - Math.Log(BAR_COUNT - i, BAR_COUNT)) * (_maximumFrequencyIndex - _minimumFrequencyIndex) + _minimumFrequencyIndex);
+ _freqVolScalar[i] = 1 + (float)Math.Sqrt((double)i / (double)BAR_COUNT) * 1.25f;
+ }
+ }
+
+ private void GetBarData()
+ {
+ //Get FFT data
+ BassWasapi.BASS_WASAPI_GetData(_fftData, (int)_maxFft);
+ int barIndex = 0;
+ //Calculate bar values by squaring fftData from log(x) fft bin, and multiply by a few magic values to end up with a somewhat reasonable graphical representation of the sound
+ for (barIndex = 0; barIndex < BAR_COUNT; barIndex++)
+ {
+ _barValues[barIndex] = ((float)Math.Sqrt(_fftData[_logIndex[barIndex]]) * 15f * VolumeScalar) * _freqVolScalar[barIndex];
+ }
+ barIndex = 0;
+
+ //This chunk of code is supposed to do a rolling average to smooth out the lower values to look cleaner for another visualizer i'm working on
+ float preScaled;
+
+ float preScaled1 = _barValues[barIndex];
+ preScaled1 += _barValues[barIndex + 1];
+ preScaled1 /= 2f;
+ BarValues[barIndex] = Utility.Clamp(preScaled1, 0f, 1f);
+
+ barIndex++;
+
+ preScaled1 = _barValues[barIndex - 1] * 0.75f;
+ preScaled1 += _barValues[barIndex];
+ preScaled1 += _barValues[barIndex + 1] * 0.75f;
+ preScaled1 /= 2.5f;
+ BarValues[barIndex] = Utility.Clamp(preScaled1, 0f, 1f);
+
+ for (barIndex = 2; barIndex < 50; barIndex++)
+ {
+ preScaled = _barValues[barIndex - 2] * 0.5f;
+ preScaled += _barValues[barIndex - 1] * 0.75f;
+ preScaled += _barValues[barIndex];
+ preScaled += _barValues[barIndex + 1] * 0.75f;
+ preScaled += _barValues[barIndex + 2] * 0.5f;
+ preScaled /= 3.5f;
+ BarValues[barIndex] = Utility.Clamp(preScaled, 0f, 1f);
+ }
+ for (barIndex = 50; barIndex < 999; barIndex++)
+ {
+ preScaled = _barValues[barIndex - 1] * 0.75f;
+ preScaled += _barValues[barIndex];
+ preScaled += _barValues[barIndex + 1] * 0.75f;
+ preScaled /= 2.5f;
+ BarValues[barIndex] = Utility.Clamp(preScaled, 0f, 1f);
+ }
+ preScaled = _barValues[barIndex - 1];
+ preScaled += _barValues[barIndex];
+ preScaled /= 2f;
+ BarValues[barIndex] = Utility.Clamp(preScaled, 0f, 1f);
+
+ //Calculate the song beat
+ float sum = 0f;
+ for (int i = 2; i < 28; i++)
+ sum += (float)Math.Sqrt(_barValues[i]); //Prettier scaling > Accurate scaling
+
+ SongBeat = (sum / 25f);
+ }
+
+ private static int IgnoreDataProc(IntPtr buffer, int length, IntPtr user)
+ {
+ return 1;
+ }
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/Utility.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/Utility.cs
new file mode 100644
index 0000000..bbf8170
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/Utility.cs
@@ -0,0 +1,30 @@
+/*
+ * ###################################################################################################################
+ * # Thanks to AterialDawn #
+ * # #
+ * # Source: https://github.com/AterialDawn/CUEAudioVisualizer/blob/master/CUEAudioVisualizer/Utility.cs #
+ * # Date: 23.10.2015 #
+ * # Commit: d415fd1dda2e7fd98391ac83c000d7e4a781558e #
+ * # #
+ * ###################################################################################################################
+ *
+ * > Note < This code is refactored and all parts not used inb this tutorial are removed.
+ */
+
+using System;
+
+namespace Example_AudioAnalyzer_full.TakeAsIs
+{
+ public static class Utility
+ {
+ public static float Clamp(float value, float min, float max)
+ {
+ return Math.Min(Math.Max(value, min), max);
+ }
+
+ public static float LinearInterpolate(float absMin, float absMax, float value)
+ {
+ return (value / (1f / (absMax - absMin))) + absMin;
+ }
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/WASAPIInitializationException.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/WASAPIInitializationException.cs
new file mode 100644
index 0000000..cff7769
--- /dev/null
+++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/TakeAsIs/WASAPIInitializationException.cs
@@ -0,0 +1,26 @@
+/*
+ * ###################################################################################################################
+ * # Thanks to AterialDawn #
+ * # #
+ * # Source: https://github.com/AterialDawn/CUEAudioVisualizer/blob/master/CUEAudioVisualizer/Exceptions/WASAPIInitializationException.cs #
+ * # Date: 23.10.2015 #
+ * # Commit: d415fd1dda2e7fd98391ac83c000d7e4a781558e #
+ * # #
+ * ###################################################################################################################
+ *
+ * > Note < This code is refactored and all parts not used inb this tutorial are removed.
+ */
+
+using System;
+using Un4seen.Bass;
+
+namespace Example_AudioAnalyzer_full.TakeAsIs
+{
+ public class WASAPIInitializationException : Exception
+ {
+ public BASSError? OptionalError { get; private set; }
+
+ public WASAPIInitializationException(string message) : base(message) { OptionalError = null; }
+ public WASAPIInitializationException(string message, BASSError error) : base(message) { OptionalError = error; }
+ }
+}
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/bass.dll b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/bass.dll
new file mode 100644
index 0000000..963bea5
Binary files /dev/null and b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/bass.dll differ
diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/basswasapi.dll b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/basswasapi.dll
new file mode 100644
index 0000000..be5b95c
Binary files /dev/null and b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/basswasapi.dll differ