1
0
mirror of https://github.com/DarthAffe/CUE.NET.git synced 2025-12-12 16:58:29 +00:00

Added AudioAnalyzer-Example

This commit is contained in:
Darth Affe 2015-10-23 22:54:09 +02:00
parent 0c862fc6de
commit 6ed251a484
16 changed files with 731 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>

View File

@ -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<Tuple<string, int>> 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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Example_AudioAnalyzer_full</RootNamespace>
<AssemblyName>Example_AudioAnalyzer_full</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Bass.Net, Version=2.4.8.4, Culture=neutral, PublicKeyToken=b7566c273e6ef480, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\Bass.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="AudioAnalyzerExample.cs" />
<Compile Include="AudioSpectrumBrush.cs" />
<Compile Include="AudioSpectrumEffect.cs" />
<Compile Include="SongBeatEffect.cs" />
<Compile Include="TakeAsIs\BassHelper.cs" />
<Compile Include="TakeAsIs\SoundDataProcessor.cs" />
<Compile Include="TakeAsIs\Utility.cs" />
<Compile Include="TakeAsIs\WASAPIInitializationException.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\CUE.NET.csproj">
<Project>{70a266b5-e9d4-4eaa-a91a-947c0039ffb6}</Project>
<Name>CUE.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="bass.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="basswasapi.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(SolutionDir)libs\x86\CUESDK_2013.dll" "$(TargetDir)x86\" /y</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=libs/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -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
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> 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")]

View File

@ -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
}
}

View File

@ -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<Tuple<string, int>> GetBassDevices()
{
List<Tuple<string, int>> deviceList = new List<Tuple<string, int>>();
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<string, int>(deviceName, i));
}
return deviceList;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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; }
}
}