Compare commits

...

29 Commits

Author SHA1 Message Date
008fd65c08
Update README.md 2021-08-05 23:43:58 +02:00
f7f30f36c7 Removed old MSI build-target 2019-12-03 15:48:03 +01:00
e62259ca63 Updated RGB.NET; added Steel-Series 2019-12-01 18:13:58 +01:00
b30bb88762 Bumped version number to 1.3.1.1 2019-06-09 19:28:59 +02:00
6ad2e861a0 Changed Settings-Serialization to work with hte new double-values in colors.
Fixes #50
2019-06-09 19:25:02 +02:00
967dde1d3d Bumped version number to 1.3.1 2019-05-26 14:34:49 +02:00
7216eae954 Updated RGB.NET 2019-05-26 14:34:39 +02:00
e94c0723c5 Updated nuget-packages 2019-01-06 10:26:44 +01:00
5dfc02eeab Bumped version-number to 1.3 2018-10-06 12:01:34 +02:00
806dd3aae7 Fixed default value of the background brush 2018-10-06 12:00:13 +02:00
dde304b007 Added setting to change the background-brush 2018-10-06 11:53:58 +02:00
7eac420a8e Updated RGB.NET 2018-10-06 11:53:35 +02:00
7cf179421f Merge branch 'master' of https://github.com/DarthAffe/KeyboardAudioVisualizer 2018-07-15 17:34:46 +02:00
b54e01a96b Bumped version-number to 1.2 2018-07-15 17:34:41 +02:00
7b6c2c184e Updated RGB.NET and included new device-types 2018-07-15 17:33:21 +02:00
8f53049bdf Updated audio capturing to make use of the SingleBlockRead-event 2018-07-15 17:17:42 +02:00
edwardbaeg
0ec92488e4 Fix typo (#4) 2018-03-10 09:46:24 +01:00
4141a5dd36 Bumped version number to 1.1 2018-02-09 23:21:15 +01:00
2ad4a6f333 Increased max update-rate 2018-02-09 23:19:09 +01:00
4543dcb787 Added volume prescaling-option to resolve #3 2018-02-09 22:45:56 +01:00
1cef641c62 Fixed a render bug in the gradient editor 2018-02-09 21:23:38 +01:00
940d2eb631 Added a workaround for the weird windows taskbar-closewindow behavior 2018-02-09 21:12:33 +01:00
8d1488db24 Added another workaround for fake-suround devices 2018-02-09 21:12:07 +01:00
3c76269c65 Fixed wrong gradient-selection 2018-02-09 21:11:31 +01:00
f42334aa2b Fixed error when creating a new configuration 2018-02-04 17:32:40 +01:00
2f9286e39d Added color-settings to resolve #2 2018-02-04 15:48:11 +01:00
d4b4071f71 Updated all dependencies 2018-01-29 13:45:10 +01:00
cb8146c594 Minor changes 2018-01-29 13:16:28 +01:00
1af8bb67c3 Added something (a workaround?) to prevent problems with fake 7.1 drivers 2017-09-30 22:05:06 +02:00
44 changed files with 2128 additions and 540 deletions

3
.gitignore vendored
View File

@ -286,6 +286,3 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
/NuGet.Config
/NuGet.Config
/KeyboardAudioVisualizer/NuGet.Config

View File

@ -7,7 +7,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@ -4,9 +4,12 @@ using System.Windows;
using System.Windows.Controls;
using Hardcodet.Wpf.TaskbarNotification;
using KeyboardAudioVisualizer.AudioProcessing;
using KeyboardAudioVisualizer.Configuration;
using KeyboardAudioVisualizer.Helper;
using KeyboardAudioVisualizer.Legacy;
using Newtonsoft.Json;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Settings = KeyboardAudioVisualizer.Configuration.Settings;
namespace KeyboardAudioVisualizer
@ -40,7 +43,7 @@ namespace KeyboardAudioVisualizer
//Settings settings = SerializationHelper.LoadObjectFromFile<Settings>(PATH_SETTINGS);
Settings settings = null;
try { settings = JsonConvert.DeserializeObject<Settings>(File.ReadAllText(PATH_SETTINGS)); }
try { settings = JsonConvert.DeserializeObject<Settings>(File.ReadAllText(PATH_SETTINGS), new ColorSerializer()); }
catch (Exception ex)
{
Console.WriteLine(ex.Message);
@ -52,9 +55,16 @@ namespace KeyboardAudioVisualizer
if (settings == null)
{
settings = new Settings();
settings = new Settings
{
Version = Settings.CURRENT_VERSION,
Background = new LinearGradient(new GradientStop(0.5, new Color(64, 0, 0, 0)))
};
_taskbarIcon.ShowBalloonTip("Keyboard Audio-Visualizer is starting in the tray!", "Click on the icon to open the configuration.", BalloonIcon.Info);
}
else if (settings.Version != Settings.CURRENT_VERSION)
ConfigurationUpdates.PerformOn(settings);
ApplicationManager.Instance.Settings = settings;
AudioVisualizationFactory.Initialize();
@ -74,7 +84,7 @@ namespace KeyboardAudioVisualizer
{
base.OnExit(e);
File.WriteAllText(PATH_SETTINGS, JsonConvert.SerializeObject(ApplicationManager.Instance.Settings));
File.WriteAllText(PATH_SETTINGS, JsonConvert.SerializeObject(ApplicationManager.Instance.Settings, new ColorSerializer()));
ConfigurationMigrator.CleanupOldConfigs();
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
using System.Windows;
using KeyboardAudioVisualizer.AudioProcessing;
using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider;
@ -13,8 +11,10 @@ using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using RGB.NET.Devices.CoolerMaster;
using RGB.NET.Devices.Corsair;
using RGB.NET.Devices.Corsair.SpecialParts;
using RGB.NET.Devices.Logitech;
using RGB.NET.Devices.Novation;
using RGB.NET.Devices.Razer;
using RGB.NET.Devices.SteelSeries;
using RGB.NET.Groups;
using Point = RGB.NET.Core.Point;
using GetDecoratorFunc = System.Func<KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider.VisualizationType, KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider.IVisualizationProvider, RGB.NET.Core.IBrushDecorator>;
@ -38,6 +38,8 @@ namespace KeyboardAudioVisualizer
private readonly Dictionary<VisualizationIndex, IEnumerable<(ILedGroup group, GetDecoratorFunc getDecoratorFunc)>> _groups = new Dictionary<VisualizationIndex, IEnumerable<(ILedGroup group, GetDecoratorFunc getDecoratorFunc)>>();
public TimerUpdateTrigger UpdateTrigger { get; } = new TimerUpdateTrigger();
#endregion
#region Commands
@ -62,15 +64,24 @@ namespace KeyboardAudioVisualizer
{
RGBSurface surface = RGBSurface.Instance;
surface.UpdateFrequency = 1.0 / MathHelper.Clamp(Settings.UpdateRate, 1, 40);
surface.UpdateMode = UpdateMode.Continuous;
UpdateTrigger.UpdateFrequency = 1.0 / MathHelper.Clamp(Settings.UpdateRate, 1, 60);
surface.RegisterUpdateTrigger(UpdateTrigger);
surface.LoadDevices(CorsairDeviceProvider.Instance);
surface.LoadDevices(LogitechDeviceProvider.Instance);
surface.LoadDevices(CoolerMasterDeviceProvider.Instance);
LoadDevices(surface, CorsairDeviceProvider.Instance);
LoadDevices(surface, CoolerMasterDeviceProvider.Instance);
LoadDevices(surface, NovationDeviceProvider.Instance);
LoadDevices(surface, RazerDeviceProvider.Instance);
LoadDevices(surface, LogitechDeviceProvider.Instance);
LoadDevices(surface, SteelSeriesDeviceProvider.Instance);
surface.AlignDevices();
ILedGroup background = new ListLedGroup(surface.Leds);
background.Brush = new SolidColorBrush(new Color(64, 0, 0, 0)); //TODO DarthAffe 06.08.2017: A-Channel gives some kind of blur - settings!
background.Brush = new LinearGradientBrush(Settings.Background);
LinearGradient primaryGradient = Settings[VisualizationIndex.Primary].Gradient;
LinearGradient secondaryGradient = Settings[VisualizationIndex.Secondary].Gradient;
LinearGradient tertiaryGradient = Settings[VisualizationIndex.Tertiary].Gradient;
List<(ILedGroup, GetDecoratorFunc)> primaryGroups = new List<(ILedGroup, GetDecoratorFunc)>();
List<(ILedGroup, GetDecoratorFunc)> secondaryGroups = new List<(ILedGroup, GetDecoratorFunc)>();
@ -79,6 +90,7 @@ namespace KeyboardAudioVisualizer
switch (device.DeviceInfo.DeviceType)
{
case RGBDeviceType.Keyboard:
case RGBDeviceType.Keypad:
case RGBDeviceType.LedMatrix:
ListLedGroup primary = new ListLedGroup(device);
@ -87,42 +99,44 @@ namespace KeyboardAudioVisualizer
{
primary.RemoveLeds(lightbar.Leds);
IGradient keyboardLevelGradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)), new GradientStop(1, new Color(255, 0, 0)));
ILedGroup lightbarLeft = new ListLedGroup(lightbar.Left);
lightbarLeft.Brush = new LinearGradientBrush(keyboardLevelGradient);
lightbarLeft.Brush = new LinearGradientBrush(new Point(1.0, 0.5), new Point(0.0, 0.5), tertiaryGradient);
tertiaryGroups.Add((lightbarLeft, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Left, 0)));
ILedGroup lightbarRight = new ListLedGroup(lightbar.Right);
lightbarRight.Brush = new LinearGradientBrush(keyboardLevelGradient);
lightbarRight.Brush = new LinearGradientBrush(tertiaryGradient);
tertiaryGroups.Add((lightbarRight, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Right, 1)));
ILedGroup lightbarCenter = new ListLedGroup(lightbar.Center);
lightbarCenter.Brush = new SolidColorBrush(new Color(255, 255, 255));
lightbarCenter.Brush = new LinearGradientBrush(secondaryGradient);
secondaryGroups.Add((lightbarCenter, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer)));
}
primary.Brush = new LinearGradientBrush(new RainbowGradient(300, -14));
primaryGroups.Add((primary, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Horizontal)));
primary.Brush = new LinearGradientBrush(primaryGradient);
primaryGroups.Add((primary, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Horizontal, 0, primaryGradient)));
break;
case RGBDeviceType.Mousepad:
case RGBDeviceType.LedStripe:
IGradient mousepadLevelGradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)), new GradientStop(1, new Color(255, 0, 0)));
case RGBDeviceType.HeadsetStand:
ILedGroup left = new RectangleLedGroup(new Rectangle(device.Location.X, device.Location.Y, device.Size.Width / 2.0, device.Size.Height));
left.Brush = new LinearGradientBrush(new Point(0.5, 1), new Point(0.5, 0), mousepadLevelGradient);
left.Brush = new LinearGradientBrush(new Point(0.5, 1), new Point(0.5, 0), tertiaryGradient);
tertiaryGroups.Add((left, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Top, 0)));
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));
right.Brush = new LinearGradientBrush(new Point(0.5, 1), new Point(0.5, 0), mousepadLevelGradient);
right.Brush = new LinearGradientBrush(new Point(0.5, 1), new Point(0.5, 0), tertiaryGradient);
tertiaryGroups.Add((right, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer, LevelBarDirection.Top, 1)));
break;
case RGBDeviceType.Mouse:
case RGBDeviceType.Headset:
case RGBDeviceType.Speaker:
case RGBDeviceType.Fan:
case RGBDeviceType.GraphicsCard:
case RGBDeviceType.DRAM:
case RGBDeviceType.Mainboard:
ILedGroup deviceGroup = new ListLedGroup(device);
deviceGroup.Brush = new SolidColorBrush(new Color(255, 255, 255));
deviceGroup.Brush = new LinearGradientBrush(secondaryGradient);
secondaryGroups.Add((deviceGroup, (visualizationType, visualizer) => CreateDecorator(visualizationType, visualizer)));
break;
}
@ -138,6 +152,14 @@ namespace KeyboardAudioVisualizer
surface.Updating += args => AudioVisualizationFactory.Instance.Update();
}
private void LoadDevices(RGBSurface surface, IRGBDeviceProvider deviceProvider)
{
surface.LoadDevices(deviceProvider, RGBDeviceType.Keyboard | RGBDeviceType.LedMatrix
| RGBDeviceType.Mousepad | RGBDeviceType.LedStripe
| RGBDeviceType.Mouse | RGBDeviceType.Headset
| RGBDeviceType.HeadsetStand);
}
//TODO DarthAffe 12.09.2017: This is just a big mess - is this worth to rework before arge?
public void ApplyVisualization(VisualizationIndex visualizationIndex, VisualizationType visualizationType)
{
@ -157,13 +179,13 @@ namespace KeyboardAudioVisualizer
}
}
private IBrushDecorator CreateDecorator(VisualizationType visualizationType, IVisualizationProvider visualizationProvider, LevelBarDirection direction = LevelBarDirection.Top, int dataIndex = 0)
private IBrushDecorator CreateDecorator(VisualizationType visualizationType, IVisualizationProvider visualizationProvider, LevelBarDirection direction = LevelBarDirection.Top, int dataIndex = 0, LinearGradient gradient = null)
{
if (visualizationType == VisualizationType.FrequencyBars)
return new FrequencyBarsDecorator(visualizationProvider);
if (visualizationType == VisualizationType.Level)
return new LevelBarDecorator(visualizationProvider, direction, dataIndex);
return new LevelBarDecorator(visualizationProvider, direction, dataIndex, gradient);
if (visualizationType == VisualizationType.Beat)
return new BeatDecorator(visualizationProvider);
@ -179,8 +201,8 @@ namespace KeyboardAudioVisualizer
private void Exit()
{
RGBSurface.Instance?.Dispose();
AudioVisualizationFactory.Instance?.Dispose();
try { AudioVisualizationFactory.Instance?.Dispose(); } catch { }
try { RGBSurface.Instance?.Dispose(); } catch { }
Application.Current.Shutdown();
}

View File

@ -13,6 +13,8 @@ namespace KeyboardAudioVisualizer.AudioCapture
public int Size => _capacity;
public float? Prescale { get; set; } = null;
#endregion
#region Constructors
@ -29,51 +31,68 @@ namespace KeyboardAudioVisualizer.AudioCapture
#region Methods
public void Put(float left, float right)
{
_currentIndex++;
if (_currentIndex >= _capacity) _currentIndex = 0;
_bufferLeft[_currentIndex] = left;
_bufferRight[_currentIndex] = right;
}
public void Put(float[] src, int offset, int count)
{
lock (_bufferLeft)
if ((count & 1) != 0) return; // we expect stereo-data to be an even amount of values
if (count > _capacity)
{
if ((count & 1) != 0) return; // we expect stereo-data to be an even amount of values
offset += count - _capacity;
count = _capacity;
}
if (count > _capacity)
for (int i = 0; i < count; i += 2)
{
_currentIndex++;
if (_currentIndex >= _capacity) _currentIndex = 0;
if (Prescale.HasValue)
{
offset += count - _capacity;
count = _capacity;
_bufferLeft[_currentIndex] = src[offset + i] / Prescale.Value;
_bufferRight[_currentIndex] = src[offset + i + 1] / Prescale.Value;
}
for (int i = 0; i < count; i += 2)
else
{
_currentIndex++;
if (_currentIndex >= _capacity) _currentIndex = 0;
_bufferLeft[_currentIndex] = src[offset + i];
_bufferRight[_currentIndex] = src[offset + i + 1];
}
}
}
public void CopyLeftInto(ref float[] data, int offset)
public void CopyLeftInto(ref float[] data, int offset) => CopyLeftInto(ref data, offset, Math.Min(data.Length, _capacity));
public void CopyLeftInto(ref float[] data, int offset, int count)
{
lock (_bufferLeft)
for (int i = 0; i < _capacity; i++)
data[offset + i] = _bufferLeft[(_currentIndex + i) % _capacity];
int bufferOffset = _capacity - count;
for (int i = 0; i < count; i++)
data[offset + i] = _bufferLeft[(_currentIndex + (bufferOffset + i)) % _capacity];
}
public void CopyRightInto(ref float[] data, int offset)
public void CopyRightInto(ref float[] data, int offset) => CopyRightInto(ref data, offset, Math.Min(data.Length, _capacity));
public void CopyRightInto(ref float[] data, int offset, int count)
{
lock (_bufferLeft)
for (int i = 0; i < _capacity; i++)
data[offset + i] = _bufferRight[(_currentIndex + i) % _capacity];
int bufferOffset = _capacity - count;
for (int i = 0; i < count; i++)
data[offset + i] = _bufferRight[(_currentIndex + (bufferOffset + i)) % _capacity];
}
public void CopyMixInto(ref float[] data, int offset)
public void CopyMixInto(ref float[] data, int offset) => CopyMixInto(ref data, offset, Math.Min(data.Length, _capacity));
public void CopyMixInto(ref float[] data, int offset, int count)
{
lock (_bufferLeft)
for (int i = 0; i < _capacity; i++)
{
int index = (_currentIndex + i) % _capacity;
data[offset + i] = (_bufferLeft[index] + _bufferRight[index]) / 2f;
}
int bufferOffset = _capacity - count;
for (int i = 0; i < count; i++)
{
int index = (_currentIndex + (bufferOffset + i)) % _capacity;
data[offset + i] = (_bufferLeft[index] + _bufferRight[index]) / 2f;
}
}
#endregion

View File

@ -1,4 +1,6 @@
using CSCore;
using System;
using CSCore;
using CSCore.CoreAudioAPI;
using CSCore.SoundIn;
using CSCore.Streams;
@ -10,11 +12,12 @@ namespace KeyboardAudioVisualizer.AudioCapture
private WasapiCapture _capture;
private SoundInSource _soundInSource;
private IWaveSource _source;
private SingleBlockNotificationStream _stream;
private readonly float[] _readBuffer = new float[2048];
private AudioEndpointVolume _audioEndpointVolume;
public int SampleRate => _soundInSource?.WaveFormat?.SampleRate ?? -1;
public float MasterVolume => _audioEndpointVolume.MasterVolumeLevelScalar;
#endregion
@ -28,15 +31,34 @@ namespace KeyboardAudioVisualizer.AudioCapture
public void Initialize()
{
_capture = new WasapiLoopbackCapture();
MMDevice captureDevice = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
WaveFormat deviceFormat = captureDevice.DeviceFormat;
_audioEndpointVolume = AudioEndpointVolume.FromDevice(captureDevice);
//DarthAffe 07.02.2018: This is a really stupid workaround to (hopefully) finally fix the surround driver issues
for (int i = 1; i < 13; i++)
try { _capture = new WasapiLoopbackCapture(100, new WaveFormat(deviceFormat.SampleRate, deviceFormat.BitsPerSample, i)); } catch { /* We're just trying ... */ }
if (_capture == null)
throw new NullReferenceException("Failed to initialize WasapiLoopbackCapture");
_capture.Initialize();
_soundInSource = new SoundInSource(_capture) { FillWithZeros = false };
_source = _soundInSource.WaveFormat.SampleRate == 44100
? _soundInSource.ToStereo()
: _soundInSource.ChangeSampleRate(44100).ToStereo();
_stream = _soundInSource.WaveFormat.SampleRate == 44100
? new SingleBlockNotificationStream(_soundInSource.ToStereo().ToSampleSource())
: new SingleBlockNotificationStream(_soundInSource.ChangeSampleRate(44100).ToStereo().ToSampleSource());
_stream = new SingleBlockNotificationStream(_source.ToSampleSource());
_stream.SingleBlockRead += StreamOnSingleBlockRead;
_soundInSource.DataAvailable += OnSoundDataAvailable;
_source = _stream.ToWaveSource();
byte[] buffer = new byte[_source.WaveFormat.BytesPerSecond / 2];
_soundInSource.DataAvailable += (s, aEvent) =>
{
while ((_source.Read(buffer, 0, buffer.Length)) > 0) ;
};
_capture.Start();
}
@ -47,12 +69,8 @@ namespace KeyboardAudioVisualizer.AudioCapture
_capture?.Dispose();
}
private void OnSoundDataAvailable(object sender, DataAvailableEventArgs dataAvailableEventArgs)
{
int readCount;
while ((readCount = _stream.Read(_readBuffer, 0, _readBuffer.Length)) > 0)
DataAvailable?.Invoke(_readBuffer, 0, readCount);
}
private void StreamOnSingleBlockRead(object sender, SingleBlockReadEventArgs singleBlockReadEventArgs)
=> DataAvailable?.Invoke(singleBlockReadEventArgs.Left, singleBlockReadEventArgs.Right);
#endregion
}

