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