From 427d42f1bbbf7be8fecdce07ea9e68339d928588 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 12 Aug 2017 19:19:25 +0200 Subject: [PATCH] Added tons of UI-stuff (working configuration and visualization for all providers) --- KeyboardAudioVisualizer/App.config | 10 +- KeyboardAudioVisualizer/ApplicationManager.cs | 18 ++- .../AudioProcessing/AudioProcessor.cs | 18 +-- .../FrequencyBarsVisualizationProvider.cs | 29 ++-- .../LevelVisualizationProvider.cs | 3 +- .../Configuration/IConfiguration.cs | 6 +- KeyboardAudioVisualizer/Controls/Formular.cs | 22 ++- .../Converter/EqualsToBoolConverter.cs | 18 +++ .../KeyboardAudioVisualizer.csproj | 36 ++++- .../Resources/KeyboardAudioVisualizer.xaml | 7 +- KeyboardAudioVisualizer/Styles/ComboBox.xaml | 144 ++++++++++++++++++ KeyboardAudioVisualizer/Styles/Formular.xaml | 5 +- KeyboardAudioVisualizer/Styles/GroupBox.xaml | 3 +- KeyboardAudioVisualizer/Styles/Theme.xaml | 10 +- .../UI/Configuration/BeatConfiguration.xaml | 29 ++++ .../FrequencyBarsConfiguration.xaml | 63 +++++++- .../UI/Configuration/LevelConfiguration.xaml | 57 +++++++ .../UI/ConfigurationWindow.xaml | 80 +++++++++- .../UI/Visualization/BeatVisualization.xaml | 32 ++++ .../UI/Visualization/BeatVisualizer.cs | 80 ++++++++++ .../FrequencyBarsVisualization.xaml | 32 ++++ .../Visualization/FrequencyBarsVisualizer.cs | 142 +++++++++++++++++ .../UI/Visualization/LevelVisualization.xaml | 70 +++++++++ .../UI/Visualization/LevelVisualizer.cs | 97 ++++++++++++ KeyboardAudioVisualizer/packages.config | 2 +- 25 files changed, 951 insertions(+), 62 deletions(-) create mode 100644 KeyboardAudioVisualizer/Converter/EqualsToBoolConverter.cs create mode 100644 KeyboardAudioVisualizer/Styles/ComboBox.xaml create mode 100644 KeyboardAudioVisualizer/UI/Configuration/BeatConfiguration.xaml create mode 100644 KeyboardAudioVisualizer/UI/Configuration/LevelConfiguration.xaml create mode 100644 KeyboardAudioVisualizer/UI/Visualization/BeatVisualization.xaml create mode 100644 KeyboardAudioVisualizer/UI/Visualization/BeatVisualizer.cs create mode 100644 KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualization.xaml create mode 100644 KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualizer.cs create mode 100644 KeyboardAudioVisualizer/UI/Visualization/LevelVisualization.xaml create mode 100644 KeyboardAudioVisualizer/UI/Visualization/LevelVisualizer.cs diff --git a/KeyboardAudioVisualizer/App.config b/KeyboardAudioVisualizer/App.config index 731f6de..7381577 100644 --- a/KeyboardAudioVisualizer/App.config +++ b/KeyboardAudioVisualizer/App.config @@ -1,6 +1,14 @@ - + + + + + + + + + \ No newline at end of file diff --git a/KeyboardAudioVisualizer/ApplicationManager.cs b/KeyboardAudioVisualizer/ApplicationManager.cs index bd6e9d8..ea612b1 100644 --- a/KeyboardAudioVisualizer/ApplicationManager.cs +++ b/KeyboardAudioVisualizer/ApplicationManager.cs @@ -91,12 +91,12 @@ namespace KeyboardAudioVisualizer //new ListLedGroup(device).Brush = new BeatBrush(AudioProcessor.Instance.PrimaryVisualizationProvider, new Color(255, 255, 255)); //{ - // ILedGroup left = new RectangleLedGroup(new Rectangle(device.Location.X, device.Location.Y, device.Size.Width / 2.0, device.Size.Height)); - // ILedGroup right = new RectangleLedGroup(new Rectangle(device.Location.X + (device.Size.Width / 2.0), device.Location.Y, device.Size.Width / 2.0, device.Size.Height)); + // ILedGroup left1 = new RectangleLedGroup(new Rectangle(device.Location.X, device.Location.Y, device.Size.Width / 2.0, device.Size.Height)); + // ILedGroup right1 = new RectangleLedGroup(new Rectangle(device.Location.X + (device.Size.Width / 2.0), device.Location.Y, device.Size.Width / 2.0, device.Size.Height)); // IGradient levelGradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)), new GradientStop(1, new Color(255, 0, 0))); - // left.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, levelGradient, LevelBarDirection.Left, 0); - // right.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, levelGradient, LevelBarDirection.Right, 1); + // left1.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, levelGradient, LevelBarDirection.Left, 0); + // right1.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, levelGradient, LevelBarDirection.Right, 1); //} break; @@ -105,8 +105,14 @@ namespace KeyboardAudioVisualizer ILedGroup right = new RectangleLedGroup(new Rectangle(device.Location.X + (device.Size.Width / 2.0), device.Location.Y, device.Size.Width / 2.0, device.Size.Height)); IGradient mousematLevelGradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)), new GradientStop(1, new Color(255, 0, 0))); - left.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, mousematLevelGradient, LevelBarDirection.Top, 0); - right.Brush = new LevelBarBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, mousematLevelGradient, LevelBarDirection.Top, 1); + left.Brush = new LevelBarBrush(AudioProcessor.Instance.TertiaryVisualizationProvider, mousematLevelGradient, LevelBarDirection.Top, 0); + right.Brush = new LevelBarBrush(AudioProcessor.Instance.TertiaryVisualizationProvider, mousematLevelGradient, LevelBarDirection.Top, 1); + break; + + case RGBDeviceType.Mouse: + case RGBDeviceType.Headset: + ILedGroup deviceGroup = new ListLedGroup(device); + deviceGroup.Brush = new BeatBrush(AudioProcessor.Instance.SecondaryVisualizationProvider, new Color(255, 255, 255)); break; } diff --git a/KeyboardAudioVisualizer/AudioProcessing/AudioProcessor.cs b/KeyboardAudioVisualizer/AudioProcessing/AudioProcessor.cs index 2e12345..71661aa 100644 --- a/KeyboardAudioVisualizer/AudioProcessing/AudioProcessor.cs +++ b/KeyboardAudioVisualizer/AudioProcessing/AudioProcessor.cs @@ -8,12 +8,6 @@ namespace KeyboardAudioVisualizer.AudioProcessing { public class AudioProcessor : IDisposable { - #region Constants - - private const int MAXIMUM_UPDATE_RATE = 40; // We won't allow to change the FPS beyond this - - #endregion - #region Properties & Fields public static AudioProcessor Instance { get; private set; } @@ -24,6 +18,7 @@ namespace KeyboardAudioVisualizer.AudioProcessing public IVisualizationProvider PrimaryVisualizationProvider { get; private set; } public IVisualizationProvider SecondaryVisualizationProvider { get; private set; } + public IVisualizationProvider TertiaryVisualizationProvider { get; private set; } #endregion @@ -38,8 +33,10 @@ namespace KeyboardAudioVisualizer.AudioProcessing public void Update() { _spectrumProvider.Update(); - PrimaryVisualizationProvider.Update(); - SecondaryVisualizationProvider.Update(); + + PrimaryVisualizationProvider?.Update(); + SecondaryVisualizationProvider?.Update(); + TertiaryVisualizationProvider?.Update(); } public static void Initialize() @@ -67,8 +64,11 @@ namespace KeyboardAudioVisualizer.AudioProcessing //PrimaryVisualizationProvider = new BeatVisualizationProvider(new BeatVisualizationProviderConfiguration(), _spectrumProvider); PrimaryVisualizationProvider.Initialize(); - SecondaryVisualizationProvider = new LevelVisualizationProvider(new LevelVisualizationProviderConfiguration(), _audioBuffer); + SecondaryVisualizationProvider = new BeatVisualizationProvider(new BeatVisualizationProviderConfiguration(), _spectrumProvider); SecondaryVisualizationProvider.Initialize(); + + TertiaryVisualizationProvider = new LevelVisualizationProvider(new LevelVisualizationProviderConfiguration(), _audioBuffer); + TertiaryVisualizationProvider.Initialize(); } public void Dispose() => _audioInput.Dispose(); diff --git a/KeyboardAudioVisualizer/AudioProcessing/VisualizationPRovider/FrequencyBarsVisualizationProvider.cs b/KeyboardAudioVisualizer/AudioProcessing/VisualizationPRovider/FrequencyBarsVisualizationProvider.cs index 5d7f9b3..267eaa9 100644 --- a/KeyboardAudioVisualizer/AudioProcessing/VisualizationPRovider/FrequencyBarsVisualizationProvider.cs +++ b/KeyboardAudioVisualizer/AudioProcessing/VisualizationPRovider/FrequencyBarsVisualizationProvider.cs @@ -12,14 +12,14 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider public class FrequencyBarsVisualizationProviderConfiguration : AbstractConfiguration { - private ValueMode _valueMode = ValueMode.Max; + private ValueMode _valueMode = ValueMode.Sum; public ValueMode ValueMode { get => _valueMode; set => SetProperty(ref _valueMode, value); } - private SpectrumMode _spectrumMode = SpectrumMode.Gamma; + private SpectrumMode _spectrumMode = SpectrumMode.Logarithmic; public SpectrumMode SpectrumMode { get => _spectrumMode; @@ -40,15 +40,15 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider set => SetProperty(ref _smoothing, value); } - private float _minFrequency = 60; - public float MinFrequency + private double _minFrequency = 60; + public double MinFrequency { get => _minFrequency; set => SetProperty(ref _minFrequency, value); } - private float _maxFrequency = 15000; - public float MaxFrequency + private double _maxFrequency = 15000; + public double MaxFrequency { get => _maxFrequency; set => SetProperty(ref _maxFrequency, value); @@ -61,8 +61,8 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider set => SetProperty(ref _referenceLevel, value); } - private float _emphasisePeaks = 0.5f; - public float EmphasisePeaks + private double _emphasisePeaks = 0.5f; + public double EmphasisePeaks { get => _emphasisePeaks; set => SetProperty(ref _emphasisePeaks, value); @@ -147,8 +147,11 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider if (_configuration.EmphasisePeaks > 0.001) binPower = Math.Pow(binPower, 1 + _configuration.EmphasisePeaks) * _emphasiseFactor; - VisualizationData[i] = (float)((VisualizationData[i] * _smoothingFactor) + (binPower * (1.0 - _smoothingFactor))); - if (float.IsNaN(VisualizationData[i])) VisualizationData[i] = 0; + if (i < VisualizationData.Length) + { + VisualizationData[i] = (float)((VisualizationData[i] * _smoothingFactor) + (binPower * (1.0 - _smoothingFactor))); + if (float.IsNaN(VisualizationData[i])) VisualizationData[i] = 0; + } } } @@ -157,11 +160,11 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider switch (_configuration.SpectrumMode) { case SpectrumMode.Gamma: - return _spectrumProvider.GetGammaSpectrum(_configuration.Bars, _configuration.Gamma, _configuration.MinFrequency, _configuration.MaxFrequency); + return _spectrumProvider.GetGammaSpectrum(_configuration.Bars, _configuration.Gamma, (float)_configuration.MinFrequency, (float)_configuration.MaxFrequency); case SpectrumMode.Logarithmic: - return _spectrumProvider.GetLogarithmicSpectrum(_configuration.Bars, _configuration.MinFrequency, _configuration.MaxFrequency); + return _spectrumProvider.GetLogarithmicSpectrum(_configuration.Bars, (float)_configuration.MinFrequency, (float)_configuration.MaxFrequency); case SpectrumMode.Linear: - return _spectrumProvider.GetLinearSpectrum(_configuration.Bars, _configuration.MinFrequency, _configuration.MaxFrequency); + return _spectrumProvider.GetLinearSpectrum(_configuration.Bars, (float)_configuration.MinFrequency, (float)_configuration.MaxFrequency); default: return null; } diff --git a/KeyboardAudioVisualizer/AudioProcessing/VisualizationProvider/LevelVisualizationProvider.cs b/KeyboardAudioVisualizer/AudioProcessing/VisualizationProvider/LevelVisualizationProvider.cs index fbb8554..f4d6c18 100644 --- a/KeyboardAudioVisualizer/AudioProcessing/VisualizationProvider/LevelVisualizationProvider.cs +++ b/KeyboardAudioVisualizer/AudioProcessing/VisualizationProvider/LevelVisualizationProvider.cs @@ -2,6 +2,7 @@ using System.Linq; using KeyboardAudioVisualizer.AudioCapture; using KeyboardAudioVisualizer.Configuration; +using KeyboardAudioVisualizer.Helper; namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider { @@ -89,7 +90,7 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider private void RecalculateConfigValues(string changedPropertyName) { if ((changedPropertyName == null) || (changedPropertyName == nameof(LevelVisualizationProviderConfiguration.Smoothing))) - _smoothingFactor = Math.Log10(_configuration.Smoothing); + _smoothingFactor = Math.Log10(MathHelper.Clamp(_configuration.Smoothing, 0.001, 9.5)); if ((changedPropertyName == null) || (changedPropertyName == nameof(LevelVisualizationProviderConfiguration.Scale)) || (changedPropertyName == nameof(LevelVisualizationProviderConfiguration.ConversionMode))) diff --git a/KeyboardAudioVisualizer/Configuration/IConfiguration.cs b/KeyboardAudioVisualizer/Configuration/IConfiguration.cs index 87e3044..ac4755f 100644 --- a/KeyboardAudioVisualizer/Configuration/IConfiguration.cs +++ b/KeyboardAudioVisualizer/Configuration/IConfiguration.cs @@ -1,5 +1,7 @@ -namespace KeyboardAudioVisualizer.Configuration +using System.ComponentModel; + +namespace KeyboardAudioVisualizer.Configuration { // DarthAffe 05.08.2017: Marker interface - public interface IConfiguration { } + public interface IConfiguration : INotifyPropertyChanged { } } diff --git a/KeyboardAudioVisualizer/Controls/Formular.cs b/KeyboardAudioVisualizer/Controls/Formular.cs index 5ef7148..ed82f12 100644 --- a/KeyboardAudioVisualizer/Controls/Formular.cs +++ b/KeyboardAudioVisualizer/Controls/Formular.cs @@ -77,6 +77,12 @@ namespace KeyboardAudioVisualizer.Controls public static void SetRowSpan(DependencyObject element, int value) => element.SetValue(RowSpanProperty, value); public static int GetRowSpan(DependencyObject element) => (int)element.GetValue(RowSpanProperty); + public static readonly DependencyProperty FillProperty = DependencyProperty.RegisterAttached("Fill", typeof(bool), typeof(Formular), + new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); + + public static void SetFill(DependencyObject element, bool value) => element.SetValue(FillProperty, value); + public static bool GetFill(DependencyObject element) => (bool)element.GetValue(FillProperty); + // ReSharper restore InconsistentNaming #endregion @@ -91,7 +97,7 @@ namespace KeyboardAudioVisualizer.Controls foreach (UIElement child in InternalChildren) { child.Measure(availableSize); - layout.AddElement(child); + layout.AddElement(child, 0); } return new Size(layout.Width, layout.Height); @@ -104,9 +110,9 @@ namespace KeyboardAudioVisualizer.Controls FormularLayout layout = new FormularLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing); foreach (UIElement child in InternalChildren) - child.Arrange(layout.AddElement(child)); + child.Arrange(layout.AddElement(child, finalSize.Width)); - return new Size(layout.Width, layout.Height); + return new Size(finalSize.Width, layout.Height); } #endregion @@ -146,7 +152,7 @@ namespace KeyboardAudioVisualizer.Controls #region Methods - public Rect AddElement(UIElement element) + public Rect AddElement(UIElement element, double targetWidth) { bool isLabel = GetIsLabel(element); int lineBreaks = GetLineBreaks(element); @@ -177,9 +183,13 @@ namespace KeyboardAudioVisualizer.Controls if (element is FrameworkElement fe) fe.MaxHeight = height; - Rect rect = new Rect(new Point(_currentRowWidth, (_rows * _rowHeight) + (_rows * _rowSpacing)), new Size(elementWidth, height)); + double width = elementWidth; + if ((targetWidth >= 1) && GetFill(element)) + width = targetWidth - _currentRowWidth; - _currentRowWidth += elementWidth + _elementSpacing; + Rect rect = new Rect(new Point(_currentRowWidth, (_rows * _rowHeight) + (_rows * _rowSpacing)), new Size(width, height)); + + _currentRowWidth += width + _elementSpacing; return rect; } diff --git a/KeyboardAudioVisualizer/Converter/EqualsToBoolConverter.cs b/KeyboardAudioVisualizer/Converter/EqualsToBoolConverter.cs new file mode 100644 index 0000000..3856734 --- /dev/null +++ b/KeyboardAudioVisualizer/Converter/EqualsToBoolConverter.cs @@ -0,0 +1,18 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace KeyboardAudioVisualizer.Converter +{ + [ValueConversion(typeof(object), typeof(bool))] + public class EqualsToBoolConverter : IValueConverter + { + #region Methods + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => Equals(value, parameter); + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException(); + + #endregion + } +} diff --git a/KeyboardAudioVisualizer/KeyboardAudioVisualizer.csproj b/KeyboardAudioVisualizer/KeyboardAudioVisualizer.csproj index 7270621..df90530 100644 --- a/KeyboardAudioVisualizer/KeyboardAudioVisualizer.csproj +++ b/KeyboardAudioVisualizer/KeyboardAudioVisualizer.csproj @@ -73,8 +73,8 @@ - - ..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll + + ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll @@ -129,6 +129,7 @@ + @@ -140,6 +141,9 @@ ConfigurationWindow.xaml + + + @@ -191,6 +195,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + MSBuild:Compile Designer @@ -219,19 +227,37 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + MSBuild:Compile Designer + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + - - - + diff --git a/KeyboardAudioVisualizer/Resources/KeyboardAudioVisualizer.xaml b/KeyboardAudioVisualizer/Resources/KeyboardAudioVisualizer.xaml index 7e81dd1..dc8baaf 100644 --- a/KeyboardAudioVisualizer/Resources/KeyboardAudioVisualizer.xaml +++ b/KeyboardAudioVisualizer/Resources/KeyboardAudioVisualizer.xaml @@ -2,7 +2,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:KeyboardAudioVisualizer.UI" xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles" - xmlns:controls="clr-namespace:KeyboardAudioVisualizer.Controls"> + xmlns:controls="clr-namespace:KeyboardAudioVisualizer.Controls" + xmlns:converter="clr-namespace:KeyboardAudioVisualizer.Converter"> @@ -10,14 +11,18 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/KeyboardAudioVisualizer/Styles/Formular.xaml b/KeyboardAudioVisualizer/Styles/Formular.xaml index cc53cdd..7e58030 100644 --- a/KeyboardAudioVisualizer/Styles/Formular.xaml +++ b/KeyboardAudioVisualizer/Styles/Formular.xaml @@ -11,9 +11,10 @@ BasedOn="{StaticResource StyleFrameworkElement}" TargetType="{x:Type controls:Formular}"> - - + + + + + + + + + + \ No newline at end of file diff --git a/KeyboardAudioVisualizer/UI/Visualization/BeatVisualizer.cs b/KeyboardAudioVisualizer/UI/Visualization/BeatVisualizer.cs new file mode 100644 index 0000000..c7d9ef7 --- /dev/null +++ b/KeyboardAudioVisualizer/UI/Visualization/BeatVisualizer.cs @@ -0,0 +1,80 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; +using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider; +using RGB.NET.Core; +using Color = System.Windows.Media.Color; +using Point = System.Windows.Point; + +namespace KeyboardAudioVisualizer.UI.Visualization +{ + public class BeatVisualizer : Control + { + #region DependencyProperties + // ReSharper disable InconsistentNaming + + public static readonly DependencyProperty VisualizationProviderProperty = DependencyProperty.Register( + "VisualizationProvider", typeof(IVisualizationProvider), typeof(BeatVisualizer), new PropertyMetadata(default(IVisualizationProvider))); + + public IVisualizationProvider VisualizationProvider + { + get => (IVisualizationProvider)GetValue(VisualizationProviderProperty); + set => SetValue(VisualizationProviderProperty, value); + } + + public static readonly DependencyProperty BrushProperty = DependencyProperty.Register( + "Brush", typeof(Brush), typeof(BeatVisualizer), new PropertyMetadata(default(Brush))); + + public Brush Brush + { + get => (Brush)GetValue(BrushProperty); + set => SetValue(BrushProperty, value); + } + + public static readonly DependencyProperty BeatValueProperty = DependencyProperty.Register( + "BeatValue", typeof(float), typeof(BeatVisualizer), new PropertyMetadata(default(float))); + + public float BeatValue + { + get => (float)GetValue(BeatValueProperty); + set => SetValue(BeatValueProperty, value); + } + + // ReSharper restore InconsistentNaming + #endregion + + #region Constructors + + public BeatVisualizer() + { + RGBSurface.Instance.Updated += args => Dispatcher.BeginInvoke(new Action(Update), DispatcherPriority.Normal); + + //TODO DarthAffe 12.08.2017: Create brush from config + Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255)); + } + + #endregion + + #region Methods + + private void Update() + { + IVisualizationProvider visualizationProvider = VisualizationProvider; + if ((visualizationProvider == null) || (Visibility != Visibility.Visible)) return; + + if (visualizationProvider.VisualizationData[0] > 0.9) + BeatValue = 1f; + else if (BeatValue > 0.01f) + { + float newValue = BeatValue * 0.625f; + if (newValue > 0.01f) + BeatValue = newValue; + else BeatValue = 0; + } + } + + #endregion + } +} diff --git a/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualization.xaml b/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualization.xaml new file mode 100644 index 0000000..6d7d53f --- /dev/null +++ b/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualization.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualizer.cs b/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualizer.cs new file mode 100644 index 0000000..62dd797 --- /dev/null +++ b/KeyboardAudioVisualizer/UI/Visualization/FrequencyBarsVisualizer.cs @@ -0,0 +1,142 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; +using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider; +using RGB.NET.Brushes.Gradients; +using RGB.NET.Core; +using Color = System.Windows.Media.Color; +using Rectangle = System.Windows.Shapes.Rectangle; + +namespace KeyboardAudioVisualizer.UI.Visualization +{ + [TemplatePart(Name = "PART_BarsPanel", Type = typeof(Panel))] + public class FrequencyBarsVisualizer : Control + { + #region DependencyProperties + // ReSharper disable InconsistentNaming + + public static readonly DependencyProperty VisualizationProviderProperty = DependencyProperty.Register( + "VisualizationProvider", typeof(IVisualizationProvider), typeof(FrequencyBarsVisualizer), + new PropertyMetadata(default(IVisualizationProvider), VisualizationProviderChanged)); + + public IVisualizationProvider VisualizationProvider + { + get => (IVisualizationProvider)GetValue(VisualizationProviderProperty); + set => SetValue(VisualizationProviderProperty, value); + } + // ReSharper restore InconsistentNaming + #endregion + + #region Properties & Fields + + private IGradient _gradient; + private Panel _panel; + private Rectangle[] _bars = new Rectangle[0]; + + #endregion + + #region Constructors + + public FrequencyBarsVisualizer() + { + RGBSurface.Instance.Updated += args => Dispatcher.BeginInvoke(new Action(Update), DispatcherPriority.Normal); + SizeChanged += (sender, args) => UpdateSizes(); + + //TODO DarthAffe 12.08.2017: Get gradient from config + _gradient = new RainbowGradient(300, -14); + } + + #endregion + + #region Methods + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _panel = GetTemplateChild("PART_BarsPanel") as Panel; + + InitializeBars(); + } + + private static void VisualizationProviderChanged(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + FrequencyBarsVisualizer visualizer = dependencyObject as FrequencyBarsVisualizer; + if (visualizer == null) return; + + void ConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs args) => visualizer.ConfigurationChanged(args.PropertyName); + + if (dependencyPropertyChangedEventArgs.OldValue is IVisualizationProvider oldVisualizationProvider) + oldVisualizationProvider.Configuration.PropertyChanged -= ConfigurationOnPropertyChanged; + + if (dependencyPropertyChangedEventArgs.NewValue is IVisualizationProvider newVisualizationProvider) + newVisualizationProvider.Configuration.PropertyChanged += ConfigurationOnPropertyChanged; + } + + private void ConfigurationChanged(string changedPropertyName) + { + if ((changedPropertyName == null) || (changedPropertyName == nameof(FrequencyBarsVisualizationProviderConfiguration.Bars))) + InitializeBars(); + } + + private void InitializeBars() + { + if (_panel == null) return; + + _panel.Children.Clear(); + _bars = new Rectangle[((FrequencyBarsVisualizationProviderConfiguration)VisualizationProvider.Configuration).Bars]; + + for (int i = 0; i < _bars.Length; i++) + { + _bars[i] = new Rectangle { VerticalAlignment = VerticalAlignment.Bottom, Width = 0 }; + _panel.Children.Add(_bars[i]); + } + + UpdateSizes(); + UpdateColors(); + } + + private void UpdateSizes() + { + if (_bars.Length == 0) return; + + double barSpacing = ActualWidth / _bars.Length; + double barWidth = (barSpacing * 3.0) / 4.0; + double margin = barSpacing - barWidth; + + for (int i = 0; i < _bars.Length; i++) + { + _bars[i].Width = barWidth; + _bars[i].Margin = new Thickness(margin / 2, 0, margin / 2, 0); + } + } + + private void UpdateColors() + { + for (int i = 0; i < _bars.Length; i++) + { + RGB.NET.Core.Color color = _gradient.GetColor((double)i / _bars.Length); + _bars[i].Fill = new SolidColorBrush(Color.FromRgb(color.R, color.G, color.B)); + } + } + + private void Update() + { + IVisualizationProvider visualizationProvider = VisualizationProvider; + if ((visualizationProvider == null) || (Visibility != Visibility.Visible)) return; + + int count = Math.Min(_bars.Length, visualizationProvider.VisualizationData.Length); + for (int i = 0; i < count; i++) + { + _bars[i].Height = (float)((_bars[i].Height * 0.5) + ((ActualHeight * visualizationProvider.VisualizationData[i]) * (1.0 - 0.5))); + if (double.IsNaN(_bars[i].Height)) _bars[i].Height = 0; + } + } + + #endregion + } +} diff --git a/KeyboardAudioVisualizer/UI/Visualization/LevelVisualization.xaml b/KeyboardAudioVisualizer/UI/Visualization/LevelVisualization.xaml new file mode 100644 index 0000000..56e1111 --- /dev/null +++ b/KeyboardAudioVisualizer/UI/Visualization/LevelVisualization.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/KeyboardAudioVisualizer/UI/Visualization/LevelVisualizer.cs b/KeyboardAudioVisualizer/UI/Visualization/LevelVisualizer.cs new file mode 100644 index 0000000..a746688 --- /dev/null +++ b/KeyboardAudioVisualizer/UI/Visualization/LevelVisualizer.cs @@ -0,0 +1,97 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; +using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider; +using RGB.NET.Core; +using Color = System.Windows.Media.Color; +using Point = System.Windows.Point; + +namespace KeyboardAudioVisualizer.UI.Visualization +{ + public class LevelVisualizer : Control + { + #region DependencyProperties + // ReSharper disable InconsistentNaming + + public static readonly DependencyProperty VisualizationProviderProperty = DependencyProperty.Register( + "VisualizationProvider", typeof(IVisualizationProvider), typeof(LevelVisualizer), new PropertyMetadata(default(IVisualizationProvider))); + + public IVisualizationProvider VisualizationProvider + { + get => (IVisualizationProvider)GetValue(VisualizationProviderProperty); + set => SetValue(VisualizationProviderProperty, value); + } + + public static readonly DependencyProperty BrushLeftProperty = DependencyProperty.Register( + "BrushLeft", typeof(Brush), typeof(LevelVisualizer), new PropertyMetadata(default(Brush))); + + public Brush BrushLeft + { + get => (Brush)GetValue(BrushLeftProperty); + set => SetValue(BrushLeftProperty, value); + } + + public static readonly DependencyProperty BrushRightProperty = DependencyProperty.Register( + "BrushRight", typeof(Brush), typeof(LevelVisualizer), new PropertyMetadata(default(Brush))); + + public Brush BrushRight + { + get => (Brush)GetValue(BrushRightProperty); + set => SetValue(BrushRightProperty, value); + } + + public static readonly DependencyProperty SizeLeftProperty = DependencyProperty.Register( + "SizeLeft", typeof(int), typeof(LevelVisualizer), new PropertyMetadata(default(int))); + + public int SizeLeft + { + get => (int)GetValue(SizeLeftProperty); + set => SetValue(SizeLeftProperty, value); + } + + public static readonly DependencyProperty SizeRightProperty = DependencyProperty.Register( + "SizeRight", typeof(int), typeof(LevelVisualizer), new PropertyMetadata(default(int))); + + public int SizeRight + { + get => (int)GetValue(SizeRightProperty); + set => SetValue(SizeRightProperty, value); + } + + // ReSharper restore InconsistentNaming + #endregion + + #region Constructors + + public LevelVisualizer() + { + RGBSurface.Instance.Updated += args => Dispatcher.BeginInvoke(new Action(Update), DispatcherPriority.Normal); + + //TODO DarthAffe 12.08.2017: Create brush from config + BrushLeft = new LinearGradientBrush(Color.FromRgb(255, 0, 0), Color.FromRgb(0, 0, 255), new Point(0, 0.5), new Point(1, 0.5)); + BrushRight = new LinearGradientBrush(Color.FromRgb(0, 0, 255), Color.FromRgb(255, 0, 0), new Point(0, 0.5), new Point(1, 0.5)); + } + + #endregion + + #region Methods + + private void Update() + { + IVisualizationProvider visualizationProvider = VisualizationProvider; + if ((visualizationProvider == null) || (Visibility != Visibility.Visible)) return; + + int horizontalSizeLeft = (int)(visualizationProvider.VisualizationData[0] * (ActualWidth / 2)); + if (Math.Abs(SizeLeft - horizontalSizeLeft) > 1) + SizeLeft = horizontalSizeLeft; + + int horizontalSizeRight = (int)(visualizationProvider.VisualizationData[1] * (ActualWidth / 2)); + if (Math.Abs(SizeRight - horizontalSizeRight) > 1) + SizeRight = horizontalSizeRight; + } + + #endregion + } +} diff --git a/KeyboardAudioVisualizer/packages.config b/KeyboardAudioVisualizer/packages.config index 06f2799..e2069eb 100644 --- a/KeyboardAudioVisualizer/packages.config +++ b/KeyboardAudioVisualizer/packages.config @@ -9,5 +9,5 @@ - + \ No newline at end of file