View File

@ -2,11 +2,12 @@
namespace KeyboardAudioVisualizer.AudioCapture
{
public delegate void AudioData(float[] data, int offset, int count);
public delegate void AudioData(float left, float right);
public interface IAudioInput : IDisposable
{
int SampleRate { get; }
float MasterVolume { get; }
event AudioData DataAvailable;

View File

@ -31,6 +31,11 @@ namespace KeyboardAudioVisualizer.AudioProcessing
public void Update()
{
if (ApplicationManager.Instance.Settings.EnableAudioPrescale)
_audioBuffer.Prescale = _audioInput.MasterVolume;
else
_audioBuffer.Prescale = null;
foreach (IAudioProcessor processor in _processors.Where(x => x.IsActive))
processor.Update();
}
@ -49,7 +54,7 @@ namespace KeyboardAudioVisualizer.AudioProcessing
_audioInput.Initialize();
_audioBuffer = new AudioBuffer(4096); // Working with ~93ms -
_audioInput.DataAvailable += (data, offset, count) => _audioBuffer.Put(data, offset, count);
_audioInput.DataAvailable += (left, right) => _audioBuffer.Put(left, right);
_processors.Add(new FourierSpectrumProvider(_audioBuffer));

View File

@ -2,7 +2,6 @@
using KeyboardAudioVisualizer.AudioProcessing.Equalizer;
using KeyboardAudioVisualizer.AudioProcessing.Spectrum;
using KeyboardAudioVisualizer.Configuration;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
{
@ -93,9 +92,6 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
public IConfiguration Configuration => _configuration;
public float[] VisualizationData { get; private set; }
public string DisplayName => "Spectrometer";
public RGBDeviceType VisualizerFor => RGBDeviceType.Keyboard | RGBDeviceType.LedMatrix;
#endregion
#region Constructors

View File

@ -1,9 +1,6 @@
using System;
using System.Linq;
using KeyboardAudioVisualizer.AudioProcessing.Spectrum;
using KeyboardAudioVisualizer.AudioProcessing.Spectrum;
using KeyboardAudioVisualizer.Configuration;
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
{
@ -16,7 +13,6 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
#endregion
// Port of https://github.com/kctess5/Processing-Beat-Detection
public class BeatVisualizationProvider : AbstractAudioProcessor, IVisualizationProvider
{
#region Properties & Fields
@ -24,47 +20,11 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
private readonly BeatVisualizationProviderConfiguration _configuration;
private readonly ISpectrumProvider _specturProvider;
private int _beatBands = 30; //Number of bands to montiter, higher for more accuracy, lower for speed
private int _longTermAverageSamples = 60; //gets average volume over a period of time
private int _shortTermAverageSamples = 1; //average volume over a shorter "instantanious" time
private int _deltaArraySamples = 300; //number of energy deltas between long & short average to sum together
private int _beatAverageSamples = 100;
private int _beatCounterArraySamples = 400;
private int _maxTime = 200;
private float _predictiveInfluenceConstant = 0.1f;
private float _predictiveInfluence;
private int _cyclePerBeatIntensity;
private float[][] _deltaArray;
private float[][] _shortAverageArray;
private float[][] _longAverageArray;
private float[] _globalAverageArray;
private int[] _beatCounterArray;
private int[] _beatSpread;
private int _beatCounterPosition;
private int _cyclesPerBeat;
private int _longPosition;
private int _shortPosition;
private int _deltaPosition;
private int[] _count;
private float[] _totalLong;
private float[] _totalShort;
private float[] _delta;
private float[] _c;
private int _beat;
private int _beatCounter;
private float[] _beatAverage;
private float _totalBeat;
private int _beatPosition;
private float _totalGlobal;
private float _threshold;
private float _standardDeviation;
private RingBuffer[] _history;
public IConfiguration Configuration => _configuration;
public float[] VisualizationData { get; } = new float[1];
public string DisplayName => "Beat";
public RGBDeviceType VisualizerFor => (RGBDeviceType)0xFF;
#endregion
#region Constructors
@ -81,181 +41,30 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
public override void Initialize()
{
_deltaArray = new float[_deltaArraySamples][];
for (int i = 0; i < _deltaArray.Length; i++)
_deltaArray[i] = new float[_beatBands];
_shortAverageArray = new float[_shortTermAverageSamples][];
for (int i = 0; i < _shortAverageArray.Length; i++)
_shortAverageArray[i] = new float[_beatBands];
_longAverageArray = new float[_longTermAverageSamples / _shortTermAverageSamples][];
for (int i = 0; i < _longAverageArray.Length; i++)
_longAverageArray[i] = new float[_beatBands];
_globalAverageArray = new float[_longTermAverageSamples];
_beatCounterArray = new int[_beatCounterArraySamples];
_beatSpread = new int[_maxTime];
_count = new int[_beatBands];
_totalLong = new float[_beatBands];
_totalShort = new float[_beatBands];
_delta = new float[_beatBands];
_c = new float[_beatBands]; //multiplier used to determain threshold
_beatAverage = new float[_beatAverageSamples];
_history = new RingBuffer[64];
for (int i = 0; i < _history.Length; i++)
_history[i] = new RingBuffer(32);
}
public override void Update()
{
ISpectrum spectrum = _specturProvider.GetLogarithmicSpectrum(60, minFrequency: 60);
VisualizationData[0] = 0;
if (_shortPosition >= _shortTermAverageSamples) _shortPosition = 0; //Resets incremental variables
if (_longPosition >= (_longTermAverageSamples / _shortTermAverageSamples)) _longPosition = 0;
if (_deltaPosition >= _deltaArraySamples) _deltaPosition = 0;
if (_beatPosition >= _beatAverageSamples) _beatPosition = 0;
/////////////////////////////////////Calculate short and long term array averages///////////////////////////////////////////////////////////////////////////////////////////////////////////
for (int i = 0; i < _beatBands; i++)
ISpectrum spectrum = _specturProvider.GetLogarithmicSpectrum(64);
for (int i = 0; i < 32; i++)
{
_shortAverageArray[_shortPosition][i] = spectrum[i].Average; //stores the average intensity between the freq. bounds to the short term array
_totalLong[i] = 0;
_totalShort[i] = 0;
for (int j = 0; j < (_longTermAverageSamples / _shortTermAverageSamples); j++)
_totalLong[i] += _longAverageArray[j][i]; //adds up all the values in both of these arrays, for averaging
for (int j = 0; j < _shortTermAverageSamples; j++)
_totalShort[i] += _shortAverageArray[j][i];
}
float currentEnergy = spectrum[i].Average;
float averageEnergy = _history[i].Average;
_history[i].Put(currentEnergy);
///////////////////////////////////////////Find wideband frequency average intensity/////////////////////////////////////////////////////////////////////////////////////////////////////
_totalGlobal = 0;
_globalAverageArray[_longPosition] = spectrum[0, 2000].Average(x => x.Average);
for (int j = 0; j < _longTermAverageSamples; j++)
_totalGlobal += _globalAverageArray[j];
_totalGlobal = _totalGlobal / _longTermAverageSamples;
//////////////////////////////////Populate long term average array//////////////////////////////////////////////////////////////////////////////////////////////////////////////
if ((_shortPosition % _shortTermAverageSamples) == 0)
{ //every time the short array is completely new it is added to long array
for (int i = 0; i < _beatBands; i++)
_longAverageArray[_longPosition][i] = _totalShort[i]; //increases speed of program, but is the same as if each individual value was stored in long array
_longPosition++;
}
/////////////////////////////////////////Find index of variation for each band///////////////////////////////////////////////////////////////////////////////////////////////////////
for (int i = 0; i < _beatBands; i++)
{
_totalLong[i] = _totalLong[i] / (float)_longTermAverageSamples / (float)_shortTermAverageSamples;
_delta[i] = 0;
_deltaArray[_deltaPosition][i] = (float)Math.Pow(Math.Abs(_totalLong[i] - _totalShort[i]), 2);
for (int j = 0; j < _deltaArraySamples; j++)
_delta[i] += _deltaArray[j][i];
_delta[i] /= _deltaArraySamples;
///////////////////////////////////////////Find local beats/////////////////////////////////////////////////////////////////////////////////////////////////////
_c[i] = (float)((1.3 + MathHelper.Clamp(Map(_delta[i], 0, 3000, 0, 0.4), 0, 0.4) //delta is usually bellow 2000
+ Map(MathHelper.Clamp(Math.Pow(_totalLong[i], 0.5), 0, 6), 0, 20, 0.3, 0) //possibly comment this out, adds weight to the lower end
+ Map(MathHelper.Clamp(_count[i], 0, 15), 0, 15, 1, 0))
- Map(MathHelper.Clamp(_count[i], 30, 200), 30, 200, 0, 0.75));
if ((_cyclePerBeatIntensity / _standardDeviation) > 3.5)
if (currentEnergy > (35 * averageEnergy))
{
_predictiveInfluence = (float)(_predictiveInfluenceConstant * (1 - (Math.Cos(_beatCounter * (Math.PI * Math.PI)) / _cyclesPerBeat)));
_predictiveInfluence *= (float)Map(MathHelper.Clamp(_cyclePerBeatIntensity / _standardDeviation, 3.5, 20), 3.5, 15, 1, 6);
if (_cyclesPerBeat > 10)
_c[i] += _predictiveInfluence;
VisualizationData[0] = 1;
break;
}
}
_beat = 0;
for (int i = 0; i < _beatBands; i++)
{
if ((_totalShort[i] > (_totalLong[i] * _c[i])) & (_count[i] > 7))
{ //If beat is detected
if ((_count[i] > 12) & (_count[i] < 200))
{
_beatCounterArray[_beatCounterPosition % _beatCounterArraySamples] = _count[i];
_beatCounterPosition++;
}
_count[i] = 0; //resets counter
}
}
/////////////////////////////////////////Figure out # of beats, and average///////////////////////////////////////////////////////////////////////////////////////////////////////
for (int i = 0; i < _beatBands; i++)
if (_count[i] < 2)
_beat++; //If there has been a recent beat in a band add to the global beat value
_beatAverage[_beatPosition] = _beat;
for (int j = 0; j < _beatAverageSamples; j++)
_totalBeat += _beatAverage[j];
_totalBeat = _totalBeat / _beatAverageSamples;
/////////////////////////////////////////////////find global beat///////////////////////////////////////////////////////////////////////////////////////////////
_c[0] = (float)(3.25 + Map(MathHelper.Clamp(_beatCounter, 0, 5), 0, 5, 5, 0));
if (_cyclesPerBeat > 10)
_c[0] = (float)(_c[0] + (0.75 * (1 - (Math.Cos(_beatCounter * (Math.PI * Math.PI)) / _cyclesPerBeat))));
_threshold = (float)MathHelper.Clamp((_c[0] * _totalBeat) + Map(MathHelper.Clamp(_totalGlobal, 0, 2), 0, 2, 4, 0), 5, 1000);
if ((_beat > _threshold) & (_beatCounter > 5))
{
VisualizationData[0] = 1;
_beatCounter = 0;
}
else
VisualizationData[0] = 0;
/////////////////////////////////////////////////////Calculate beat spreads///////////////////////////////////////////////////////////////////////////////////////////
//average = beatCounterArraySamples/200 !!!
for (int i = 0; i < _maxTime; i++)
_beatSpread[i] = 0;
for (int i = 0; i < _beatCounterArraySamples; i++)
_beatSpread[_beatCounterArray[i]]++;
_cyclesPerBeat = Mode(_beatCounterArray);
if (_cyclesPerBeat < 20)
_cyclesPerBeat *= 2;
_cyclePerBeatIntensity = _beatSpread.Max();
_standardDeviation = 0;
for (int i = 0; i < _maxTime; i++)
_standardDeviation += (float)Math.Pow((_beatCounterArraySamples / _maxTime) - _beatSpread[i], 2);
_standardDeviation = (float)Math.Pow(_standardDeviation / _maxTime, 0.5);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
_shortPosition++;
_deltaPosition++;
for (int i = 0; i < _beatBands; i++) _count[i]++;
_beatCounter++;
_beatPosition++;
}
private int Mode(int[] array)
{
int[] modeMap = new int[array.Length];
int maxEl = array[0];
int maxCount = 1;
for (int i = 0; i < array.Length; i++)
{
int el = array[i];
if (modeMap[el] == 0)
modeMap[el] = 1;
else
modeMap[el]++;
if (modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
private static double Map(double value, double oldMin, double oldMax, double newMin, double newMax) => newMin + ((newMax - newMin) * ((value - oldMin) / (oldMax - oldMin)));
#endregion
}
}

View File

@ -3,7 +3,6 @@ using System.Linq;
using KeyboardAudioVisualizer.AudioCapture;
using KeyboardAudioVisualizer.Configuration;
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
{
@ -63,10 +62,6 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
public IConfiguration Configuration => _configuration;
public float[] VisualizationData { get; } = new float[3];
public string DisplayName => "Level";
public RGBDeviceType VisualizerFor => RGBDeviceType.Keyboard | RGBDeviceType.LedMatrix | RGBDeviceType.LedStripe | RGBDeviceType.Mousepad;
#endregion
#region Constructors
@ -85,9 +80,9 @@ namespace KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider
public override void Initialize()
{
_sampleDataLeft = new float[_audioBuffer.Size];
_sampleDataRight = new float[_audioBuffer.Size];
_sampleDataMix = new float[_audioBuffer.Size];
_sampleDataLeft = new float[2048];
_sampleDataRight = new float[2048];
_sampleDataMix = new float[2048];
RecalculateConfigValues(null);
}

View File

@ -1,25 +1,12 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Xml.Serialization;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Configuration
{
public class AbstractConfiguration : AbstractBindable, IConfiguration, INotifyPropertyChanged
{
#region Properties & Fields
private IBrush _brush;
[XmlIgnore]
public IBrush Brush
{
get => _brush;
set => SetProperty(ref _brush, value);
}
#endregion
#region Methods
protected override bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)

View File

@ -0,0 +1,47 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Configuration
{
public class ColorSerializer : JsonConverter
{
#region Methods
public override bool CanConvert(Type objectType) => objectType == typeof(Color);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (!(value is Color color)) return;
writer.WriteStartObject();
writer.WritePropertyName("A");
writer.WriteValue(color.A);
writer.WritePropertyName("R");
writer.WriteValue(color.R);
writer.WritePropertyName("G");
writer.WriteValue(color.G);
writer.WritePropertyName("B");
writer.WriteValue(color.B);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jsonObject = JObject.Load(reader);
if (jsonObject.Property("A").Value.ToObject<double>() > 1.0) //DarthAffe 09.06.2019: Convert old Settings
return new Color(jsonObject.Property("A").Value.ToObject<byte>(),
jsonObject.Property("R").Value.ToObject<byte>(),
jsonObject.Property("G").Value.ToObject<byte>(),
jsonObject.Property("B").Value.ToObject<byte>());
else
return new Color(jsonObject.Property("A").Value.ToObject<double>(),
jsonObject.Property("R").Value.ToObject<double>(),
jsonObject.Property("G").Value.ToObject<double>(),
jsonObject.Property("B").Value.ToObject<double>());
}
#endregion
}
}

View File

@ -1,10 +1,7 @@
using System.ComponentModel;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Configuration
{
public interface IConfiguration : INotifyPropertyChanged
{
IBrush Brush { get; set; }
}
{ }
}

View File

@ -2,15 +2,29 @@
using System.Collections.Generic;
using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider;
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Configuration
{
public class Settings
{
#region Constants
public const int CURRENT_VERSION = 1;
#endregion
#region Properties & Fields
public int Version { get; set; } = 0;
public double UpdateRate { get; set; } = 40.0;
public bool EnableAudioPrescale { get; set; } = false;
public LinearGradient Background { get; set; }
public Dictionary<VisualizationIndex, VisualizationSettings> Visualizations { get; set; } = new Dictionary<VisualizationIndex, VisualizationSettings>();
public VisualizationSettings this[VisualizationIndex visualizationIndex]
@ -32,6 +46,8 @@ namespace KeyboardAudioVisualizer.Configuration
public VisualizationType SelectedVisualization { get; set; }
public LinearGradient Gradient { get; set; }
public EqualizerConfiguration EqualizerConfiguration { get; set; } = new EqualizerConfiguration();
public FrequencyBarsVisualizationProviderConfiguration FrequencyBarsConfiguration { get; set; } = new FrequencyBarsVisualizationProviderConfiguration();
@ -72,14 +88,24 @@ namespace KeyboardAudioVisualizer.Configuration
{
case VisualizationIndex.Primary:
SelectedVisualization = VisualizationType.FrequencyBars;
Gradient = new LinearGradient(new GradientStop(0, HSVColor.Create(300, 1, 1)),
new GradientStop(0.20, HSVColor.Create(225, 1, 1)),
new GradientStop(0.35, HSVColor.Create(180, 1, 1)),
new GradientStop(0.50, HSVColor.Create(135, 1, 1)),
new GradientStop(0.65, HSVColor.Create(90, 1, 1)),
new GradientStop(0.80, HSVColor.Create(45, 1, 1)),
new GradientStop(0.95, HSVColor.Create(0, 1, 1)));
break;
case VisualizationIndex.Secondary:
SelectedVisualization = VisualizationType.Beat;
Gradient = new LinearGradient(new GradientStop(0.5, new Color(255, 255, 255)));
break;
case VisualizationIndex.Tertiary:
SelectedVisualization = VisualizationType.Level;
Gradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)),
new GradientStop(1, new Color(255, 0, 0)));
break;
}
}

View File

@ -0,0 +1,483 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using RGB.NET.Core;
using Color = RGB.NET.Core.Color;
using Point = System.Windows.Point;
using Rectangle = System.Windows.Shapes.Rectangle;
using WpfColor = System.Windows.Media.Color;
namespace KeyboardAudioVisualizer.Controls
{
[TemplatePart(Name = "PART_Selector", Type = typeof(Panel))]
[TemplatePart(Name = "PART_SliderAlpha", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderRed", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderGreen", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderBlue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderHue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderSaturation", Type = typeof(Slider))]
[TemplatePart(Name = "PART_SliderValue", Type = typeof(Slider))]
[TemplatePart(Name = "PART_Preview", Type = typeof(Rectangle))]
public class ColorSelector : Control
{
#region Properties & Fields
private bool _ignorePropertyChanged;
private bool _dragSelector;
private byte _a;
private byte _r;
private byte _g;
private byte _b;
private double _hue;
private double _saturation;
private double _value;
private Panel _selector;
private Rectangle _selectorColor;
private Grid _selectorGrip;
private Slider _sliderAlpha;
private Slider _sliderRed;
private Slider _sliderGreen;
private Slider _sliderBlue;
private Slider _sliderHue;
private Slider _sliderSaturation;
private Slider _sliderValue;
private Rectangle _preview;
private SolidColorBrush _previewBrush;
private SolidColorBrush _selectorBrush;
private LinearGradientBrush _alphaBrush;
private LinearGradientBrush _redBrush;
private LinearGradientBrush _greenBrush;
private LinearGradientBrush _blueBrush;
private LinearGradientBrush _hueBrush;
private LinearGradientBrush _saturationBrush;
private LinearGradientBrush _valueBrush;
#endregion
#region DependencyProperties
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(
"SelectedColor", typeof(Color), typeof(ColorSelector), new FrameworkPropertyMetadata(new Color(255, 0, 0),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
SelectedColorChanged));
public Color SelectedColor
{
get => (Color)GetValue(SelectedColorProperty);
set => SetValue(SelectedColorProperty, value);
}
#endregion
#region Methods
public override void OnApplyTemplate()
{
if ((_selector = GetTemplateChild("PART_Selector") as Panel) != null)
{
_selectorBrush = new SolidColorBrush();
_selectorColor = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = _selectorBrush
};
_selector.Children.Add(_selectorColor);
Rectangle selectorWhite = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = new LinearGradientBrush(WpfColor.FromRgb(255, 255, 255), WpfColor.FromArgb(0, 255, 255, 255), new Point(0, 0.5), new Point(1, 0.5))
};
_selector.Children.Add(selectorWhite);
Rectangle selectorBlack = new Rectangle
{
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
SnapsToDevicePixels = true,
StrokeThickness = 0,
Fill = new LinearGradientBrush(WpfColor.FromRgb(0, 0, 0), WpfColor.FromArgb(0, 0, 0, 0), new Point(0.5, 1), new Point(0.5, 0))
};
_selector.Children.Add(selectorBlack);
_selectorGrip = new Grid
{
VerticalAlignment = VerticalAlignment.Bottom,
HorizontalAlignment = HorizontalAlignment.Left,
SnapsToDevicePixels = true
};
_selectorGrip.Children.Add(new Ellipse
{
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
SnapsToDevicePixels = true,
Stroke = new SolidColorBrush(WpfColor.FromRgb(0, 0, 0)),
StrokeThickness = 2,
Fill = null,
Width = 12,
Height = 12
});
_selectorGrip.Children.Add(new Ellipse
{
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
SnapsToDevicePixels = true,
Stroke = new SolidColorBrush(WpfColor.FromRgb(255, 255, 255)),
StrokeThickness = 1,
Fill = null,
Width = 10,
Height = 10
});
_selector.Children.Add(_selectorGrip);
_selector.SizeChanged += (sender, args) => UpdateSelector();
_selector.MouseLeftButtonDown += (sender, args) =>
{
_dragSelector = true;
UpdateSelectorValue(args.GetPosition(_selector));
};
_selector.MouseEnter += (sender, args) =>
{
if (args.LeftButton == MouseButtonState.Pressed)
{
_dragSelector = true;
UpdateSelectorValue(args.GetPosition(_selector));
}
};
_selector.MouseLeftButtonUp += (sender, args) => _dragSelector = false;
_selector.MouseLeave += (sender, args) => _dragSelector = false;
_selector.MouseMove += (sender, args) => UpdateSelectorValue(args.GetPosition(_selector));
_selector.ClipToBounds = true;
}
if ((_sliderAlpha = GetTemplateChild("PART_SliderAlpha") as Slider) != null)
{
_alphaBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderAlpha.Background = _alphaBrush;
_sliderAlpha.ValueChanged += AChanged;
}
if ((_sliderRed = GetTemplateChild("PART_SliderRed") as Slider) != null)
{
_redBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderRed.Background = _redBrush;
_sliderRed.ValueChanged += RChanged;
}
if ((_sliderGreen = GetTemplateChild("PART_SliderGreen") as Slider) != null)
{
_greenBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderGreen.Background = _greenBrush;
_sliderGreen.ValueChanged += GChanged;
}
if ((_sliderBlue = GetTemplateChild("PART_SliderBlue") as Slider) != null)
{
_blueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderBlue.Background = _blueBrush;
_sliderBlue.ValueChanged += BChanged;
}
if ((_sliderHue = GetTemplateChild("PART_SliderHue") as Slider) != null)
{
_hueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1.0 / 6.0),
new GradientStop(new WpfColor(), 2.0 / 6.0),
new GradientStop(new WpfColor(), 3.0 / 6.0),
new GradientStop(new WpfColor(), 4.0 / 6.0),
new GradientStop(new WpfColor(), 5.0 / 6.0),
new GradientStop(new WpfColor(), 1) }));
_sliderHue.Background = _hueBrush;
_sliderHue.ValueChanged += HueChanged;
}
if ((_sliderSaturation = GetTemplateChild("PART_SliderSaturation") as Slider) != null)
{
_saturationBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderSaturation.Background = _saturationBrush;
_sliderSaturation.ValueChanged += SaturationChanged;
}
if ((_sliderValue = GetTemplateChild("PART_SliderValue") as Slider) != null)
{
_valueBrush = new LinearGradientBrush(new GradientStopCollection(new[] { new GradientStop(new WpfColor(), 0),
new GradientStop(new WpfColor(), 1) }));
_sliderValue.Background = _valueBrush;
_sliderValue.ValueChanged += ValueChanged;
}
if ((_preview = GetTemplateChild("PART_Preview") as Rectangle) != null)
{
_previewBrush = new SolidColorBrush();
_preview.Fill = _previewBrush;
}
SetColor(SelectedColor);
}
private static void SelectedColorChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is ColorSelector cs) || !(dependencyPropertyChangedEventArgs.NewValue is Color color)) return;
cs.SetColor(color);
}
private void SetColor(Color color)
{
if (_ignorePropertyChanged) return;
SetA(color);
SetRGB(color);
SetHSV(color);
UpdateSelector();
UpdateUIColors();
}
private void AChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_a = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
Color color = new Color(_a, _r, _g, _b);
UpdateSelectedColor(color);
UpdateUIColors();
UpdateSelector();
}
private void RChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_r = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void GChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_g = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void BChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_b = (byte)routedPropertyChangedEventArgs.NewValue.Clamp(0, byte.MaxValue);
RGBChanged();
}
private void RGBChanged()
{
Color color = new Color(_a, _r, _g, _b);
UpdateSelectedColor(color);
SetHSV(color);
UpdateUIColors();
UpdateSelector();
}
private void HueChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_hue = routedPropertyChangedEventArgs.NewValue.Clamp(0, 360);
HSVChanged();
}
private void SaturationChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_saturation = routedPropertyChangedEventArgs.NewValue.Clamp(0, 1);
HSVChanged();
}
private void ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
{
if (_ignorePropertyChanged) return;
_value = routedPropertyChangedEventArgs.NewValue.Clamp(0, 1);
HSVChanged();
}
private void HSVChanged()
{
Color color = HSVColor.Create(_a, _hue, _saturation, _value);
UpdateSelectedColor(color);
SetRGB(color);
UpdateUIColors();
UpdateSelector();
}
private void SetA(Color color)
{
_ignorePropertyChanged = true;
_a = color.GetA();
if (_sliderAlpha != null)
_sliderAlpha.Value = _a;
_ignorePropertyChanged = false;
}
private void SetRGB(Color color)
{
_ignorePropertyChanged = true;
_r = color.GetR();
if (_sliderRed != null)
_sliderRed.Value = _r;
_g = color.GetG();
if (_sliderGreen != null)
_sliderGreen.Value = _g;
_b = color.GetB();
if (_sliderBlue != null)
_sliderBlue.Value = _b;
_ignorePropertyChanged = false;
}
private void SetHSV(Color color)
{
_ignorePropertyChanged = true;
_hue = color.GetHue();
if (_sliderHue != null)
_sliderHue.Value = _hue;
_saturation = color.GetSaturation();
if (_sliderSaturation != null)
_sliderSaturation.Value = _saturation;
_value = color.GetValue();
if (_sliderValue != null)
_sliderValue.Value = _value;
_ignorePropertyChanged = false;
}
private void UpdateSelectedColor(Color color)
{
_ignorePropertyChanged = true;
SelectedColor = color;
_ignorePropertyChanged = false;
}
private void UpdateSelector()
{
if (_selector == null) return;
double selectorX = (_selector.ActualWidth * _saturation) - (_selectorGrip.ActualWidth / 2);
double selectorY = (_selector.ActualHeight * _value) - (_selectorGrip.ActualHeight / 2);
if (!double.IsNaN(selectorX) && !double.IsNaN(selectorY))
_selectorGrip.Margin = new Thickness(selectorX, 0, 0, selectorY);
}
private void UpdateSelectorValue(Point mouseLocation)
{
if (!_dragSelector) return;
double saturation = mouseLocation.X / _selector.ActualWidth;
double value = 1 - (mouseLocation.Y / _selector.ActualHeight);
if (!double.IsNaN(saturation) && !double.IsNaN(value))
{
_saturation = saturation;
_value = value;
HSVChanged();
}
}
private void UpdateUIColors()
{
Color hueColor = HSVColor.Create(_hue, 1, 1);
if (_previewBrush != null)
_previewBrush.Color = WpfColor.FromArgb(_a, _r, _g, _b);
if (_selectorBrush != null)
_selectorBrush.Color = WpfColor.FromRgb(hueColor.GetR(), hueColor.GetG(), hueColor.GetB());
if (_alphaBrush != null)
{
_alphaBrush.GradientStops[0].Color = WpfColor.FromArgb(0, _r, _g, _b);
_alphaBrush.GradientStops[1].Color = WpfColor.FromArgb(255, _r, _g, _b);
}
if (_redBrush != null)
{
_redBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 0, _g, _b);
_redBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, 255, _g, _b);
}
if (_greenBrush != null)
{
_greenBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, _r, 0, _b);
_greenBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, _r, 255, _b);
}
if (_blueBrush != null)
{
_blueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, _r, _g, 0);
_blueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, _r, _g, 255);
}
if (_hueBrush != null)
{
Color referenceColor1 = HSVColor.Create(0, _saturation, _value);
Color referenceColor2 = HSVColor.Create(60, _saturation, _value);
Color referenceColor3 = HSVColor.Create(120, _saturation, _value);
Color referenceColor4 = HSVColor.Create(180, _saturation, _value);
Color referenceColor5 = HSVColor.Create(240, _saturation, _value);
Color referenceColor6 = HSVColor.Create(300, _saturation, _value);
_hueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, referenceColor1.GetR(), referenceColor1.GetG(), referenceColor1.GetB());
_hueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor2.GetR(), referenceColor2.GetG(), referenceColor2.GetB());
_hueBrush.GradientStops[2].Color = WpfColor.FromArgb(_a, referenceColor3.GetR(), referenceColor3.GetG(), referenceColor3.GetB());
_hueBrush.GradientStops[3].Color = WpfColor.FromArgb(_a, referenceColor4.GetR(), referenceColor4.GetG(), referenceColor4.GetB());
_hueBrush.GradientStops[4].Color = WpfColor.FromArgb(_a, referenceColor5.GetR(), referenceColor5.GetG(), referenceColor5.GetB());
_hueBrush.GradientStops[5].Color = WpfColor.FromArgb(_a, referenceColor6.GetR(), referenceColor6.GetG(), referenceColor6.GetB());
_hueBrush.GradientStops[6].Color = WpfColor.FromArgb(_a, referenceColor1.GetR(), referenceColor1.GetG(), referenceColor1.GetB());
}
if (_saturationBrush != null)
{
Color referenceColor = HSVColor.Create(_hue, 1, _value);
_saturationBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 255, 255, 255);
_saturationBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor.GetR(), referenceColor.GetG(), referenceColor.GetB());
}
if (_valueBrush != null)
{
Color referenceColor = HSVColor.Create(_hue, _saturation, 1);
_valueBrush.GradientStops[0].Color = WpfColor.FromArgb(_a, 0, 0, 0);
_valueBrush.GradientStops[1].Color = WpfColor.FromArgb(_a, referenceColor.GetR(), referenceColor.GetG(), referenceColor.GetB());
}
}
#endregion
}
}

