mirror of
https://github.com/DarthAffe/CUE.NET.git
synced 2025-12-13 09:08:34 +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
|
libs\x64\CUESDK_2013.dll = libs\x64\CUESDK_2013.dll
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{7FD88256-5E14-4D7C-862B-7BC2CD04081A}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -51,5 +59,7 @@ Global
|
|||||||
{D69EF6D8-68FF-4C56-B5CB-253971B1DF91} = {FF50AF6A-D2AC-4772-B013-C10D127DBE29}
|
{D69EF6D8-68FF-4C56-B5CB-253971B1DF91} = {FF50AF6A-D2AC-4772-B013-C10D127DBE29}
|
||||||
{0525D895-E706-4920-8733-DABD9194BFB1} = {D69EF6D8-68FF-4C56-B5CB-253971B1DF91}
|
{0525D895-E706-4920-8733-DABD9194BFB1} = {D69EF6D8-68FF-4C56-B5CB-253971B1DF91}
|
||||||
{2F99124B-FAED-432D-B797-45566D373411} = {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
|
EndGlobalSection
|
||||||
EndGlobal
|
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