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:
parent
0c862fc6de
commit
6ed251a484
10
CUE.NET.sln
10
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
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Bass.Net.dll
Normal file
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/Bass.Net.dll
Normal file
Binary file not shown.
@ -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>
|
||||
@ -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>
|
||||
@ -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")]
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/bass.dll
Normal file
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/bass.dll
Normal file
Binary file not shown.
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/basswasapi.dll
Normal file
BIN
Examples/AudioAnalyzer/Example_AudioAnalyzer_full/basswasapi.dll
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user