View File

@ -4,12 +4,12 @@ using System.Windows.Controls;
namespace KeyboardAudioVisualizer.Controls
{
public class Formular : Panel
public class Form : Panel
{
#region DependencyProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register("RowHeight", typeof(double), typeof(Formular),
public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register("RowHeight", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(24.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double RowHeight
@ -22,7 +22,7 @@ namespace KeyboardAudioVisualizer.Controls
}
}
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register("LabelWidth", typeof(double), typeof(Formular),
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register("LabelWidth", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double LabelWidth
@ -35,7 +35,7 @@ namespace KeyboardAudioVisualizer.Controls
}
}
public static readonly DependencyProperty ElementSpacingProperty = DependencyProperty.Register("ElementSpacing", typeof(double), typeof(Formular),
public static readonly DependencyProperty ElementSpacingProperty = DependencyProperty.Register("ElementSpacing", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double ElementSpacing
@ -44,7 +44,7 @@ namespace KeyboardAudioVisualizer.Controls
set => SetValue(ElementSpacingProperty, value);
}
public static readonly DependencyProperty RowSpacingProperty = DependencyProperty.Register("RowSpacing", typeof(double), typeof(Formular),
public static readonly DependencyProperty RowSpacingProperty = DependencyProperty.Register("RowSpacing", typeof(double), typeof(Form),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public double RowSpacing
@ -59,25 +59,25 @@ namespace KeyboardAudioVisualizer.Controls
#region AttachedProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty IsLabelProperty = DependencyProperty.RegisterAttached("IsLabel", typeof(bool), typeof(Formular),
public static readonly DependencyProperty IsLabelProperty = DependencyProperty.RegisterAttached("IsLabel", typeof(bool), typeof(Form),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetIsLabel(UIElement element, bool value) => element.SetValue(IsLabelProperty, value);
public static bool GetIsLabel(UIElement element) => (bool)element.GetValue(IsLabelProperty);
public static readonly DependencyProperty LineBreaksProperty = DependencyProperty.RegisterAttached("LineBreaks", typeof(int), typeof(Formular),
public static readonly DependencyProperty LineBreaksProperty = DependencyProperty.RegisterAttached("LineBreaks", typeof(int), typeof(Form),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetLineBreaks(UIElement element, int value) => element.SetValue(LineBreaksProperty, value);
public static int GetLineBreaks(UIElement element) => (int)element.GetValue(LineBreaksProperty);
public static readonly DependencyProperty RowSpanProperty = DependencyProperty.RegisterAttached("RowSpan", typeof(int), typeof(Formular),
public static readonly DependencyProperty RowSpanProperty = DependencyProperty.RegisterAttached("RowSpan", typeof(int), typeof(Form),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
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),
public static readonly DependencyProperty FillProperty = DependencyProperty.RegisterAttached("Fill", typeof(bool), typeof(Form),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetFill(DependencyObject element, bool value) => element.SetValue(FillProperty, value);
@ -92,7 +92,7 @@ namespace KeyboardAudioVisualizer.Controls
{
if (InternalChildren.Count == 0) return new Size(0, 0);
FormularLayout layout = new FormularLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
FormLayout layout = new FormLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
foreach (UIElement child in InternalChildren)
{
@ -107,7 +107,7 @@ namespace KeyboardAudioVisualizer.Controls
{
if (InternalChildren.Count == 0) return new Size(0, 0);
FormularLayout layout = new FormularLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
FormLayout layout = new FormLayout(RowHeight, LabelWidth, ElementSpacing, RowSpacing);
foreach (UIElement child in InternalChildren)
child.Arrange(layout.AddElement(child, finalSize.Width));
@ -119,7 +119,7 @@ namespace KeyboardAudioVisualizer.Controls
#region Data
private class FormularLayout
private class FormLayout
{
#region Properties & Fields
@ -140,7 +140,7 @@ namespace KeyboardAudioVisualizer.Controls
#region Constructors
public FormularLayout(double rowHeight, double labelWidth, double elementSpacing, double rowSpacing)
public FormLayout(double rowHeight, double labelWidth, double elementSpacing, double rowSpacing)
{
this._rowHeight = rowHeight;
this._labelWidth = labelWidth;

View File

@ -0,0 +1,424 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
using Rectangle = System.Windows.Shapes.Rectangle;
using GradientStop = RGB.NET.Brushes.Gradients.GradientStop;
namespace KeyboardAudioVisualizer.Controls
{
[TemplatePart(Name = "PART_Gradient", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_Stops", Type = typeof(Canvas))]
public class GradientEditor : Control
{
#region Properties & Fields
private Canvas _gradientContainer;
private Canvas _stopContainer;
private readonly List<Rectangle> _previewRectangles = new List<Rectangle>();
private readonly Dictionary<GradientStop, ContentControl> _stops = new Dictionary<GradientStop, ContentControl>();
private ContentControl _draggingStop;
private AdornerLayer _adornerLayer;
private ColorPickerAdorner _adorner;
private Window _window;
#endregion
#region DepdencyProperties
public static readonly DependencyProperty GradientProperty = DependencyProperty.Register(
"Gradient", typeof(LinearGradient), typeof(GradientEditor), new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnGradientChanged));
public LinearGradient Gradient
{
get => (LinearGradient)GetValue(GradientProperty);
set => SetValue(GradientProperty, value);
}
public static readonly DependencyProperty GradientStopStyleProperty = DependencyProperty.Register(
"GradientStopStyle", typeof(Style), typeof(GradientEditor), new PropertyMetadata(default(Style)));
public Style GradientStopStyle
{
get => (Style)GetValue(GradientStopStyleProperty);
set => SetValue(GradientStopStyleProperty, value);
}
public static readonly DependencyProperty SelectedStopProperty = DependencyProperty.Register(
"SelectedStop", typeof(GradientStop), typeof(GradientEditor), new PropertyMetadata(default(GradientStop), SelectedStopChanged));
public GradientStop SelectedStop
{
get => (GradientStop)GetValue(SelectedStopProperty);
set => SetValue(SelectedStopProperty, value);
}
public static readonly DependencyProperty ColorSelectorTemplateProperty = DependencyProperty.Register(
"ColorSelectorTemplate", typeof(DataTemplate), typeof(GradientEditor), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ColorSelectorTemplate
{
get => (DataTemplate)GetValue(ColorSelectorTemplateProperty);
set => SetValue(ColorSelectorTemplateProperty, value);
}
public static readonly DependencyProperty CanAddOrDeleteStopsProperty = DependencyProperty.Register(
"CanAddOrDeleteStops", typeof(bool), typeof(GradientEditor), new PropertyMetadata(true));
public bool CanAddOrDeleteStops
{
get => (bool)GetValue(CanAddOrDeleteStopsProperty);
set => SetValue(CanAddOrDeleteStopsProperty, value);
}
#endregion
#region AttachedProperties
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached(
"IsSelected", typeof(bool), typeof(GradientEditor), new PropertyMetadata(default(bool)));
public static void SetIsSelected(DependencyObject element, bool value) => element.SetValue(IsSelectedProperty, value);
public static bool GetIsSelected(DependencyObject element) => (bool)element.GetValue(IsSelectedProperty);
#endregion
#region Constructors
public GradientEditor()
{
if (Gradient == null)
Gradient = new LinearGradient();
}
#endregion
#region Methods
public override void OnApplyTemplate()
{
if ((_gradientContainer = GetTemplateChild("PART_Gradient") as Canvas) != null)
{
_gradientContainer.SizeChanged += (sender, args) => UpdateGradientPreview();
_gradientContainer.MouseDown += GradientContainerOnMouseDown;
}
if ((_stopContainer = GetTemplateChild("PART_Stops") as Canvas) != null)
_stopContainer.SizeChanged += (sender, args) => UpdateGradientStops();
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
_window = Window.GetWindow(this);
if (_window != null)
{
_window.PreviewMouseDown += WindowMouseDown;
_window.PreviewKeyDown += (sender, args) =>
{
if (args.Key == Key.Escape)
SelectedStop = null;
};
}
UpdateGradientPreview();
UpdateGradientStops();
}
private void UpdateGradientPreview()
{
if ((_gradientContainer == null) || (Gradient == null)) return;
List<GradientStop> gradientStops = Gradient.GradientStops.OrderBy(x => x.Offset).ToList();
if (gradientStops.Count == 0)
UpdatePreviewRectangleCount(gradientStops.Count);
else if (gradientStops.Count == 1)
{
UpdatePreviewRectangleCount(gradientStops.Count);
GradientStop firstStop = gradientStops[0];
UpdatePreviewRectangle(_previewRectangles[0], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, 0, 1, firstStop.Color, firstStop.Color);
}
else
{
UpdatePreviewRectangleCount(gradientStops.Count + 1);
GradientStop firstStop = gradientStops[0];
UpdatePreviewRectangle(_previewRectangles[0], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, 0, firstStop.Offset, firstStop.Color, firstStop.Color);
for (int i = 0; i < (gradientStops.Count - 1); i++)
{
GradientStop stop = gradientStops[i];
GradientStop nextStop = gradientStops[i + 1];
Rectangle rect = _previewRectangles[i + 1];
UpdatePreviewRectangle(rect, _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, stop.Offset, nextStop.Offset, stop.Color, nextStop.Color);
}
GradientStop lastStop = gradientStops[gradientStops.Count - 1];
UpdatePreviewRectangle(_previewRectangles[_previewRectangles.Count - 1], _gradientContainer.ActualWidth, _gradientContainer.ActualHeight, lastStop.Offset, 1, lastStop.Color, lastStop.Color);
}
}
private void UpdatePreviewRectangle(Rectangle rect, double referenceWidth, double referenceHeight, double from, double to,
RGB.NET.Core.Color startColor, RGB.NET.Core.Color endColor)
{
rect.Fill = new LinearGradientBrush(Color.FromArgb(startColor.GetA(), startColor.GetR(), startColor.GetG(), startColor.GetB()),
Color.FromArgb(endColor.GetA(), endColor.GetR(), endColor.GetG(), endColor.GetB()),
new Point(0, 0.5), new Point(1, 0.5));
//DarthAffe 09.02.2018: Forced rounding to prevent render issues on resize
Canvas.SetLeft(rect, Math.Floor(referenceWidth * from.Clamp(0, 1)));
rect.Width = Math.Ceiling(referenceWidth * (to.Clamp(0, 1) - from.Clamp(0, 1)));
Canvas.SetTop(rect, 0);
rect.Height = referenceHeight;
}
private void UpdatePreviewRectangleCount(int gradientCount)
{
int countDiff = gradientCount - _previewRectangles.Count;
if (countDiff > 0)
for (int i = 0; i < countDiff; i++)
{
Rectangle rect = new Rectangle { VerticalAlignment = VerticalAlignment.Stretch };
_previewRectangles.Add(rect);
_gradientContainer.Children.Add(rect);
}
if (countDiff < 0)
for (int i = 0; i < Math.Abs(countDiff); i++)
{
int index = _previewRectangles.Count - i - 1;
Rectangle rect = _previewRectangles[index];
_previewRectangles.RemoveAt(index);
_gradientContainer.Children.Remove(rect);
}
}
private void UpdateGradientStops()
{
if (Gradient == null) return;
List<GradientStop> gradientStops = Gradient.GradientStops.OrderBy(x => x.Offset).ToList();
UpdateGradientStopsCount(gradientStops);
foreach (GradientStop stop in gradientStops)
UpdateGradientStop(_stops[stop], _stopContainer.ActualWidth, _stopContainer.ActualHeight, stop);
}
private void UpdateGradientStop(ContentControl control, double referenceWidth, double referenceHeight, GradientStop stop)
{
control.Background = new SolidColorBrush(Color.FromArgb(stop.Color.GetA(), stop.Color.GetR(), stop.Color.GetG(), stop.Color.GetB()));
Canvas.SetLeft(control, (referenceWidth * stop.Offset.Clamp(0, 1)) - (control.Width / 2.0));
Canvas.SetTop(control, 0);
control.Height = referenceHeight;
}
private void UpdateGradientStopsCount(List<GradientStop> gradientStops)
{
foreach (GradientStop stop in gradientStops)
{
if (!_stops.ContainsKey(stop))
{
ContentControl control = new ContentControl
{
VerticalAlignment = VerticalAlignment.Stretch,
Style = GradientStopStyle,
Content = stop
};
control.MouseDown += GradientStopOnMouseDown;
_stops.Add(stop, control);
_stopContainer.Children.Add(control);
}
}
List<GradientStop> stopsToRemove = new List<GradientStop>();
foreach (KeyValuePair<GradientStop, ContentControl> stopPair in _stops)
if (!gradientStops.Contains(stopPair.Key))
{
ContentControl control = stopPair.Value;
control.MouseDown -= GradientStopOnMouseDown;
stopsToRemove.Add(stopPair.Key);
_stopContainer.Children.Remove(control);
}
foreach (GradientStop stop in stopsToRemove)
_stops.Remove(stop);
}
private void AttachGradient(AbstractGradient gradient) => gradient.GradientChanged += GradientChanged;
private void DetachGradient(AbstractGradient gradient) => gradient.GradientChanged -= GradientChanged;
private void GradientChanged(object o, EventArgs eventArgs)
{
UpdateGradientPreview();
UpdateGradientStops();
}
private static void OnGradientChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is GradientEditor ge)) return;
if (dependencyPropertyChangedEventArgs.OldValue is AbstractGradient oldGradient)
ge.DetachGradient(oldGradient);
if (dependencyPropertyChangedEventArgs.NewValue is AbstractGradient newGradient)
ge.AttachGradient(newGradient);
}
private void GradientContainerOnMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if ((mouseButtonEventArgs.ChangedButton != MouseButton.Left) || (Gradient == null) || !CanAddOrDeleteStops) return;
double offset = mouseButtonEventArgs.GetPosition(_gradientContainer).X / _gradientContainer.ActualWidth;
RGB.NET.Core.Color color = Gradient.GetColor(offset);
GradientStop newStop = new GradientStop(offset, color);
Gradient.GradientStops.Add(newStop);
SelectedStop = newStop;
}
private void GradientStopOnMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if (!((o as ContentControl)?.Content is GradientStop stop) || (Gradient == null)) return;
if (mouseButtonEventArgs.ChangedButton == MouseButton.Right)
{
if (CanAddOrDeleteStops)
Gradient.GradientStops.Remove(stop);
}
else if (mouseButtonEventArgs.ChangedButton == MouseButton.Left)
{
SelectedStop = stop;
_draggingStop = (ContentControl)o;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_draggingStop?.Content is GradientStop stop)
{
double location = e.GetPosition(_gradientContainer).X;
stop.Offset = (location / _gradientContainer.ActualWidth).Clamp(0, 1);
}
}
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
_draggingStop = null;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
_draggingStop = null;
}
private static void SelectedStopChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is GradientEditor gradientEditor)) return;
if (gradientEditor._adorner != null)
gradientEditor._adornerLayer.Remove(gradientEditor._adorner);
if (dependencyPropertyChangedEventArgs.OldValue is GradientStop oldStop)
{
if (gradientEditor._stops.TryGetValue(oldStop, out ContentControl oldcontrol))
SetIsSelected(oldcontrol, false);
}
if (dependencyPropertyChangedEventArgs.NewValue is GradientStop stop)
{
ContentControl stopContainer = gradientEditor._stops[stop];
SetIsSelected(stopContainer, true);
if (gradientEditor._adornerLayer != null)
{
ContentControl contentControl = new ContentControl
{
ContentTemplate = gradientEditor.ColorSelectorTemplate,
Content = stop
};
ColorPickerAdorner adorner = new ColorPickerAdorner(stopContainer, contentControl);
gradientEditor._adorner = adorner;
gradientEditor._adornerLayer.Add(adorner);
}
}
}
private void WindowMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs)
{
if ((_adorner != null) && (VisualTreeHelper.HitTest(_adorner, mouseButtonEventArgs.GetPosition(_adorner)) == null))
SelectedStop = null;
}
#endregion
}
public class ColorPickerAdorner : Adorner
{
#region Properties & Fields
private readonly VisualCollection _visualChildren;
private readonly FrameworkElement _colorSelector;
protected override int VisualChildrenCount => 1;
protected override Visual GetVisualChild(int index) => _colorSelector;
#endregion
#region Constructors
public ColorPickerAdorner(UIElement adornedElement, FrameworkElement colorSelector)
: base(adornedElement)
{
this._colorSelector = colorSelector;
_visualChildren = new VisualCollection(this) { colorSelector };
}
#endregion
#region Methods
protected override Size ArrangeOverride(Size finalSize)
{
Window referenceWindow = Window.GetWindow(AdornedElement);
Point referenceLocation = AdornedElement.TranslatePoint(new Point(0, 0), referenceWindow);
double referenceWidth = ((FrameworkElement)AdornedElement).ActualWidth / 2.0;
double referenceHeight = ((FrameworkElement)AdornedElement).Height;
double referenceX = referenceLocation.X + referenceWidth;
double halfWidth = finalSize.Width / 2.0;
double maxOffset = referenceWindow.Width - halfWidth;
double offset = (referenceX < halfWidth ? referenceX
: (((referenceX + (referenceWidth * 2)) > maxOffset)
? halfWidth - ((maxOffset - referenceX) - (referenceWidth * 2))
: halfWidth));
_colorSelector.Arrange(new Rect(new Point(referenceWidth - offset, referenceHeight), finalSize));
return _colorSelector.RenderSize;
}
protected override Size MeasureOverride(Size constraint)
{
_colorSelector.Measure(constraint);
return _colorSelector.DesiredSize;
}
#endregion
}
}

View File

@ -24,11 +24,8 @@ namespace KeyboardAudioVisualizer.Decorators
protected override void Update(double deltaTime) => _visualizationProvider.Update();
public void ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, ref Color color)
{
color.APercent *= _visualizationProvider.VisualizationData[0];
}
#endregion
public Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color) => color.SetA(color.A * _visualizationProvider.VisualizationData[0]);
}
}

View File

@ -27,14 +27,13 @@ namespace KeyboardAudioVisualizer.Decorators
protected override void Update(double deltaTime) => _visualizationProvider.Update();
public void ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, ref Color color)
public Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color)
{
int barSampleIndex = Math.Min(_visualizationProvider.VisualizationData.Length, (int)Math.Floor(_visualizationProvider.VisualizationData.Length * (renderTarget.Point.X / (rectangle.Location.X + rectangle.Size.Width))));
double curBarHeight = 1.0 - Math.Max(0f, _visualizationProvider.VisualizationData[barSampleIndex]);
double verticalPos = (renderTarget.Point.Y / rectangle.Size.Height);
if (curBarHeight > verticalPos)
color.A = 0;
return curBarHeight > verticalPos ? color.SetA(0) : color;
}
#endregion

View File

@ -1,4 +1,5 @@
using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Decorators
@ -10,16 +11,18 @@ namespace KeyboardAudioVisualizer.Decorators
private readonly IVisualizationProvider _visualizationProvider;
public LevelBarDirection Direction { get; set; }
public int DataIndex { get; set; }
public LinearGradient Gradient { get; set; }
#endregion
#region Constructors
public LevelBarDecorator(IVisualizationProvider visualizationProvider, LevelBarDirection direction, int dataIndex)
public LevelBarDecorator(IVisualizationProvider visualizationProvider, LevelBarDirection direction, int dataIndex, LinearGradient gradient)
{
this._visualizationProvider = visualizationProvider;
this.Direction = direction;
this.DataIndex = dataIndex;
this.Gradient = gradient;
}
#endregion
@ -28,30 +31,37 @@ namespace KeyboardAudioVisualizer.Decorators
protected override void Update(double deltaTime) => _visualizationProvider.Update();
public void ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, ref Color color)
public Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color)
{
double offset = CalculateOffset(rectangle, renderTarget);
if (Direction == LevelBarDirection.Horizontal)
{
if (offset < 0)
{
offset = (-offset * 2);
if (offset >= _visualizationProvider.VisualizationData[0])
color.A = 0;
return color.SetA(0);
else
return Gradient.GetColor(offset);
}
else
{
offset *= 2;
if (offset >= _visualizationProvider.VisualizationData[1])
color.A = 0;
return color.SetA(0);
else
return Gradient.GetColor(offset);
}
}
else
{
if (offset >= _visualizationProvider.VisualizationData[DataIndex])
color.A = 0;
return color.SetA(0);
}
return color;
}
private double CalculateOffset(Rectangle rectangle, BrushRenderTarget renderTarget)

