mirror of
https://github.com/DarthAffe/KeyboardAudioVisualizer.git
synced 2025-12-12 15:18:30 +00:00
Added Equalizer-UI
This commit is contained in:
parent
4d92282b73
commit
9dcf82e6aa
@ -1,4 +1,5 @@
|
|||||||
using RGB.NET.Core;
|
using KeyboardAudioVisualizer.Helper;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
||||||
{
|
{
|
||||||
@ -13,7 +14,7 @@ namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (!IsFixedOffset)
|
if (!IsFixedOffset)
|
||||||
SetProperty(ref _offset, value);
|
SetProperty(ref _offset, float.IsNaN(value) ? 0 : MathHelper.Clamp(value, 0, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
|||||||
public float Value
|
public float Value
|
||||||
{
|
{
|
||||||
get => _value;
|
get => _value;
|
||||||
set => SetProperty(ref _value, value);
|
set => SetProperty(ref _value, float.IsNaN(value) ? 0 : MathHelper.Clamp(value, -1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsFixedOffset { get; }
|
public bool IsFixedOffset { get; }
|
||||||
|
|||||||
@ -9,5 +9,8 @@ namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
|||||||
ObservableCollection<EqualizerBand> Bands { get; }
|
ObservableCollection<EqualizerBand> Bands { get; }
|
||||||
|
|
||||||
float[] CalculateValues(int count);
|
float[] CalculateValues(int count);
|
||||||
|
|
||||||
|
EqualizerBand AddBand(float offset, float modification);
|
||||||
|
void RemoveBandBand(EqualizerBand band);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
||||||
{
|
{
|
||||||
public class MultiBandEqualizer : IEqualizer
|
public class MultiBandEqualizer : AbstractBindable, IEqualizer
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
public ObservableCollection<EqualizerBand> Bands { get; } = new ObservableCollection<EqualizerBand>();
|
public ObservableCollection<EqualizerBand> Bands { get; } = new ObservableCollection<EqualizerBand>();
|
||||||
|
|
||||||
private float[] _values;
|
private readonly Dictionary<int, float[]> _values = new Dictionary<int, float[]>();
|
||||||
|
|
||||||
public bool IsEnabled { get; set; } = true;
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
@ -27,40 +30,64 @@ namespace KeyboardAudioVisualizer.AudioProcessing.Equalizer
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public void AddBand(float frequency, float modification, bool isFixedFrequency = false)
|
public EqualizerBand AddBand(float offset, float modification) => AddBand(offset, modification, false);
|
||||||
|
|
||||||
|
public EqualizerBand AddBand(float offset, float modification, bool isFixedFrequency)
|
||||||
{
|
{
|
||||||
EqualizerBand band = new EqualizerBand(frequency, modification, isFixedFrequency);
|
EqualizerBand band = new EqualizerBand(offset, modification, isFixedFrequency);
|
||||||
band.PropertyChanged += (sender, args) => InvalidateCache();
|
band.PropertyChanged += (sender, args) => InvalidateCache();
|
||||||
Bands.Add(band);
|
Bands.Add(band);
|
||||||
|
|
||||||
InvalidateCache();
|
InvalidateCache();
|
||||||
|
|
||||||
|
return band;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] CalculateValues(int values)
|
public void RemoveBandBand(EqualizerBand band)
|
||||||
{
|
{
|
||||||
if ((_values == null) || (_values.Length != values))
|
if (!band.IsFixedOffset)
|
||||||
|
Bands.Remove(band);
|
||||||
|
|
||||||
|
InvalidateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] CalculateValues(int count)
|
||||||
|
{
|
||||||
|
if (!_values.TryGetValue(count, out float[] values))
|
||||||
{
|
{
|
||||||
_values = new float[values];
|
values = RecalculateValues(count);
|
||||||
RecalculateValues();
|
_values[count] = values;
|
||||||
}
|
}
|
||||||
return _values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecalculateValues()
|
private float[] RecalculateValues(int count)
|
||||||
{
|
{
|
||||||
float width = _values.Length;
|
float[] values = new float[count];
|
||||||
for (int i = 0; i < _values.Length; i++)
|
|
||||||
|
List<EqualizerBand> orderedBands = Bands.OrderBy(x => x.Offset).ToList();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
float offset = (i / width);
|
float offset = (i / (float)count);
|
||||||
EqualizerBand bandBefore = Bands.Last(n => n.Offset <= offset);
|
EqualizerBand bandBefore = orderedBands.Last(n => n.Offset <= offset);
|
||||||
EqualizerBand bandAfter = Bands.First(n => n.Offset >= offset);
|
EqualizerBand bandAfter = orderedBands.First(n => n.Offset >= offset);
|
||||||
offset = bandAfter.Offset <= 0 ? 0 : (offset - bandBefore.Offset) / (bandAfter.Offset - bandBefore.Offset);
|
offset = (bandAfter.Offset <= 0) || (Math.Abs(bandAfter.Offset - bandBefore.Offset) < 0.0001)
|
||||||
|
? 0 : (offset - bandBefore.Offset) / (bandAfter.Offset - bandBefore.Offset);
|
||||||
float value = (float)((3.0 * (offset * offset)) - (2.0 * (offset * offset * offset)));
|
float value = (float)((3.0 * (offset * offset)) - (2.0 * (offset * offset * offset)));
|
||||||
_values[i] = bandBefore.Value + (value * (bandAfter.Value - bandBefore.Value));
|
values[i] = bandBefore.Value + (value * (bandAfter.Value - bandBefore.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InvalidateCache() => _values = null;
|
private void InvalidateCache()
|
||||||
|
{
|
||||||
|
_values.Clear();
|
||||||
|
|
||||||
|
// ReSharper disable once ExplicitCallerInfoArgument
|
||||||
|
OnPropertyChanged(nameof(Bands));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
|
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
|
||||||
using KeyboardAudioVisualizer.AudioProcessing.Spectrum;
|
using KeyboardAudioVisualizer.AudioProcessing.Spectrum;
|
||||||
using KeyboardAudioVisualizer.Configuration;
|
using KeyboardAudioVisualizer.Configuration;
|
||||||
|
using KeyboardAudioVisualizer.Helper;
|
||||||
|
|
||||||
namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
|
namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
|
||||||
{
|
{
|
||||||
@ -131,10 +132,21 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
|
|||||||
|
|
||||||
for (int i = 0; i < spectrum.BandCount; i++)
|
for (int i = 0; i < spectrum.BandCount; i++)
|
||||||
{
|
{
|
||||||
double binPower = Math.Max(0, 20 * Math.Log10(GetBandValue(spectrum[i])));
|
double binPower = GetBandValue(spectrum[i]);
|
||||||
|
|
||||||
if (equalizerValues != null)
|
if (equalizerValues != null)
|
||||||
binPower += equalizerValues[i];
|
{
|
||||||
|
float equalizerValue = equalizerValues[i];
|
||||||
|
equalizerValue *= 10; //TODO DarthAffe 13.08.2017: Equalizer-Scale through setting?
|
||||||
|
if (Math.Abs(equalizerValue) > 0.000001)
|
||||||
|
{
|
||||||
|
bool lower = equalizerValue < 0;
|
||||||
|
equalizerValue = 1 + (equalizerValue * equalizerValue);
|
||||||
|
binPower *= lower ? 1f / equalizerValue : equalizerValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binPower = Math.Max(0, 20 * Math.Log10(binPower));
|
||||||
|
|
||||||
binPower = Math.Max(0, binPower);
|
binPower = Math.Max(0, binPower);
|
||||||
binPower /= _configuration.ReferenceLevel;
|
binPower /= _configuration.ReferenceLevel;
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
|
||||||
|
|
||||||
|
namespace KeyboardAudioVisualizer.Converter
|
||||||
|
{
|
||||||
|
public class EqualizerBandsToPointsConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
PointCollection points = new PointCollection();
|
||||||
|
|
||||||
|
if ((values.Length != 4) || (parameter == DependencyProperty.UnsetValue)
|
||||||
|
|| (values[0] == null) || (values[0] == DependencyProperty.UnsetValue)
|
||||||
|
|| (values[1] == null) || (values[1] == DependencyProperty.UnsetValue) //HACK DarthAffe 13.08.2017: I need this only to update the binding
|
||||||
|
|| (values[2] == null) || (values[2] == DependencyProperty.UnsetValue)
|
||||||
|
|| (values[3] == null) || (values[3] == DependencyProperty.UnsetValue))
|
||||||
|
return points;
|
||||||
|
|
||||||
|
IEqualizer equalizer = (IEqualizer)values[0];
|
||||||
|
double width = (double)values[2];
|
||||||
|
double height = (double)values[3];
|
||||||
|
int valueCount = int.Parse(parameter.ToString());
|
||||||
|
double halfHeight = height / 2.0;
|
||||||
|
|
||||||
|
List<(float offset, float value)> pointValues = equalizer.Bands.Select(b => (b.Offset, b.Value)).ToList();
|
||||||
|
float[] calculatedValues = equalizer.CalculateValues(valueCount);
|
||||||
|
for (int i = 0; i < calculatedValues.Length; i++)
|
||||||
|
pointValues.Add(((float)i / calculatedValues.Length, calculatedValues[i]));
|
||||||
|
|
||||||
|
foreach ((float offset, float value) in pointValues.OrderBy(x => x.offset))
|
||||||
|
points.Add(new Point(offset * width, GetPosY(value, halfHeight)));
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetPosY(float offset, double halfHeight)
|
||||||
|
{
|
||||||
|
if (offset < 0)
|
||||||
|
return halfHeight + (-offset * halfHeight);
|
||||||
|
|
||||||
|
if (offset > 0)
|
||||||
|
return halfHeight - (offset * halfHeight);
|
||||||
|
|
||||||
|
return halfHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,31 +5,22 @@ using System.Windows.Data;
|
|||||||
|
|
||||||
namespace KeyboardAudioVisualizer.Converter
|
namespace KeyboardAudioVisualizer.Converter
|
||||||
{
|
{
|
||||||
public class ValueToPosYConverter : IMultiValueConverter
|
public class OffsetToPosXConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if ((values.Length != 3) || (values[0] == null) || (values[0] == DependencyProperty.UnsetValue)
|
if ((values.Length != 2) || (parameter == DependencyProperty.UnsetValue)
|
||||||
|| (values[1] == null) || (values[1] == DependencyProperty.UnsetValue)
|
|| (values[0] == null) || (values[0] == DependencyProperty.UnsetValue)
|
||||||
|| (values[2] == null) || (values[2] == DependencyProperty.UnsetValue))
|
|| (values[1] == null) || (values[1] == DependencyProperty.UnsetValue))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float val = (float)values[0];
|
float offset = (float)values[0];
|
||||||
double height = (double)values[1];
|
double width = (double)values[1];
|
||||||
double reference = (double)values[2];
|
double correction = double.Parse(parameter.ToString());
|
||||||
|
|
||||||
double halfHeight = height / 2.0;
|
return (offset * width) - correction;
|
||||||
|
|
||||||
double offset = val / reference;
|
|
||||||
if (offset < 0)
|
|
||||||
return halfHeight + (-offset * halfHeight);
|
|
||||||
|
|
||||||
if (offset > 0)
|
|
||||||
return halfHeight - (offset * halfHeight);
|
|
||||||
|
|
||||||
return halfHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||||
|
|||||||
@ -5,20 +5,30 @@ using System.Windows.Data;
|
|||||||
|
|
||||||
namespace KeyboardAudioVisualizer.Converter
|
namespace KeyboardAudioVisualizer.Converter
|
||||||
{
|
{
|
||||||
public class OffsetToPosXConverter : IMultiValueConverter
|
public class ValueToPosYConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if ((values.Length != 2) || (values[0] == null) || (values[0] == DependencyProperty.UnsetValue)
|
if ((values.Length != 2) || (parameter == DependencyProperty.UnsetValue)
|
||||||
|| (values[1] == null) || (values[1] == DependencyProperty.UnsetValue))
|
|| (values[0] == null) || (values[0] == DependencyProperty.UnsetValue)
|
||||||
|
|| (values[1] == null) || (values[1] == DependencyProperty.UnsetValue))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float offset = (float)values[0];
|
float offset = (float)values[0];
|
||||||
double width = (double)values[1];
|
double height = (double)values[1];
|
||||||
|
double correction = double.Parse(parameter.ToString());
|
||||||
|
|
||||||
return offset * width;
|
double halfHeight = height / 2.0;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return (halfHeight + (-offset * halfHeight)) - correction;
|
||||||
|
|
||||||
|
if (offset > 0)
|
||||||
|
return (halfHeight - (offset * halfHeight)) - correction;
|
||||||
|
|
||||||
|
return halfHeight - correction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||||
|
|||||||
32
KeyboardAudioVisualizer/Helper/WPFHelper.cs
Normal file
32
KeyboardAudioVisualizer/Helper/WPFHelper.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace KeyboardAudioVisualizer.Helper
|
||||||
|
{
|
||||||
|
public static class WPFHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static T GetVisualChild<T>(this DependencyObject parent)
|
||||||
|
where T : Visual
|
||||||
|
{
|
||||||
|
T child = default(T);
|
||||||
|
|
||||||
|
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
|
||||||
|
for (int i = 0; i < numVisuals; i++)
|
||||||
|
{
|
||||||
|
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
|
||||||
|
child = v as T;
|
||||||
|
|
||||||
|
if (child == null)
|
||||||
|
child = GetVisualChild<T>(v);
|
||||||
|
|
||||||
|
if (child != null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -131,13 +131,15 @@
|
|||||||
<Compile Include="Controls\Formular.cs" />
|
<Compile Include="Controls\Formular.cs" />
|
||||||
<Compile Include="Controls\ImageButton.cs" />
|
<Compile Include="Controls\ImageButton.cs" />
|
||||||
<Compile Include="Converter\BoolToVisibilityConverter.cs" />
|
<Compile Include="Converter\BoolToVisibilityConverter.cs" />
|
||||||
|
<Compile Include="Converter\EqualizerBandsToPointsConverter.cs" />
|
||||||
<Compile Include="Converter\EqualsToBoolConverter.cs" />
|
<Compile Include="Converter\EqualsToBoolConverter.cs" />
|
||||||
<Compile Include="Converter\ValueToPosYConverter.cs" />
|
|
||||||
<Compile Include="Converter\OffsetToPosXConverter.cs" />
|
<Compile Include="Converter\OffsetToPosXConverter.cs" />
|
||||||
|
<Compile Include="Converter\ValueToPosYConverter.cs" />
|
||||||
<Compile Include="Helper\ActionCommand.cs" />
|
<Compile Include="Helper\ActionCommand.cs" />
|
||||||
<Compile Include="Helper\ExceptionExtension.cs" />
|
<Compile Include="Helper\ExceptionExtension.cs" />
|
||||||
<Compile Include="Helper\FrequencyHelper.cs" />
|
<Compile Include="Helper\FrequencyHelper.cs" />
|
||||||
<Compile Include="Helper\MathHelper.cs" />
|
<Compile Include="Helper\MathHelper.cs" />
|
||||||
|
<Compile Include="Helper\WPFHelper.cs" />
|
||||||
<Compile Include="Settings.cs" />
|
<Compile Include="Settings.cs" />
|
||||||
<Compile Include="Controls\BlurredDecorationWindow.cs" />
|
<Compile Include="Controls\BlurredDecorationWindow.cs" />
|
||||||
<Compile Include="Styles\CachedResourceDictionary.cs" />
|
<Compile Include="Styles\CachedResourceDictionary.cs" />
|
||||||
@ -248,6 +250,10 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="UI\Visualization\EqualizerVisualization.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="UI\Visualization\FrequencyBarsVisualization.xaml">
|
<Page Include="UI\Visualization\FrequencyBarsVisualization.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|||||||
@ -0,0 +1,127 @@
|
|||||||
|
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles"
|
||||||
|
xmlns:visualization="clr-namespace:KeyboardAudioVisualizer.UI.Visualization"
|
||||||
|
xmlns:equalizer="clr-namespace:KeyboardAudioVisualizer.AudioProcessing.Equalizer"
|
||||||
|
xmlns:converter="clr-namespace:KeyboardAudioVisualizer.Converter">
|
||||||
|
|
||||||
|
<styles:CachedResourceDictionary.MergedDictionaries>
|
||||||
|
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/FrameworkElement.xaml" />
|
||||||
|
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Theme.xaml" />
|
||||||
|
</styles:CachedResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<converter:OffsetToPosXConverter x:Key="OffsetToPosXConverter" />
|
||||||
|
<converter:ValueToPosYConverter x:Key="ValueToPosYConverter" />
|
||||||
|
<converter:EqualizerBandsToPointsConverter x:Key="EqualizerBandsToPointsConverter" />
|
||||||
|
|
||||||
|
<Style x:Key="StyleEqualizerVisualizer"
|
||||||
|
BasedOn="{StaticResource StyleFrameworkElement}"
|
||||||
|
TargetType="{x:Type visualization:EqualizerVisualizer}">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="False" />
|
||||||
|
<Setter Property="UseLayoutRounding" Value="False" />
|
||||||
|
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type visualization:EqualizerVisualizer}">
|
||||||
|
<Grid x:Name="Container" Background="Transparent">
|
||||||
|
<Polyline x:Name="PART_Line" Stroke="White" StrokeThickness="2" StrokeLineJoin="Round">
|
||||||
|
<Polyline.Points>
|
||||||
|
<MultiBinding Converter="{StaticResource EqualizerBandsToPointsConverter}" ConverterParameter="120">
|
||||||
|
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Equalizer" />
|
||||||
|
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Equalizer.Bands" />
|
||||||
|
<Binding Path="ActualWidth" ElementName="Container" />
|
||||||
|
<Binding Path="ActualHeight" ElementName="Container" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Polyline.Points>
|
||||||
|
</Polyline>
|
||||||
|
|
||||||
|
<ItemsControl x:Name="PART_Grips" Opacity="0"
|
||||||
|
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Equalizer.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||||
|
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Equalizer.Bands}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<Canvas />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate DataType="equalizer:EqualizerBand">
|
||||||
|
<Border Width="24" Height="24" CornerRadius="12"
|
||||||
|
BorderThickness="3" BorderBrush="{StaticResource BrushEqualizerBorder}"
|
||||||
|
Background="{StaticResource BrushEqualizerBackground}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
|
||||||
|
<ItemsControl.ItemContainerStyle>
|
||||||
|
<Style TargetType="ContentPresenter">
|
||||||
|
<Setter Property="Canvas.Left">
|
||||||
|
<Setter.Value>
|
||||||
|
<MultiBinding Converter="{StaticResource OffsetToPosXConverter}" ConverterParameter="12">
|
||||||
|
<Binding Path="Offset" />
|
||||||
|
<Binding Path="ActualWidth" ElementName="PART_Grips" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Canvas.Top">
|
||||||
|
<Setter.Value>
|
||||||
|
<MultiBinding Converter="{StaticResource ValueToPosYConverter}" ConverterParameter="12">
|
||||||
|
<Binding Path="Value" />
|
||||||
|
<Binding Path="ActualHeight" ElementName="PART_Grips" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ItemsControl.ItemContainerStyle>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True" />
|
||||||
|
<!--<Condition Binding="{Binding Path=Equalizer.IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type visualization:EqualizerVisualizer}}}" Value="True" />-->
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<MultiDataTrigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Duration="0:0:0.2" To="1"
|
||||||
|
Storyboard.TargetName="PART_Grips" Storyboard.TargetProperty="Opacity" />
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</MultiDataTrigger.EnterActions>
|
||||||
|
<MultiDataTrigger.ExitActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Duration="0:0:0.25" To="0"
|
||||||
|
Storyboard.TargetName="PART_Grips" Storyboard.TargetProperty="Opacity" />
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</MultiDataTrigger.ExitActions>
|
||||||
|
</MultiDataTrigger>
|
||||||
|
|
||||||
|
<!--<DataTrigger Binding="{Binding Path=Equalizer.IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type visualization:EqualizerVisualizer}}}" Value="False">
|
||||||
|
<DataTrigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Duration="0:0:0.2" To="1"
|
||||||
|
Storyboard.TargetName="PART_Line" Storyboard.TargetProperty="Opacity" />
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</DataTrigger.EnterActions>
|
||||||
|
<DataTrigger.ExitActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Duration="0:0:0.25" To="0"
|
||||||
|
Storyboard.TargetName="PART_Line" Storyboard.TargetProperty="Opacity" />
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</DataTrigger.ExitActions>
|
||||||
|
</DataTrigger>-->
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
</styles:CachedResourceDictionary>
|
||||||
|
|
||||||
@ -1,10 +1,13 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
|
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
|
||||||
|
using KeyboardAudioVisualizer.Helper;
|
||||||
|
|
||||||
namespace KeyboardAudioVisualizer.UI.Visualization
|
namespace KeyboardAudioVisualizer.UI.Visualization
|
||||||
{
|
{
|
||||||
//[TemplatePart(Name = "PART_Grips", Type = typeof(Canvas))]
|
[TemplatePart(Name = "PART_Grips", Type = typeof(ItemsControl))]
|
||||||
public class EqualizerVisualizer : Control
|
public class EqualizerVisualizer : Control
|
||||||
{
|
{
|
||||||
#region DependencyProperties
|
#region DependencyProperties
|
||||||
@ -19,82 +22,103 @@ namespace KeyboardAudioVisualizer.UI.Visualization
|
|||||||
set => SetValue(EqualizerProperty, value);
|
set => SetValue(EqualizerProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DependencyProperty ReferenceLevelProperty = DependencyProperty.Register(
|
|
||||||
"ReferenceLevel", typeof(double), typeof(EqualizerVisualizer), new PropertyMetadata(default(double)));
|
|
||||||
|
|
||||||
public double ReferenceLevel
|
|
||||||
{
|
|
||||||
get => (double)GetValue(ReferenceLevelProperty);
|
|
||||||
set => SetValue(ReferenceLevelProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper restore InconsistentNaming
|
// ReSharper restore InconsistentNaming
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
//private Canvas _canvas;
|
private ItemsControl _grips;
|
||||||
|
private EqualizerBand _draggingBand;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
//public EqualizerVisualizer()
|
|
||||||
//{
|
|
||||||
// SizeChanged += (sender, args) => Update();
|
|
||||||
// Update();
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
//public override void OnApplyTemplate()
|
public override void OnApplyTemplate()
|
||||||
//{
|
{
|
||||||
// base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
// _canvas = GetTemplateChild("PART_Grips") as Canvas;
|
_grips = GetTemplateChild("PART_Grips") as ItemsControl;
|
||||||
//}
|
}
|
||||||
|
|
||||||
//private static void EqualizerChanged(DependencyObject dependencyObject,
|
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||||
// DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
{
|
||||||
//{
|
base.OnMouseLeftButtonDown(e);
|
||||||
// EqualizerVisualizer visualizer = dependencyObject as EqualizerVisualizer;
|
|
||||||
// if (visualizer == null) return;
|
|
||||||
|
|
||||||
// void BandsChanged(object sender, NotifyCollectionChangedEventArgs args) => visualizer.Update();
|
EqualizerBand band = GetClickedBand();
|
||||||
|
if (band != null)
|
||||||
|
_draggingBand = band;
|
||||||
|
}
|
||||||
|
|
||||||
// if (dependencyPropertyChangedEventArgs.OldValue is IEqualizer oldEqualizer)
|
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||||
// oldEqualizer.Bands.CollectionChanged -= BandsChanged;
|
{
|
||||||
|
base.OnMouseLeftButtonUp(e);
|
||||||
|
|
||||||
// if (dependencyPropertyChangedEventArgs.NewValue is IEqualizer newEqualizer)
|
_draggingBand = null;
|
||||||
// newEqualizer.Bands.CollectionChanged += BandsChanged;
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
//private void Update()
|
protected override void OnMouseLeave(MouseEventArgs e)
|
||||||
//{
|
{
|
||||||
// if (_canvas == null) return;
|
base.OnMouseLeave(e);
|
||||||
|
|
||||||
// void OnBandChanged(object sender, PropertyChangedEventArgs args) => Update();
|
_draggingBand = null;
|
||||||
|
}
|
||||||
|
|
||||||
// foreach (object child in _canvas.Children)
|
protected override void OnMouseMove(MouseEventArgs e)
|
||||||
// {
|
{
|
||||||
// EqualizerBand band = (child as ContentControl)?.Content as EqualizerBand;
|
base.OnMouseMove(e);
|
||||||
// if (band == null) continue;
|
|
||||||
// band.PropertyChanged -= OnBandChanged;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _canvas.Children.Clear();
|
if (_draggingBand == null) return;
|
||||||
|
|
||||||
// foreach (EqualizerBand band in Equalizer.Bands)
|
UpdateBand(_draggingBand, e.GetPosition(_grips));
|
||||||
// {
|
}
|
||||||
// ContentControl ctrl = new ContentControl();
|
|
||||||
|
|
||||||
// ctrl.Content = band;
|
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseRightButtonDown(e);
|
||||||
|
|
||||||
// _canvas.Children.Add(ctrl);
|
if (_grips == null) return;
|
||||||
// }
|
|
||||||
//}
|
EqualizerBand band = GetClickedBand();
|
||||||
|
if (band == null)
|
||||||
|
{
|
||||||
|
EqualizerBand newBand = Equalizer.AddBand(0, 0);
|
||||||
|
UpdateBand(newBand, e.GetPosition(_grips));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Equalizer.RemoveBandBand(band);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBand(EqualizerBand band, Point position)
|
||||||
|
{
|
||||||
|
double halfHeight = _grips.ActualHeight / 2.0;
|
||||||
|
|
||||||
|
band.Offset = (float)(position.X / _grips.ActualWidth);
|
||||||
|
band.Value = (float)(-(position.Y - halfHeight) / halfHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EqualizerBand GetClickedBand()
|
||||||
|
{
|
||||||
|
ItemsPresenter itemsPresenter = _grips.GetVisualChild<ItemsPresenter>();
|
||||||
|
if (itemsPresenter == null) return null;
|
||||||
|
|
||||||
|
Panel panel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel;
|
||||||
|
if (panel == null) return null;
|
||||||
|
|
||||||
|
foreach (UIElement element in panel.Children)
|
||||||
|
if (element.IsMouseOver)
|
||||||
|
{
|
||||||
|
EqualizerBand band = ((element as ContentPresenter)?.Content as EqualizerBand);
|
||||||
|
if (band != null) return band;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles"
|
xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles"
|
||||||
xmlns:visualizationProvider="clr-namespace:KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider"
|
xmlns:visualizationProvider="clr-namespace:KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider"
|
||||||
xmlns:visualization="clr-namespace:KeyboardAudioVisualizer.UI.Visualization"
|
xmlns:visualization="clr-namespace:KeyboardAudioVisualizer.UI.Visualization"
|
||||||
xmlns:equalizer="clr-namespace:KeyboardAudioVisualizer.AudioProcessing.Equalizer"
|
|
||||||
xmlns:converter="clr-namespace:KeyboardAudioVisualizer.Converter">
|
xmlns:converter="clr-namespace:KeyboardAudioVisualizer.Converter">
|
||||||
|
|
||||||
<styles:CachedResourceDictionary.MergedDictionaries>
|
<styles:CachedResourceDictionary.MergedDictionaries>
|
||||||
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/FrameworkElement.xaml" />
|
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/FrameworkElement.xaml" />
|
||||||
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Theme.xaml" />
|
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Theme.xaml" />
|
||||||
|
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/UI/Visualization/EqualizerVisualization.xaml" />
|
||||||
</styles:CachedResourceDictionary.MergedDictionaries>
|
</styles:CachedResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<converter:OffsetToPosXConverter x:Key="OffsetToPosXConverter" />
|
<converter:OffsetToPosXConverter x:Key="OffsetToPosXConverter" />
|
||||||
@ -29,86 +29,10 @@
|
|||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="StyleEqualizerVisualizer"
|
|
||||||
BasedOn="{StaticResource StyleFrameworkElement}"
|
|
||||||
TargetType="{x:Type visualization:EqualizerVisualizer}">
|
|
||||||
<Setter Property="SnapsToDevicePixels" Value="False" />
|
|
||||||
<Setter Property="UseLayoutRounding" Value="False" />
|
|
||||||
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="{x:Type visualization:EqualizerVisualizer}">
|
|
||||||
<Grid Background="Transparent">
|
|
||||||
<ItemsControl x:Name="PART_Grips" Opacity="0" Margin="-12,-12,12,12"
|
|
||||||
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Equalizer.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"
|
|
||||||
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Equalizer.Bands}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<Canvas />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate DataType="equalizer:EqualizerBand">
|
|
||||||
<Border Width="24" Height="24" CornerRadius="12"
|
|
||||||
BorderThickness="3" BorderBrush="{StaticResource BrushEqualizerBorder}"
|
|
||||||
Background="{StaticResource BrushEqualizerBackground}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
|
|
||||||
<ItemsControl.ItemContainerStyle>
|
|
||||||
<Style TargetType="ContentPresenter">
|
|
||||||
<Setter Property="Canvas.Left">
|
|
||||||
<Setter.Value>
|
|
||||||
<MultiBinding Converter="{StaticResource OffsetToPosXConverter}">
|
|
||||||
<Binding Path="Offset" />
|
|
||||||
<Binding Path="ActualWidth" ElementName="PART_Grips" />
|
|
||||||
</MultiBinding>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="Canvas.Top">
|
|
||||||
<Setter.Value>
|
|
||||||
<MultiBinding Converter="{StaticResource ValueToPosYConverter}">
|
|
||||||
<Binding Path="Value" />
|
|
||||||
<Binding Path="ActualHeight" ElementName="PART_Grips" />
|
|
||||||
<Binding Path="ReferenceLevel" RelativeSource="{RelativeSource AncestorType={x:Type visualization:EqualizerVisualizer}}" />
|
|
||||||
</MultiBinding>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</ItemsControl.ItemContainerStyle>
|
|
||||||
</ItemsControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsMouseOver" Value="True">
|
|
||||||
<Trigger.EnterActions>
|
|
||||||
<BeginStoryboard>
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Duration="0:0:0.2" To="1"
|
|
||||||
Storyboard.TargetName="PART_Grips" Storyboard.TargetProperty="Opacity" />
|
|
||||||
</Storyboard>
|
|
||||||
</BeginStoryboard>
|
|
||||||
</Trigger.EnterActions>
|
|
||||||
<Trigger.ExitActions>
|
|
||||||
<BeginStoryboard>
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Duration="0:0:0.25" To="0"
|
|
||||||
Storyboard.TargetName="PART_Grips" Storyboard.TargetProperty="Opacity" />
|
|
||||||
</Storyboard>
|
|
||||||
</BeginStoryboard>
|
|
||||||
</Trigger.ExitActions>
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<DataTemplate DataType="{x:Type visualizationProvider:FrequencyBarsVisualizationProvider}">
|
<DataTemplate DataType="{x:Type visualizationProvider:FrequencyBarsVisualizationProvider}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<visualization:FrequencyBarsVisualizer Style="{StaticResource StyleFrequencyBarsVisualizer}" VisualizationProvider="{Binding}" />
|
<visualization:FrequencyBarsVisualizer Style="{StaticResource StyleFrequencyBarsVisualizer}" VisualizationProvider="{Binding}" />
|
||||||
<visualization:EqualizerVisualizer Style="{StaticResource StyleEqualizerVisualizer}" Equalizer="{Binding Equalizer}" ReferenceLevel="{Binding Configuration.ReferenceLevel}" />
|
<visualization:EqualizerVisualizer Style="{StaticResource StyleEqualizerVisualizer}" Equalizer="{Binding Equalizer}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user