View File

@ -0,0 +1,68 @@
using System.Linq;
namespace KeyboardAudioVisualizer.Helper
{
public class RingBuffer
{
#region Properties & Fields
private readonly int _capacity;
private readonly float[] _buffer;
private int _currentIndex;
public int Size => _capacity;
public float Average => _buffer.Average();
public float Min => _buffer.Min();
public float Max => _buffer.Max();
public float Sum => _buffer.Sum();
#endregion
#region Constructors
public RingBuffer(int capacity)
{
this._capacity = capacity;
_buffer = new float[capacity];
}
#endregion
#region Methods
public void Put(float value) => Put(new[] { value }, 0, 1);
public void Put(float[] src, int offset, int count)
{
lock (_buffer)
{
if (count > _capacity)
{
offset += count - _capacity;
count = _capacity;
}
for (int i = 0; i < count; i++)
{
_currentIndex++;
if (_currentIndex >= _capacity) _currentIndex = 0;
_buffer[_currentIndex] = src[offset + i];
}
}
}
public void CopyInto(ref float[] data, int offset) => CopyInto(ref data, offset, _capacity);
public void CopyInto(ref float[] data, int offset, int count)
{
lock (_buffer)
for (int i = _capacity - count; i < count; i++)
data[offset + i] = _buffer[(_currentIndex + i) % _capacity];
}
#endregion
}
}

View File

@ -41,51 +41,69 @@
<ApplicationIcon>Resources\Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="CSCore, Version=1.2.1.1, Culture=neutral, PublicKeyToken=5a08f2b6f4415dea, processorArchitecture=MSIL">
<HintPath>..\packages\CSCore.1.2.1.1\lib\net35-client\CSCore.dll</HintPath>
<Reference Include="CSCore, Version=1.2.1.2, Culture=neutral, PublicKeyToken=5a08f2b6f4415dea, processorArchitecture=MSIL">
<HintPath>..\packages\CSCore.1.2.1.2\lib\net35-client\CSCore.dll</HintPath>
</Reference>
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
</Reference>
<Reference Include="MathNet.Numerics, Version=3.20.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MathNet.Numerics.3.20.0\lib\net40\MathNet.Numerics.dll</HintPath>
<Reference Include="HidSharp, Version=2.0.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\HidSharp.2.0.5\lib\net35\HidSharp.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Interop.AuraServiceLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Asus.0.1.31\lib\net45\Interop.AuraServiceLib.dll</HintPath>
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="RGB.NET.Brushes">
<HintPath>..\packages\RGB.NET.Brushes.1.0.0\lib\net45\RGB.NET.Brushes.dll</HintPath>
<Private>True</Private>
<Reference Include="MathNet.Numerics, Version=4.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MathNet.Numerics.4.7.0\lib\net461\MathNet.Numerics.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Core">
<HintPath>..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.CoolerMaster">
<HintPath>..\packages\RGB.NET.Devices.CoolerMaster.1.0.0\lib\net45\RGB.NET.Devices.CoolerMaster.dll</HintPath>
<Private>True</Private>
<Reference Include="RGB.NET.Brushes, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Brushes.0.1.31\lib\net45\RGB.NET.Brushes.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Corsair, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Corsair.1.0.0\lib\net45\RGB.NET.Devices.Corsair.dll</HintPath>
<Reference Include="RGB.NET.Core, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Core.0.1.31\lib\net45\RGB.NET.Core.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Logitech, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Logitech.1.0.0\lib\net45\RGB.NET.Devices.Logitech.dll</HintPath>
<Reference Include="RGB.NET.Decorators, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Decorators.0.1.31\lib\net45\RGB.NET.Decorators.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Novation, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Novation.1.0.0\lib\net45\RGB.NET.Devices.Novation.dll</HintPath>
<Reference Include="RGB.NET.Devices.Asus, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Asus.0.1.31\lib\net45\RGB.NET.Devices.Asus.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Groups, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Groups.1.0.0\lib\net45\RGB.NET.Groups.dll</HintPath>
<Reference Include="RGB.NET.Devices.CoolerMaster, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.CoolerMaster.0.1.31\lib\net45\RGB.NET.Devices.CoolerMaster.dll</HintPath>
</Reference>
<Reference Include="Sanford.Multimedia.Midi, Version=6.4.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Sanford.Multimedia.Midi.6.4.1\lib\net20\Sanford.Multimedia.Midi.dll</HintPath>
<Reference Include="RGB.NET.Devices.Corsair, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Corsair.0.1.31\lib\net45\RGB.NET.Devices.Corsair.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Logitech, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Logitech.0.1.31\lib\net45\RGB.NET.Devices.Logitech.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Novation, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Novation.0.1.31\lib\net45\RGB.NET.Devices.Novation.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.Razer, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.Razer.0.1.31\lib\net45\RGB.NET.Devices.Razer.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Devices.SteelSeries, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Devices.SteelSeries.0.1.31\lib\netstandard2.0\RGB.NET.Devices.SteelSeries.dll</HintPath>
</Reference>
<Reference Include="RGB.NET.Groups, Version=0.1.31.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RGB.NET.Groups.0.1.31\lib\net45\RGB.NET.Groups.dll</HintPath>
</Reference>
<Reference Include="Sanford.Multimedia.Midi, Version=6.6.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Sanford.Multimedia.Midi.6.6.0\lib\net20\Sanford.Multimedia.Midi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Numerics" />
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
@ -140,6 +158,9 @@
<Compile Include="AudioProcessing\VisualizationProvider\LevelVisualizationProvider.cs" />
<Compile Include="AudioProcessing\Spectrum\RawSpectrumProvider.cs" />
<Compile Include="AudioProcessing\VisualizationProvider\VisualizationType.cs" />
<Compile Include="Configuration\ColorSerializer.cs" />
<Compile Include="Controls\ColorSelector.cs" />
<Compile Include="Controls\GradientEditor.cs" />
<Compile Include="Converter\VisualizationProviderDisplayNameConverter.cs" />
<Compile Include="Converter\VisualizationToLastChildFillConverter.cs" />
<Compile Include="Converter\VisualizationTypeSelectableConverter.cs" />
@ -149,7 +170,7 @@
<Compile Include="Configuration\AbstractConfiguration.cs" />
<Compile Include="Configuration\EqualizerConfiguration.cs" />
<Compile Include="Configuration\IConfiguration.cs" />
<Compile Include="Controls\Formular.cs" />
<Compile Include="Controls\Form.cs" />
<Compile Include="Controls\ImageButton.cs" />
<Compile Include="Converter\BoolToVisibilityConverter.cs" />
<Compile Include="Converter\EqualizerBandsToPointsConverter.cs" />
@ -162,11 +183,13 @@
<Compile Include="Helper\FrequencyHelper.cs" />
<Compile Include="Helper\MathHelper.cs" />
<Compile Include="Helper\ObservableDictionary.cs" />
<Compile Include="Helper\RingBuffer.cs" />
<Compile Include="Helper\VisualizationIndex.cs" />
<Compile Include="Helper\WPFHelper.cs" />
<Compile Include="Configuration\Settings.cs" />
<Compile Include="Controls\BlurredDecorationWindow.cs" />
<Compile Include="Legacy\ConfigurationMigrator.cs" />
<Compile Include="Legacy\ConfigurationUpdates.cs" />
<Compile Include="Legacy\Settings.cs" />
<Compile Include="Styles\CachedResourceDictionary.cs" />
<Compile Include="UI\ConfigurationWindow.xaml.cs">
@ -198,7 +221,6 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="NuGet.Config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
@ -224,6 +246,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\ColorSelector.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\FrameworkElement.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -236,6 +262,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\GradientEditor.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Slider.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -256,7 +286,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Styles\Formular.xaml">
<Page Include="Styles\Form.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
@ -304,15 +334,21 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\RGB.NET.Devices.Corsair.1.0.0\build\net45\RGB.NET.Devices.Corsair.targets" Condition="Exists('..\packages\RGB.NET.Devices.Corsair.1.0.0\build\net45\RGB.NET.Devices.Corsair.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\RGB.NET.Devices.Corsair.1.0.0\build\net45\RGB.NET.Devices.Corsair.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Devices.Corsair.1.0.0\build\net45\RGB.NET.Devices.Corsair.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Devices.CoolerMaster.1.0.0\build\net45\RGB.NET.Devices.CoolerMaster.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Devices.CoolerMaster.1.0.0\build\net45\RGB.NET.Devices.CoolerMaster.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Devices.Logitech.1.0.0\build\net45\RGB.NET.Devices.Logitech.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Devices.Logitech.1.0.0\build\net45\RGB.NET.Devices.Logitech.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.Novation.0.1.0\build\RGB.NET.Resources.Novation.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.Novation.0.1.0\build\RGB.NET.Resources.Novation.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.CoolerMaster.0.2.0\build\RGB.NET.Resources.CoolerMaster.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.CoolerMaster.0.2.0\build\RGB.NET.Resources.CoolerMaster.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.Corsair.0.3.0.234\build\RGB.NET.Resources.Corsair.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.Corsair.0.3.0.234\build\RGB.NET.Resources.Corsair.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.Logitech.0.3.0\build\RGB.NET.Resources.Logitech.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.Logitech.0.3.0\build\RGB.NET.Resources.Logitech.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.Razer.0.3.2.4\build\RGB.NET.Resources.Razer.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.Razer.0.3.2.4\build\RGB.NET.Resources.Razer.targets'))" />
<Error Condition="!Exists('..\packages\RGB.NET.Resources.Asus.0.3.0\build\RGB.NET.Resources.Asus.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\RGB.NET.Resources.Asus.0.3.0\build\RGB.NET.Resources.Asus.targets'))" />
</Target>
<Import Project="..\packages\RGB.NET.Devices.CoolerMaster.1.0.0\build\net45\RGB.NET.Devices.CoolerMaster.targets" Condition="Exists('..\packages\RGB.NET.Devices.CoolerMaster.1.0.0\build\net45\RGB.NET.Devices.CoolerMaster.targets')" />
<Import Project="..\packages\RGB.NET.Devices.Logitech.1.0.0\build\net45\RGB.NET.Devices.Logitech.targets" Condition="Exists('..\packages\RGB.NET.Devices.Logitech.1.0.0\build\net45\RGB.NET.Devices.Logitech.targets')" />
<Import Project="..\packages\RGB.NET.Resources.Novation.0.1.0\build\RGB.NET.Resources.Novation.targets" Condition="Exists('..\packages\RGB.NET.Resources.Novation.0.1.0\build\RGB.NET.Resources.Novation.targets')" />
<Import Project="..\packages\RGB.NET.Resources.CoolerMaster.0.2.0\build\RGB.NET.Resources.CoolerMaster.targets" Condition="Exists('..\packages\RGB.NET.Resources.CoolerMaster.0.2.0\build\RGB.NET.Resources.CoolerMaster.targets')" />
<Import Project="..\packages\RGB.NET.Resources.Corsair.0.3.0.234\build\RGB.NET.Resources.Corsair.targets" Condition="Exists('..\packages\RGB.NET.Resources.Corsair.0.3.0.234\build\RGB.NET.Resources.Corsair.targets')" />
<Import Project="..\packages\RGB.NET.Resources.Logitech.0.3.0\build\RGB.NET.Resources.Logitech.targets" Condition="Exists('..\packages\RGB.NET.Resources.Logitech.0.3.0\build\RGB.NET.Resources.Logitech.targets')" />
<Import Project="..\packages\RGB.NET.Resources.Razer.0.3.2.4\build\RGB.NET.Resources.Razer.targets" Condition="Exists('..\packages\RGB.NET.Resources.Razer.0.3.2.4\build\RGB.NET.Resources.Razer.targets')" />
<Import Project="..\packages\RGB.NET.Resources.Asus.0.3.0\build\RGB.NET.Resources.Asus.targets" Condition="Exists('..\packages\RGB.NET.Resources.Asus.0.3.0\build\RGB.NET.Resources.Asus.targets')" />
</Project>

View File

@ -0,0 +1,37 @@
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
namespace KeyboardAudioVisualizer.Legacy
{
public static class ConfigurationUpdates
{
#region Methods
public static void PerformOn(Configuration.Settings settings)
{
if (settings.Version < 1)
UpdateTo1(settings);
}
private static void UpdateTo1(Configuration.Settings settings)
{
settings.Visualizations[VisualizationIndex.Primary].Gradient = new LinearGradient(new GradientStop(0, HSVColor.Create(300, 1, 1)),
new GradientStop(0.20, HSVColor.Create(225, 1, 1)),
new GradientStop(0.35, HSVColor.Create(180, 1, 1)),
new GradientStop(0.50, HSVColor.Create(135, 1, 1)),
new GradientStop(0.65, HSVColor.Create(90, 1, 1)),
new GradientStop(0.80, HSVColor.Create(45, 1, 1)),
new GradientStop(0.95, HSVColor.Create(0, 1, 1)));
settings.Visualizations[VisualizationIndex.Secondary].Gradient = new LinearGradient(new GradientStop(0.5, new Color(255, 255, 255)));
settings.Visualizations[VisualizationIndex.Tertiary].Gradient = new LinearGradient(new GradientStop(0, new Color(0, 0, 255)),
new GradientStop(1, new Color(255, 0, 0)));
settings.Version = 1;
}
#endregion
}
}

View File

@ -49,5 +49,5 @@ using System.Windows;
// 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.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyVersion("1.3.1.1")]
[assembly: AssemblyFileVersion("1.3.1.1")]

View File

@ -8,12 +8,14 @@
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/BlurredDecorationWindow.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/ImageButton.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Formular.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Form.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/GroupBox.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/ToolTip.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/ComboBox.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Button.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/Slider.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/ColorSelector.xaml" />
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/GradientEditor.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<converter:EqualsToBoolConverter x:Key="EqualsToBoolConverter" />
@ -22,7 +24,7 @@
<Style TargetType="{x:Type controls:BlurredDecorationWindow}" BasedOn="{StaticResource StyleBlurredDecorationWindow}" />
<Style TargetType="{x:Type ui:ConfigurationWindow}" BasedOn="{StaticResource StyleBlurredDecorationWindow}" />
<Style TargetType="{x:Type controls:ImageButton}" BasedOn="{StaticResource StyleImageButton}" />
<Style TargetType="{x:Type controls:Formular}" BasedOn="{StaticResource StyleFormular}" />
<Style TargetType="{x:Type controls:Form}" BasedOn="{StaticResource StyleForm}" />
<Style TargetType="GroupBox" BasedOn="{StaticResource StyleGroupBoxBox}" />
<Style TargetType="ToolTip" BasedOn="{StaticResource StyleToolTip}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource StyleComboBox}" />

View File

@ -0,0 +1,305 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:KeyboardAudioVisualizer.Controls"
xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles">
<DrawingBrush x:Key="BrushChessboard"
TileMode="Tile"
Viewport="0,0,16,16"
ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF808080"
Geometry="M5,5 L0,5 0,10 5,10 5,5 10,5 10,0 5,0 Z"/>
</DrawingBrush.Drawing>
</DrawingBrush>
<DrawingBrush x:Key="BrushChessboardSmall"
TileMode="Tile"
Viewport="0,0,8,8"
ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF808080"
Geometry="M5,5 L0,5 0,10 5,10 5,5 10,5 10,0 5,0 Z"/>
</DrawingBrush.Drawing>
</DrawingBrush>
<Style x:Key="StyleSliderLabel"
TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="StyleSliderValue"
TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="StyleThumbSlider"
TargetType="Thumb">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Height" Value="NaN" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border VerticalAlignment="Stretch"
Width="4"
SnapsToDevicePixels="True"
Opacity="0.66"
BorderThickness="1"
Background="#FFFFFFFF"
BorderBrush="#FF000000" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleSlider"
TargetType="Slider">
<Setter Property="Focusable" Value="False" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FF000000" />
<Setter Property="IsMoveToPointEnabled" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Border SnapsToDevicePixels="True"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="#FFFFFFFF">
<Border Margin="1"
SnapsToDevicePixels="True"
Background="{StaticResource BrushChessboardSmall}">
<Border SnapsToDevicePixels="True"
Background="{TemplateBinding Background}">
<Grid x:Name="GridTrackParent" SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Track x:Name="PART_Track"
Grid.Row="1"
Width="{Binding ActualWidth, ElementName=GridTrackParent}"
Height="{Binding ActualHeight, ElementName=GridTrackParent}">
<Track.DecreaseRepeatButton>
<RepeatButton Visibility="Hidden" Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource StyleThumbSlider}" />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Visibility="Hidden" Command="Slider.IncreaseLarge" />
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</Border>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StyleColorSelector"
TargetType="{x:Type controls:ColorSelector}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="504" />
<Setter Property="Height" Value="232" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ColorSelector}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<DockPanel Margin="{TemplateBinding Padding}">
<Border DockPanel.Dock="Left"
SnapsToDevicePixels="True"
Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
BorderThickness="1"
BorderBrush="#FF000000"
Background="#FFFFFFFF">
<Grid x:Name="PART_Selector"
Margin="1"
SnapsToDevicePixels="True" />
</Border>
<Slider DockPanel.Dock="Left"
Margin="8,0"
Height="24"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
Background="{Binding Background, ElementName=PART_SliderHue}"
Minimum="{Binding Minimum, ElementName=PART_SliderHue}"
Maximum="{Binding Maximum, ElementName=PART_SliderHue}"
Value="{Binding Value, ElementName=PART_SliderHue}">
<Slider.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="90" />
</Slider.LayoutTransform>
</Slider>
<DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="28" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Alpha:" />
<Slider x:Name="PART_SliderAlpha"
Grid.Row="0" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="0" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderAlpha, StringFormat=##0}" />
<TextBlock Grid.Row="2" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Hue:" />
<Slider x:Name="PART_SliderHue"
Grid.Row="2" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="360" />
<TextBlock Grid.Row="2" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderHue, StringFormat=##0}" />
<TextBlock Grid.Row="4" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Sat:" />
<Slider x:Name="PART_SliderSaturation"
Grid.Row="4" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="1" />
<TextBlock Grid.Row="4" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderSaturation, StringFormat=0.00}" />
<TextBlock Grid.Row="6" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Value:" />
<Slider x:Name="PART_SliderValue"
Grid.Row="6" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
IsSnapToTickEnabled="False"
Minimum="0"
Maximum="1" />
<TextBlock Grid.Row="6" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderValue, StringFormat=0.00}" />
<TextBlock Grid.Row="8" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Red:" />
<Slider x:Name="PART_SliderRed"
Grid.Row="8" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="8" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderRed, StringFormat=000}" />
<TextBlock Grid.Row="10" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Green:" />
<Slider x:Name="PART_SliderGreen"
Grid.Row="10" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="10" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderGreen, StringFormat=000}" />
<TextBlock Grid.Row="12" Grid.Column="0"
Style="{StaticResource StyleSliderLabel}"
Text="Blue:" />
<Slider x:Name="PART_SliderBlue"
Grid.Row="12" Grid.Column="2"
Orientation="Horizontal"
Style="{StaticResource StyleSlider}"
TickFrequency="1"
IsSnapToTickEnabled="True"
Minimum="0"
Maximum="255" />
<TextBlock Grid.Row="12" Grid.Column="4"
Style="{StaticResource StyleSliderValue}"
Text="{Binding Value, ElementName=PART_SliderBlue, StringFormat=000}" />
</Grid>
<Border HorizontalAlignment="Stretch"
Margin="0,0,0,4"
SnapsToDevicePixels="True"
BorderThickness="1"
BorderBrush="#FF000000"
Background="#FFFFFFFF">
<Border Margin="1"
SnapsToDevicePixels="True"
Background="{StaticResource BrushChessboard}">
<Rectangle x:Name="PART_Preview"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
SnapsToDevicePixels="True" />
</Border>
</Border>
</DockPanel>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:ColorSelector}" BasedOn="{StaticResource StyleColorSelector}" />
</styles:CachedResourceDictionary>

View File

@ -7,9 +7,9 @@
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/FrameworkElement.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleFormular"
<Style x:Key="StyleForm"
BasedOn="{StaticResource StyleFrameworkElement}"
TargetType="{x:Type controls:Formular}">
TargetType="{x:Type controls:Form}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="LabelWidth" Value="112" />
@ -17,7 +17,7 @@
<Setter Property="RowSpacing" Value="8" />
</Style>
<Style x:Key="StyleLabelFormular"
<Style x:Key="StyleLabelForm"
TargetType="Label">
<Setter Property="Foreground" Value="{StaticResource BrushForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
@ -44,7 +44,7 @@
</Setter>
</Style>
<Style x:Key="StyleTextBlockFormular"
<Style x:Key="StyleTextBlockForm"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource BrushForeground}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeDefault}" />
@ -53,7 +53,7 @@
<Setter Property="TextAlignment" Value="Left" />
</Style>
<Style x:Key="StyleListBoxItemFormular"
<Style x:Key="StyleListBoxItemForm"
TargetType="ListBoxItem">
<Setter Property="MinWidth" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
@ -77,7 +77,7 @@
</Setter>
</Style>
<Style x:Key="StyleListBoxFormular"
<Style x:Key="StyleListBoxForm"
TargetType="ListBox">
<Setter Property="Focusable" Value="False" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
@ -92,7 +92,7 @@
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="ItemContainerStyle" Value="{StaticResource StyleListBoxItemFormular}" />
<Setter Property="ItemContainerStyle" Value="{StaticResource StyleListBoxItemForm}" />
</Style>
</styles:CachedResourceDictionary>

View File

@ -0,0 +1,93 @@
<styles:CachedResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:KeyboardAudioVisualizer.Controls"
xmlns:styles="clr-namespace:KeyboardAudioVisualizer.Styles">
<styles:CachedResourceDictionary.MergedDictionaries>
<styles:CachedResourceDictionary Source="/KeyboardAudioVisualizer;component/Styles/ColorSelector.xaml" />
</styles:CachedResourceDictionary.MergedDictionaries>
<Style x:Key="StyleGradientStop"
TargetType="ContentControl">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Width" Value="12" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FFFFFFFF" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type GradientStop}">
<Grid>
<Path Stretch="Fill"
Data="M 0.5,0 L 0,0.25 L 0,1 L 1,1 L 1,0.25 Z"
StrokeThickness="0"
Fill="{StaticResource BrushChessboardSmall}" />
<Path Stretch="Fill"
Data="M 0.5,0 L 0,0.25 L 0,1 L 1,1 L 1,0.25 Z"
Stroke="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=ContentControl}}"
StrokeThickness="{Binding BorderThickness, RelativeSource={RelativeSource AncestorType=ContentControl}}"
Fill="{Binding Background, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding (controls:GradientEditor.IsSelected), RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="BorderBrush" Value="#FF808080" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="StyleGradientEditor"
TargetType="{x:Type controls:GradientEditor}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Height" Value="60" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="GradientStopStyle" Value="{StaticResource StyleGradientStop}" />
<Setter Property="ColorSelectorTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type GradientStop}">
<GroupBox>
<controls:ColorSelector Foreground="#FFFFFFFF" SelectedColor="{Binding Color}" />
</GroupBox>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:GradientEditor}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<DockPanel>
<Border DockPanel.Dock="Bottom"
Height="16">
<Canvas x:Name="PART_Stops"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="Transparent" />
</Border>
<Border Background="{StaticResource BrushChessboard}">
<Canvas x:Name="PART_Gradient"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Background="Transparent" />
</Border>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:GradientEditor}" BasedOn="{StaticResource StyleGradientEditor}" />
</styles:CachedResourceDictionary>

View File

@ -13,14 +13,14 @@
<DataTemplate DataType="{x:Type visualizationProvider:BeatVisualizationProviderConfiguration}">
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</Grid.Resources>
<controls:Formular LabelWidth="240">
<Label controls:Formular.IsLabel="True" Content="No configuration available ..." />
</controls:Formular>
<controls:Form LabelWidth="240">
<Label controls:Form.IsLabel="True" Content="No configuration available ..." />
</controls:Form>
</Grid>
</DataTemplate>

View File

@ -14,9 +14,9 @@
<DataTemplate DataType="{x:Type visualizationProvider:FrequencyBarsVisualizationProviderConfiguration}">
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
<ObjectDataProvider x:Key="SpectrumModes" MethodName="GetValues" ObjectType="{x:Type system:Enum}">
<ObjectDataProvider.MethodParameters>
@ -39,62 +39,62 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:Formular Grid.Column="0">
<Label controls:Formular.IsLabel="True" Content="Spectrum:" />
<ComboBox controls:Formular.Fill="True"
<controls:Form Grid.Column="0">
<Label controls:Form.IsLabel="True" Content="Spectrum:" />
<ComboBox controls:Form.Fill="True"
ItemsSource="{Binding Source={StaticResource SpectrumModes}}"
SelectedItem="{Binding SpectrumMode}"
ToolTip="Defines how the spectrum is grouped together.&#x0a; - Linear: Each bar represents the same range of frequencies.&#x0a; - Logarithmic: The higher the frequencies get the wider the range of grouped frequencies.&#x0a; - Gamma: Uses a configurable Gamma-Value to group the frequencies." />
<Label controls:Formular.IsLabel="True" Content="Value:" />
<ComboBox controls:Formular.Fill="True"
<Label controls:Form.IsLabel="True" Content="Value:" />
<ComboBox controls:Form.Fill="True"
ItemsSource="{Binding Source={StaticResource ValueModes}}"
SelectedItem="{Binding ValueMode}"
ToolTip="Defines how the value of a bar is calculated.&#x0a; - Sum: Sums the power of all frequencies grouped in the bar using all available data.&#x0a; - Max: Uses the maximum value in each group making sure peaks are caught well.&#x0a; - Average: Uses the average of all frequencies grouped in the bar. " />
<Label controls:Formular.IsLabel="True" Content="Bars:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="96" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight"
<Label controls:Form.IsLabel="True" Content="Bars:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="96" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight"
Value="{Binding Bars}"
ToolTip="The number of bars used to represent the spectrum.." />
</controls:Formular>
</controls:Form>
<controls:Formular Grid.Column="2">
<Label controls:Formular.IsLabel="True" Content="Min Freq.:" />
<Slider controls:Formular.Fill="True" Minimum="0" Maximum="22100" IsSnapToTickEnabled="True" TickFrequency="10" TickPlacement="None"
<controls:Form Grid.Column="2">
<Label controls:Form.IsLabel="True" Content="Min Freq.:" />
<Slider controls:Form.Fill="True" Minimum="0" Maximum="22100" IsSnapToTickEnabled="True" TickFrequency="10" TickPlacement="None"
Value="{Binding MinFrequency}"
attached:SliderValue.Unit="Hz"
ToolTip="The minimum frequency used in the graph." />
<Label controls:Formular.IsLabel="True" Content="Max Freq.:" />
<Slider controls:Formular.Fill="True" Minimum="0" Maximum="22100" IsSnapToTickEnabled="True" TickFrequency="10" TickPlacement="None"
<Label controls:Form.IsLabel="True" Content="Max Freq.:" />
<Slider controls:Form.Fill="True" Minimum="0" Maximum="22100" IsSnapToTickEnabled="True" TickFrequency="10" TickPlacement="None"
Value="{Binding MaxFrequency}"
attached:SliderValue.Unit="Hz"
ToolTip="The maximum frequency used in the graph." />
<Label controls:Formular.IsLabel="True" Content="Gamma:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="6" IsSnapToTickEnabled="True" TickFrequency="0.25" TickPlacement="BottomRight"
<Label controls:Form.IsLabel="True" Content="Gamma:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="6" IsSnapToTickEnabled="True" TickFrequency="0.25" TickPlacement="BottomRight"
IsEnabled="{Binding SpectrumMode, Converter={StaticResource EqualsToBoolConverter}, ConverterParameter={x:Static visualizationProvider:SpectrumMode.Gamma}}"
Value="{Binding Gamma}"
ToolTip="Only used if 'Gamma' is selected as spectrum!&#x0a;Higher values cause more compression of high frequencies." />
</controls:Formular>
</controls:Form>
<controls:Formular Grid.Column="4">
<Label controls:Formular.IsLabel="True" controls:Formular.LineBreaks="1" Content="Reference:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="240" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="None"
<controls:Form Grid.Column="4">
<Label controls:Form.IsLabel="True" controls:Form.LineBreaks="1" Content="Reference:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="240" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="None"
Value="{Binding ReferenceLevel}"
attached:SliderValue.Unit="dB"
ToolTip="The reference value used to calculate the power of each bar.&#x0a;(You can read this as 'scaling')" />
<Label controls:Formular.IsLabel="True" controls:Formular.LineBreaks="1" Content="Smoothing:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="10" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
<Label controls:Form.IsLabel="True" controls:Form.LineBreaks="1" Content="Smoothing:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="10" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
Value="{Binding Smoothing}"
ToolTip="Smooths the graph to prevent flickering.&#x0a;Low values will cause a hectic fast plot, high values a slow one without peaks." />
<Label controls:Formular.IsLabel="True" controls:Formular.LineBreaks="1" Content="Emphasize:" />
<Slider controls:Formular.Fill="True" Minimum="0" Maximum="2" IsSnapToTickEnabled="True" TickFrequency="0.05" TickPlacement="BottomRight"
<Label controls:Form.IsLabel="True" controls:Form.LineBreaks="1" Content="Emphasize:" />
<Slider controls:Form.Fill="True" Minimum="0" Maximum="2" IsSnapToTickEnabled="True" TickFrequency="0.05" TickPlacement="BottomRight"
Value="{Binding EmphasisePeaks}"
ToolTip="Emphasizes peaks. The higher the value, the bigger the difference between a 'loud-bar' and a 'quite-bar'." />
</controls:Formular>
</controls:Form>
</Grid>
</DataTemplate>

View File

@ -13,9 +13,9 @@
<DataTemplate DataType="{x:Type visualizationProvider:LevelVisualizationProviderConfiguration}">
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
<ObjectDataProvider x:Key="ConversionModes" MethodName="GetValues" ObjectType="{x:Type system:Enum}">
<ObjectDataProvider.MethodParameters>
@ -32,27 +32,27 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:Formular Grid.Column="0">
<Label controls:Formular.IsLabel="True" Content="Calculation:" />
<ComboBox controls:Formular.Fill="True"
<controls:Form Grid.Column="0">
<Label controls:Form.IsLabel="True" Content="Calculation:" />
<ComboBox controls:Form.Fill="True"
ItemsSource="{Binding Source={StaticResource ConversionModes}}"
SelectedItem="{Binding ConversionMode}"
ToolTip="Defines how the RMS of the audio is plotted.&#x0a;Exponential has the widest range of peaks while linear has the least." />
</controls:Formular>
</controls:Form>
<controls:Formular Grid.Column="2">
<Label controls:Formular.IsLabel="True" Content="Scale:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="20" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
<controls:Form Grid.Column="2">
<Label controls:Form.IsLabel="True" Content="Scale:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="40" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
Value="{Binding Scale}"
ToolTip="Scales the whole graph." />
</controls:Formular>
</controls:Form>
<controls:Formular Grid.Column="4">
<Label controls:Formular.IsLabel="True" controls:Formular.LineBreaks="1" Content="Smoothing:" />
<Slider controls:Formular.Fill="True" Minimum="1" Maximum="10" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
<controls:Form Grid.Column="4">
<Label controls:Form.IsLabel="True" controls:Form.LineBreaks="1" Content="Smoothing:" />
<Slider controls:Form.Fill="True" Minimum="1" Maximum="10" IsSnapToTickEnabled="True" TickFrequency="0.5" TickPlacement="BottomRight"
Value="{Binding Smoothing}"
ToolTip="Smooths the plot to prevent flickering.&#x0a;Low values will cause a hectic fast plot, high values a slow one without peaks." />
</controls:Formular>
</controls:Form>
</Grid>
</DataTemplate>

View File

@ -15,12 +15,22 @@ namespace KeyboardAudioVisualizer.UI
public double UpdateRate
{
get => 1.0 / RGBSurface.Instance.UpdateFrequency;
get => 1.0 / ApplicationManager.Instance.UpdateTrigger.UpdateFrequency;
set
{
double val = MathHelper.Clamp(value, 1, 40);
double val = MathHelper.Clamp(value, 1, 60);
ApplicationManager.Instance.Settings.UpdateRate = val;
RGBSurface.Instance.UpdateFrequency = 1.0 / val;
ApplicationManager.Instance.UpdateTrigger.UpdateFrequency = 1.0 / val;
OnPropertyChanged();
}
}
public bool EnableAudioPrescale
{
get => ApplicationManager.Instance.Settings.EnableAudioPrescale;
set
{
ApplicationManager.Instance.Settings.EnableAudioPrescale = value;
OnPropertyChanged();
}
}

View File

@ -10,14 +10,15 @@
xmlns:keyboardAudioVisualizer="clr-namespace:KeyboardAudioVisualizer"
xmlns:converter="clr-namespace:KeyboardAudioVisualizer.Converter"
xmlns:visualizationProvider="clr-namespace:KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider"
xmlns:helper="clr-namespace:KeyboardAudioVisualizer.Helper"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:attached="clr-namespace:KeyboardAudioVisualizer.Attached"
xmlns:helper="clr-namespace:KeyboardAudioVisualizer.Helper"
mc:Ignorable="d"
Title="Keyboard Audio-Visualizer # Configuration"
Icon="pack://application:,,,/KeyboardAudioVisualizer;component/Resources/Icon.ico"
IconCommand="{Binding OpenHomepageCommand}"
Width="1280" Height="720">
Width="1280" Height="720"
Closed="ConfigurationWindow_OnClosed">
<controls:BlurredDecorationWindow.Resources>
<styles:CachedResourceDictionary>
@ -56,21 +57,26 @@
<AdornerDecorator>
<DockPanel LastChildFill="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Primary], Converter={StaticResource VisualizationToLastChildFillConverter}}">
<GroupBox DockPanel.Dock="Top">
<controls:Formular>
<controls:Formular.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
</controls:Formular.Resources>
<controls:GradientEditor Gradient="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Settings[(helper:VisualizationIndex)Primary].Gradient}"
ToolTip="Defines the gradient that's drawed on the device. Usage:&#x0a; Left click inside the preview to add a new stop.&#x0a; Left-click stop to change the color or move it.&#x0a; Right-click stop to remove it.&#x0a;" />
</GroupBox>
<Label controls:Formular.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Formular.Fill="True" SelectedIndex="0"
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<controls:Form>
<controls:Form.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</controls:Form.Resources>
<Label controls:Form.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Form.Fill="True" SelectedIndex="0"
ItemTemplate="{StaticResource DataTemplateVisualizationSelection}"
ItemsSource="{Binding Source={StaticResource DataProviderVisualizationTypes},
Converter={StaticResource VisualizationProviderSelectableConverter}, ConverterParameter={x:Static core:RGBDeviceType.Keyboard}}"
SelectedItem="{Binding SelectedPrimaryVisualization}"
ToolTip="The visualization shown on the device.&#x0a; - Frequency Bars: Shows vertical bars representing the frequencies of the song.&#x0a; - Level: Shows two horizontal bars representing the loudness of the song (left and right).&#x0a; - Beat: Shows a flash to the beat of the song (this doesn't work too well right now :()" />
</controls:Formular>
</controls:Form>
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
@ -78,7 +84,7 @@
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Primary]}" />
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Primary]}" Tag="0" />
</GroupBox>
</DockPanel>
</AdornerDecorator>
@ -88,20 +94,25 @@
<AdornerDecorator>
<DockPanel LastChildFill="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Secondary], Converter={StaticResource VisualizationToLastChildFillConverter}}">
<GroupBox DockPanel.Dock="Top">
<controls:Formular>
<controls:Formular.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
</controls:Formular.Resources>
<controls:GradientEditor Gradient="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Settings[(helper:VisualizationIndex)Secondary].Gradient}"
CanAddOrDeleteStops="False" />
</GroupBox>
<Label controls:Formular.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Formular.Fill="True" SelectedIndex="0"
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<controls:Form>
<controls:Form.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</controls:Form.Resources>
<Label controls:Form.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Form.Fill="True" SelectedIndex="0"
ItemTemplate="{StaticResource DataTemplateVisualizationSelection}"
ItemsSource="{Binding Source={StaticResource DataProviderVisualizationTypes},
Converter={StaticResource VisualizationProviderSelectableConverter}, ConverterParameter={x:Static core:RGBDeviceType.Mouse}}"
SelectedItem="{Binding SelectedSecondaryVisualization}" />
</controls:Formular>
</controls:Form>
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
@ -109,7 +120,7 @@
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Secondary]}" />
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Secondary]}" Tag="1" />
</GroupBox>
</DockPanel>
</AdornerDecorator>
@ -119,20 +130,24 @@
<AdornerDecorator>
<DockPanel LastChildFill="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Tertiary], Converter={StaticResource VisualizationToLastChildFillConverter}}">
<GroupBox DockPanel.Dock="Top">
<controls:Formular>
<controls:Formular.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
</controls:Formular.Resources>
<controls:GradientEditor Gradient="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Settings[(helper:VisualizationIndex)Tertiary].Gradient}" />
</GroupBox>
<Label controls:Formular.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Formular.Fill="True" SelectedIndex="0"
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<controls:Form>
<controls:Form.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</controls:Form.Resources>
<Label controls:Form.IsLabel="True" Content="Visualization: " />
<ComboBox controls:Form.Fill="True" SelectedIndex="0"
ItemTemplate="{StaticResource DataTemplateVisualizationSelection}"
ItemsSource="{Binding Source={StaticResource DataProviderVisualizationTypes},
Converter={StaticResource VisualizationProviderSelectableConverter}, ConverterParameter={x:Static core:RGBDeviceType.Mousepad}}"
SelectedItem="{Binding SelectedTertiaryVisualization}" />
</controls:Formular>
</controls:Form>
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
@ -140,7 +155,7 @@
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Tertiary]}" />
<ContentControl Content="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Visualizations[(helper:VisualizationIndex)Tertiary]}" Tag="2" />
</GroupBox>
</DockPanel>
</AdornerDecorator>
@ -148,55 +163,70 @@
<TabItem Header="Settings">
<AdornerDecorator>
<GroupBox VerticalAlignment="Top">
<StackPanel Orientation="Vertical">
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource StyleLabelFormular}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockFormular}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxFormular}" TargetType="ListBox" />
</Grid.Resources>
<DockPanel LastChildFill="False">
<DockPanel.Resources>
<Style BasedOn="{StaticResource StyleLabelForm}" TargetType="Label" />
<Style BasedOn="{StaticResource StyleTextBlockForm}" TargetType="TextBlock" />
<Style BasedOn="{StaticResource StyleListBoxForm}" TargetType="ListBox" />
</DockPanel.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<GroupBox DockPanel.Dock="Top">
<controls:Form>
<Label controls:Form.IsLabel="True" Content="Version" />
<TextBlock Text="{Binding Version}" />
<controls:Formular Grid.Column="0">
<Label controls:Formular.IsLabel="True" Content="Version:" />
<TextBlock Text="{Binding Version}" />
<Label controls:Form.IsLabel="True" Content="Update-Rate" />
<Slider Minimum="1" Maximum="60" controls:Form.Fill="True" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight"
Value="{Binding UpdateRate}"
attached:SliderValue.Unit="FPS"
ToolTip="Defines how fast the data is updated.&#x0a;Low values can reduce CPU-usage but will cause stuttering.&#x0a;Values above 40 will only affect the internal calculations and wont make the keyboard update faster.&#x0a;It's not recommended to select a value > 40." />
<Label controls:Formular.IsLabel="True" Content="Update-Rate" />
<Slider Minimum="1" Maximum="40" controls:Formular.Fill="True" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="BottomRight"
Value="{Binding UpdateRate}"
attached:SliderValue.Unit="FPS"
ToolTip="Defines how fast the data is updated.&#x0a;Low values can reduce CPU-usage but will cause stuttering." />
<Label controls:Form.IsLabel="True" Content="Fix Volume" />
<CheckBox VerticalAlignment="Center"
IsChecked="{Binding EnableAudioPrescale}"
ToolTip="Scales the audio signal inverse to the OS-master-volume.&#x0a;This might (depending on the system) lead to decrased performance&#x0a; -> only activate it if you need it." />
<Label controls:Formular.LineBreaks="1" controls:Formular.IsLabel="True" Content="Devices:" />
</controls:Formular>
</Grid>
</controls:Form>
</GroupBox>
<!-- TODO DarthAffe 05.08.2017: Fix the formular to support that use-case -->
<ItemsControl VerticalAlignment="Top" HorizontalAlignment="Left" Margin="120,-22,0,0" ItemsSource="{Binding Source={x:Static core:RGBSurface.Instance}, Path=Devices}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource StyleTextBlockFormular}">
<TextBlock.Text>
<MultiBinding StringFormat="> {0} {1} ({2})">
<Binding Path="DeviceInfo.Manufacturer" />
<Binding Path="DeviceInfo.Model" />
<Binding Path="DeviceInfo.DeviceType" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<StackPanel Orientation="Vertical">
<Border HorizontalAlignment="Left" Width="111">
<Label HorizontalAlignment="Right"
Content="Background" />
</Border>
<controls:GradientEditor Margin="120,-18,0,0"
Gradient="{Binding Source={x:Static keyboardAudioVisualizer:ApplicationManager.Instance}, Path=Settings.Background}"
ToolTip="Defines the gradient used as the background. Use transparency to create some kind of blur. Usage:&#x0a; Left click inside the preview to add a new stop.&#x0a; Left-click stop to change the color or move it.&#x0a; Right-click stop to remove it.&#x0a;" />
</StackPanel>
</GroupBox>
<GroupBox Margin="0,8,0,0" DockPanel.Dock="Top">
<StackPanel Orientation="Vertical">
<Border HorizontalAlignment="Left" Width="111">
<Label HorizontalAlignment="Right"
Content="Devices" />
</Border>
<ItemsControl VerticalAlignment="Top" HorizontalAlignment="Left" Margin="120,-18,0,0" ItemsSource="{Binding Source={x:Static core:RGBSurface.Instance}, Path=Devices}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource StyleTextBlockForm}">
<TextBlock.Text>
<MultiBinding StringFormat="> {0} {1} ({2})">
<Binding Path="DeviceInfo.Manufacturer" />
<Binding Path="DeviceInfo.Model" />
<Binding Path="DeviceInfo.DeviceType" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</GroupBox>
</DockPanel>
</AdornerDecorator>
</TabItem>
</TabControl>

View File

@ -1,9 +1,16 @@
using KeyboardAudioVisualizer.Controls;
using System;
using KeyboardAudioVisualizer.Controls;
namespace KeyboardAudioVisualizer.UI
{
public partial class ConfigurationWindow : BlurredDecorationWindow
{
public ConfigurationWindow() => InitializeComponent();
//DarthAffe 07.02.2018: This prevents the applicaiton from not shutting down and crashing afterwards if 'close' is selected in the taskbar-context-menu
private void ConfigurationWindow_OnClosed(object sender, EventArgs e)
{
ApplicationManager.Instance.ExitCommand.Execute(null);
}
}
}

View File

@ -25,7 +25,9 @@
</Style>
<DataTemplate DataType="{x:Type visualizationProvider:BeatVisualizationProvider}">
<visualization:BeatVisualizer Style="{StaticResource StyleBeatVisualizer}" VisualizationProvider="{Binding}" />
<visualization:BeatVisualizer Style="{StaticResource StyleBeatVisualizer}"
VisualizationProvider="{Binding}"
VisualizationIndex="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
</DataTemplate>
</styles:CachedResourceDictionary>

View File

@ -4,14 +4,20 @@ using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider;
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
namespace KeyboardAudioVisualizer.UI.Visualization
{
public class BeatVisualizer : Control
{
#region Properties & Fields
private LinearGradient _gradient;
#endregion
#region DependencyProperties
// ReSharper disable InconsistentNaming
@ -24,6 +30,15 @@ namespace KeyboardAudioVisualizer.UI.Visualization
set => SetValue(VisualizationProviderProperty, value);
}
public static readonly DependencyProperty VisualizationIndexProperty = DependencyProperty.Register(
"VisualizationIndex", typeof(VisualizationIndex?), typeof(BeatVisualizer), new PropertyMetadata(null, VisualizationIndexChanged));
public VisualizationIndex? VisualizationIndex
{
get => (VisualizationIndex?)GetValue(VisualizationIndexProperty);
set => SetValue(VisualizationIndexProperty, value);
}
public static readonly DependencyProperty BrushProperty = DependencyProperty.Register(
"Brush", typeof(Brush), typeof(BeatVisualizer), new PropertyMetadata(default(Brush)));
@ -52,7 +67,7 @@ namespace KeyboardAudioVisualizer.UI.Visualization
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
@ -75,6 +90,37 @@ namespace KeyboardAudioVisualizer.UI.Visualization
}
}
private static void VisualizationIndexChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is BeatVisualizer visualizer)) return;
visualizer.UpdateGradient();
}
private void UpdateGradient()
{
void GradientChanged(object sender, EventArgs args) => UpdateColor();
if (_gradient != null)
_gradient.GradientChanged -= GradientChanged;
_gradient = VisualizationIndex.HasValue ? ApplicationManager.Instance.Settings[VisualizationIndex.Value].Gradient : null;
if (_gradient != null)
_gradient.GradientChanged += GradientChanged;
UpdateColor();
}
private void UpdateColor()
{
if (_gradient == null) return;
GradientStopCollection gradientStops = new GradientStopCollection();
foreach (RGB.NET.Brushes.Gradients.GradientStop stop in _gradient.GradientStops)
gradientStops.Add(new System.Windows.Media.GradientStop(System.Windows.Media.Color.FromArgb(stop.Color.GetA(), stop.Color.GetR(), stop.Color.GetG(), stop.Color.GetB()), stop.Offset));
Brush = new LinearGradientBrush(gradientStops, new System.Windows.Point(0, 0.5), new System.Windows.Point(1, 0.5));
}
#endregion
}
}

View File

@ -31,8 +31,11 @@
<DataTemplate DataType="{x:Type visualizationProvider:FrequencyBarsVisualizationProvider}">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<visualization:FrequencyBarsVisualizer Style="{StaticResource StyleFrequencyBarsVisualizer}" VisualizationProvider="{Binding}" />
<visualization:EqualizerVisualizer Style="{StaticResource StyleEqualizerVisualizer}" Equalizer="{Binding Equalizer}" />
<visualization:FrequencyBarsVisualizer Style="{StaticResource StyleFrequencyBarsVisualizer}"
VisualizationProvider="{Binding}"
VisualizationIndex="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
<visualization:EqualizerVisualizer Style="{StaticResource StyleEqualizerVisualizer}"
Equalizer="{Binding Equalizer}" />
</Grid>
</DataTemplate>

View File

@ -5,6 +5,7 @@ using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using KeyboardAudioVisualizer.AudioProcessing.VisualizationProvider;
using KeyboardAudioVisualizer.Helper;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Color = System.Windows.Media.Color;
@ -27,12 +28,22 @@ namespace KeyboardAudioVisualizer.UI.Visualization
get => (IVisualizationProvider)GetValue(VisualizationProviderProperty);
set => SetValue(VisualizationProviderProperty, value);
}
public static readonly DependencyProperty VisualizationIndexProperty = DependencyProperty.Register(
"VisualizationIndex", typeof(VisualizationIndex?), typeof(FrequencyBarsVisualizer), new PropertyMetadata(null, VisualizationIndexChanged));
public VisualizationIndex? VisualizationIndex
{
get => (VisualizationIndex?)GetValue(VisualizationIndexProperty);
set => SetValue(VisualizationIndexProperty, value);
}
// ReSharper restore InconsistentNaming
#endregion
#region Properties & Fields
private IGradient _gradient;
private LinearGradient _gradient;
private Panel _panel;
private Rectangle[] _bars = new Rectangle[0];
@ -44,9 +55,6 @@ namespace KeyboardAudioVisualizer.UI.Visualization
{
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
@ -65,8 +73,7 @@ namespace KeyboardAudioVisualizer.UI.Visualization
private static void VisualizationProviderChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
FrequencyBarsVisualizer visualizer = dependencyObject as FrequencyBarsVisualizer;
if (visualizer == null) return;
if (!(dependencyObject is FrequencyBarsVisualizer visualizer)) return;
void ConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs args) => visualizer.ConfigurationChanged(args.PropertyName);
@ -77,6 +84,26 @@ namespace KeyboardAudioVisualizer.UI.Visualization
newVisualizationProvider.Configuration.PropertyChanged += ConfigurationOnPropertyChanged;
}
private static void VisualizationIndexChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is FrequencyBarsVisualizer visualizer)) return;
visualizer.UpdateGradient();
}
private void UpdateGradient()
{
void GradientChanged(object sender, EventArgs args) => UpdateColors();
if (_gradient != null)
_gradient.GradientChanged -= GradientChanged;
_gradient = VisualizationIndex.HasValue ? ApplicationManager.Instance.Settings[VisualizationIndex.Value].Gradient : null;
if (_gradient != null)
_gradient.GradientChanged += GradientChanged;
UpdateColors();
}
private void ConfigurationChanged(string changedPropertyName)
{
if ((changedPropertyName == null) || (changedPropertyName == nameof(FrequencyBarsVisualizationProviderConfiguration.Bars)))
@ -119,10 +146,12 @@ namespace KeyboardAudioVisualizer.UI.Visualization
private void UpdateColors()
{
if (_gradient == null) return;
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));
_bars[i].Fill = new SolidColorBrush(Color.FromRgb(color.GetR(), color.GetG(), color.GetB()));
}
}

View File

@ -63,7 +63,9 @@
</Style>
<DataTemplate DataType="{x:Type visualizationProvider:LevelVisualizationProvider}">
<visualization:LevelVisualizer Style="{StaticResource StyleLevelVisualizer}" VisualizationProvider="{Binding}" />
<visualization:LevelVisualizer Style="{StaticResource StyleLevelVisualizer}"
VisualizationProvider="{Binding}"
VisualizationIndex="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
</DataTemplate>
</styles:CachedResourceDictionary>

View File

@ -1,17 +1,27 @@
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 KeyboardAudioVisualizer.Helper;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using Color = System.Windows.Media.Color;
using GradientStop = RGB.NET.Brushes.Gradients.GradientStop;
using Point = System.Windows.Point;
namespace KeyboardAudioVisualizer.UI.Visualization
{
public class LevelVisualizer : Control
{
#region Properties & Fields
private LinearGradient _gradient;
#endregion
#region DependencyProperties
// ReSharper disable InconsistentNaming
@ -24,6 +34,15 @@ namespace KeyboardAudioVisualizer.UI.Visualization
set => SetValue(VisualizationProviderProperty, value);
}
public static readonly DependencyProperty VisualizationIndexProperty = DependencyProperty.Register(
"VisualizationIndex", typeof(VisualizationIndex?), typeof(LevelVisualizer), new PropertyMetadata(null, VisualizationIndexChanged));
public VisualizationIndex? VisualizationIndex
{
get => (VisualizationIndex?)GetValue(VisualizationIndexProperty);
set => SetValue(VisualizationIndexProperty, value);
}
public static readonly DependencyProperty BrushLeftProperty = DependencyProperty.Register(
"BrushLeft", typeof(Brush), typeof(LevelVisualizer), new PropertyMetadata(default(Brush)));
@ -68,10 +87,6 @@ namespace KeyboardAudioVisualizer.UI.Visualization
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
@ -92,6 +107,38 @@ namespace KeyboardAudioVisualizer.UI.Visualization
SizeRight = horizontalSizeRight;
}
private void SetBrushes()
{
if (_gradient == null) return;
GradientStopCollection gradientStops = new GradientStopCollection();
foreach (GradientStop stop in _gradient.GradientStops)
gradientStops.Add(new System.Windows.Media.GradientStop(Color.FromArgb(stop.Color.GetA(), stop.Color.GetR(), stop.Color.GetG(), stop.Color.GetB()), stop.Offset));
BrushLeft = new LinearGradientBrush(gradientStops, new Point(1, 0.5), new Point(0, 0.5));
BrushRight = new LinearGradientBrush(gradientStops, new Point(0, 0.5), new Point(1, 0.5));
}
private static void VisualizationIndexChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is LevelVisualizer visualizer)) return;
visualizer.UpdateGradient();
}
private void UpdateGradient()
{
void GradientChanged(object sender, EventArgs args) => SetBrushes();
if (_gradient != null)
_gradient.GradientChanged -= GradientChanged;
_gradient = VisualizationIndex.HasValue ? ApplicationManager.Instance.Settings[VisualizationIndex.Value].Gradient : null;
if (_gradient != null)
_gradient.GradientChanged += GradientChanged;
SetBrushes();
}
#endregion
}
}

View File

@ -1,16 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CSCore" version="1.2.1.1" targetFramework="net461" />
<package id="CSCore" version="1.2.1.2" targetFramework="net461" />
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.8" targetFramework="net461" />
<package id="MathNet.Numerics" version="3.20.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="RGB.NET.Brushes" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Core" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Devices.CoolerMaster" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Devices.Corsair" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Devices.Logitech" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Devices.Novation" version="1.0.0" targetFramework="net461" />
<package id="RGB.NET.Groups" version="1.0.0" targetFramework="net461" />
<package id="Sanford.Multimedia.Midi" version="6.4.1" targetFramework="net461" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
<package id="HidSharp" version="2.0.5" targetFramework="net461" />
<package id="MathNet.Numerics" version="4.7.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net461" />
<package id="RGB.NET.Brushes" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Core" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Decorators" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.Asus" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.CoolerMaster" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.Corsair" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.Logitech" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.Novation" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.Razer" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Devices.SteelSeries" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Groups" version="0.1.31" targetFramework="net461" />
<package id="RGB.NET.Resources.Asus" version="0.3.0" targetFramework="net461" />
<package id="RGB.NET.Resources.CoolerMaster" version="0.2.0" targetFramework="net461" />
<package id="RGB.NET.Resources.Corsair" version="0.3.0.234" targetFramework="net461" />
<package id="RGB.NET.Resources.Logitech" version="0.3.0" targetFramework="net461" />
<package id="RGB.NET.Resources.Novation" version="0.1.0" targetFramework="net461" />
<package id="RGB.NET.Resources.Razer" version="0.3.2.4" targetFramework="net461" />
<package id="Sanford.Multimedia.Midi" version="6.6.0" targetFramework="net461" />
<package id="Sanford.Multimedia.Midi.Standard" version="6.6.0" targetFramework="net461" />
<package id="System.Management" version="4.5.0" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
</packages>

12
NuGet.Config Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="RGB.NET" value="http://nuget.arge.be/v3/index.json" />
</packageSources>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
</configuration>

View File

@ -1,3 +1,7 @@
This software is no longer actively developed.
Consider checking out [Artemis](https://github.com/Artemis-RGB/Artemis) for a even more feature rich replacement.
# KeyboardAudioVisualizer
It's colorful - I like it!
@ -36,7 +40,7 @@ It's colorful - I like it!
- **Gamma:** The correction value used for gamma-grouping (disabled if any other grouping is selected). High values lead to a stronger compression of high frequencies. _(default: 2)_
- **Reference:** The reference value used to calculate the power of each bar. Adjust this to your audio volume. Low volume -> low reference, high volume -> higher reference. _(default: 90)_
- **Smoothing:** Smooths the graph to prevent flickering. Low values will cause a hectic fast plot, high values a slow one without peaks. _(default: 3)_
- **Emphasize:** Emphasizes peaks. The higher the value, the bigger the difference between a "loud-bar" and a "quite-bar". _(default: 0.5)_
- **Emphasize:** Emphasizes peaks. The higher the value, the bigger the difference between a "loud-bar" and a "quiet-bar". _(default: 0.5)_
**Equalizer**
Allows to finetune the graph by slective increasing/decresing the value.