diff --git a/Artemis/Artemis.sln b/Artemis/Artemis.sln new file mode 100644 index 000000000..9566a2c74 --- /dev/null +++ b/Artemis/Artemis.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Artemis/Artemis/App.config b/Artemis/Artemis/App.config new file mode 100644 index 000000000..ab387ef0f --- /dev/null +++ b/Artemis/Artemis/App.config @@ -0,0 +1,102 @@ + + + + + +
+
+
+
+
+ + + + + + + + + 4 + + + 21 + + + 1 + + + 3 + + + #FF0000FF + + + #FF1E90FF + + + + + False + + + #FFFF5000 + + + #FFFF0000 + + + + + TypeWave + + + + + True + + + #FFFF0000 + + + True + + + 20 + + + 500 + + + 4 + + + + + TypeWave + + + Logitech G910 Orion Spark RGB + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/App.xaml b/Artemis/Artemis/App.xaml new file mode 100644 index 000000000..8b9f0d35e --- /dev/null +++ b/Artemis/Artemis/App.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/App.xaml.cs b/Artemis/Artemis/App.xaml.cs new file mode 100644 index 000000000..5f252eeb7 --- /dev/null +++ b/Artemis/Artemis/App.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows; + +namespace Artemis +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/AppBootStrapper.cs b/Artemis/Artemis/AppBootStrapper.cs new file mode 100644 index 000000000..a0ca2e72f --- /dev/null +++ b/Artemis/Artemis/AppBootStrapper.cs @@ -0,0 +1,19 @@ +using System.Windows; +using Artemis.ViewModels; +using Caliburn.Micro; + +namespace Artemis +{ + public class AppBootstrapper : BootstrapperBase + { + public AppBootstrapper() + { + Initialize(); + } + + protected override void OnStartup(object sender, StartupEventArgs e) + { + DisplayRootViewFor(); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj new file mode 100644 index 000000000..ba59376e9 --- /dev/null +++ b/Artemis/Artemis/Artemis.csproj @@ -0,0 +1,396 @@ + + + + + Debug + AnyCPU + {ED9997A2-E54C-4E9F-9350-62BE672C3ABE} + WinExe + Properties + Artemis + Artemis + v4.5.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + + + + + + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 2 + 1.0.0.%2a + false + true + true + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + EAC088BE27A2DE790AE6F37A020409F4A1B5EC0E + + + Artemis_TemporaryKey.pfx + + + true + + + false + + + + ..\packages\Caliburn.Micro.Core.2.0.2\lib\net45\Caliburn.Micro.dll + True + + + ..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll + True + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net45\MahApps.Metro.dll + True + + + E:\Downloads\Chome Downloads\MyMemory-x64.dll + + + ..\packages\NAudio.1.7.3\lib\net35\NAudio.dll + True + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\Open.WinKeyboardHook.1.0.10.0\lib\net45\Open.WinKeyboardHook.dll + True + + + + + + + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net45\System.Windows.Interactivity.dll + True + + + + + + + + + 4.0 + + + + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.AvalonDock.dll + True + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll + True + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll + True + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll + True + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.DataGrid.dll + True + + + ..\packages\Extended.Wpf.Toolkit.2.5\lib\net40\Xceed.Wpf.Toolkit.dll + True + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + AudioVisualization.settings + + + True + True + General.settings + + + True + True + RocketLeague.settings + + + True + True + TypeWave.settings + + + + + + + + + + + + + + + + + + + + + + + + + + + EffectsView.xaml + + + DebugEffectView.xaml + + + AudioVisualizerView.xaml + + + TypeHoleView.xaml + + + TypeWaveView.xaml + + + GamesView.xaml + + + CounterStrikeView.xaml + + + Dota2View.xaml + + + RocketLeagueView.xaml + + + Witcher3View.xaml + + + OverlaysView.xaml + + + VolumeDisplayView.xaml + + + ShellView.xaml + + + + + Code + + + True + True + Resources.resx + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + SettingsSingleFileGenerator + AudioVisualization.Designer.cs + + + SettingsSingleFileGenerator + General.Designer.cs + + + SettingsSingleFileGenerator + RocketLeague.Designer.cs + + + SettingsSingleFileGenerator + TypeWave.Designer.cs + + + + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + PreserveNewest + + + + + + + False + Microsoft .NET Framework 4.5.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Events/ChangeActiveEffect.cs b/Artemis/Artemis/Events/ChangeActiveEffect.cs new file mode 100644 index 000000000..47addd474 --- /dev/null +++ b/Artemis/Artemis/Events/ChangeActiveEffect.cs @@ -0,0 +1,12 @@ +namespace Artemis.Events +{ + public class ChangeActiveEffect + { + public ChangeActiveEffect(string activeEffect) + { + ActiveEffect = activeEffect; + } + + public string ActiveEffect { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Events/ChangeBitmap.cs b/Artemis/Artemis/Events/ChangeBitmap.cs new file mode 100644 index 000000000..cdae57658 --- /dev/null +++ b/Artemis/Artemis/Events/ChangeBitmap.cs @@ -0,0 +1,19 @@ +using System.Drawing; + +namespace Artemis.Events +{ + public class ChangeBitmap + { + public ChangeBitmap(Bitmap bitmap) + { + Bitmap = bitmap; + } + + public Bitmap Bitmap { get; private set; } + + public void ChangeTextMessage(Bitmap bitmap) + { + Bitmap = bitmap; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Corsair/K70.cs b/Artemis/Artemis/KeyboardProviders/Corsair/K70.cs new file mode 100644 index 000000000..f507409bc --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Corsair/K70.cs @@ -0,0 +1,24 @@ +using System.Drawing; + +namespace Artemis.KeyboardProviders.Corsair +{ + internal class K95 : KeyboardProvider + { + public K95() + { + Name = "Corsair Gaming K95 RGB"; + } + + public override void Enable() + { + } + + public override void Disable() + { + } + + public override void DrawBitmap(Bitmap bitmap) + { + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Corsair/K95.cs b/Artemis/Artemis/KeyboardProviders/Corsair/K95.cs new file mode 100644 index 000000000..6179b973c --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Corsair/K95.cs @@ -0,0 +1,25 @@ +using System.Drawing; + +namespace Artemis.KeyboardProviders.Corsair +{ + internal class K70 : KeyboardProvider + { + public K70() + { + Name = "Corsair Gaming K70 RGB"; + } + + public override void Enable() + { + } + + public override void Disable() + { + } + + public override void DrawBitmap(Bitmap bitmap) + { + // TODO: Convert bitmap to something tasty for CUE.NET + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs b/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs new file mode 100644 index 000000000..5158a0fc9 --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs @@ -0,0 +1,13 @@ +using System.Drawing; + +namespace Artemis.KeyboardProviders +{ + public abstract class KeyboardProvider + { + public string Name { get; set; } + + public abstract void Enable(); + public abstract void Disable(); + public abstract void DrawBitmap(Bitmap bitmap); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs new file mode 100644 index 000000000..1f2ad0ab2 --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs @@ -0,0 +1,34 @@ +using System.Drawing; +using System.Threading; +using Artemis.KeyboardProviders.Logitech.Utilities; + +namespace Artemis.KeyboardProviders.Logitech +{ + internal class Orion : KeyboardProvider + { + public Orion() + { + Name = "Logitech G910 Orion Spark RGB"; + } + + public override void Enable() + { + // Initialize the SDK + LogitechGSDK.LogiLedInit(); + Thread.Sleep(200); + LogitechGSDK.LogiLedSaveCurrentLighting(); + } + + public override void Disable() + { + // Shutdown the SDK + LogitechGSDK.LogiLedRestoreLighting(); + LogitechGSDK.LogiLedShutdown(); + } + + public override void DrawBitmap(Bitmap bitmap) + { + LogitechGSDK.LogiLedSetLightingFromBitmap(OrionUtilities.BitmapToByteArray(bitmap)); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs new file mode 100644 index 000000000..6c341892f --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Windows.Forms; +using Artemis.Utilities.Keyboard; + +namespace Artemis.KeyboardProviders.Logitech.Utilities +{ + public static class KeyMap + { + static KeyMap() + { + // There are several keyboard layouts + // TODO: Implemented more layouts and an option to select them + UsEnglishOrionKeys = new List + { + // Row 1 + new Key(Keys.Escape, 0, 0), + new Key(Keys.F1, 1, 0), + new Key(Keys.F2, 2, 0), + new Key(Keys.F3, 3, 0), + new Key(Keys.F4, 4, 0), + new Key(Keys.F5, 5, 0), + new Key(Keys.F6, 6, 0), + new Key(Keys.F7, 7, 0), + new Key(Keys.F8, 8, 0), + new Key(Keys.F9, 9, 0), + new Key(Keys.F10, 10, 0), + new Key(Keys.F11, 11, 0), + new Key(Keys.F12, 12, 0), + new Key(Keys.PrintScreen, 13, 0), + new Key(Keys.Scroll, 14, 0), + new Key(Keys.Pause, 15, 0), + + // Row 2 + new Key(Keys.Oemtilde, 0, 1), + new Key(Keys.D1, 1, 1), + new Key(Keys.D2, 2, 1), + new Key(Keys.D3, 3, 1), + new Key(Keys.D4, 4, 1), + new Key(Keys.D5, 5, 1), + new Key(Keys.D6, 6, 1), + new Key(Keys.D7, 7, 1), + new Key(Keys.D8, 8, 1), + new Key(Keys.D9, 9, 1), + new Key(Keys.D0, 10, 1), + new Key(Keys.OemMinus, 11, 1), + new Key(Keys.Oemplus, 12, 1), + new Key(Keys.Back, 13, 1), + new Key(Keys.Insert, 14, 1), + new Key(Keys.Home, 15, 1), + new Key(Keys.PageUp, 16, 1), + new Key(Keys.NumLock, 17, 1), + new Key(Keys.Divide, 18, 1), + new Key(Keys.Multiply, 19, 1), + new Key(Keys.Subtract, 20, 1), + + // Row 3 + new Key(Keys.Tab, 0, 2), + new Key(Keys.Q, 1, 2), + new Key(Keys.W, 2, 2), + new Key(Keys.E, 3, 2), + new Key(Keys.R, 4, 2), + new Key(Keys.T, 5, 2), + new Key(Keys.Y, 6, 2), + new Key(Keys.U, 7, 2), + new Key(Keys.I, 8, 2), + new Key(Keys.O, 9, 2), + new Key(Keys.P, 10, 2), + new Key(Keys.OemOpenBrackets, 11, 2), + new Key(Keys.Oem6, 12, 2), + new Key(Keys.Delete, 14, 2), + new Key(Keys.End, 15, 2), + new Key(Keys.Next, 16, 2), + new Key(Keys.NumPad7, 17, 2), + new Key(Keys.NumPad8, 18, 2), + new Key(Keys.NumPad9, 19, 2), + new Key(Keys.Add, 20, 2), + + // Row 4 + new Key(Keys.Capital, 0, 3), + new Key(Keys.A, 1, 3), + new Key(Keys.S, 2, 3), + new Key(Keys.D, 3, 3), + new Key(Keys.F, 4, 3), + new Key(Keys.G, 5, 3), + new Key(Keys.H, 6, 3), + new Key(Keys.J, 7, 3), + new Key(Keys.K, 8, 3), + new Key(Keys.L, 9, 3), + new Key(Keys.Oem1, 10, 3), + new Key(Keys.Oem7, 11, 3), + new Key(Keys.Oem5, 12, 3), + new Key(Keys.Return, 13, 3), + new Key(Keys.NumPad4, 17, 3), + new Key(Keys.NumPad5, 18, 3), + new Key(Keys.NumPad6, 19, 3), + + // Row 5 + new Key(Keys.LShiftKey, 1, 4), + new Key(Keys.OemBackslash, 2, 4), + new Key(Keys.Z, 2, 4), + new Key(Keys.X, 3, 4), + new Key(Keys.C, 4, 4), + new Key(Keys.V, 5, 4), + new Key(Keys.B, 6, 4), + new Key(Keys.N, 7, 4), + new Key(Keys.M, 8, 4), + new Key(Keys.Oemcomma, 9, 4), + new Key(Keys.OemPeriod, 10, 4), + new Key(Keys.OemQuestion, 11, 4), + new Key(Keys.RShiftKey, 13, 4), + new Key(Keys.Up, 15, 4), + new Key(Keys.NumPad1, 17, 4), + new Key(Keys.NumPad2, 18, 4), + new Key(Keys.NumPad3, 19, 4), + // Both returns return "Return" (Yes...) + // new OrionKey(System.Windows.Forms.Keys.Return, 20, 4), + + // Row 6 + new Key(Keys.LControlKey, 0, 5), + new Key(Keys.LWin, 1, 5), + new Key(Keys.LMenu, 2, 5), + new Key(Keys.Space, 5, 5), + new Key(Keys.RMenu, 11, 5), + new Key(Keys.RWin, 12, 5), + new Key(Keys.Apps, 13, 5), + new Key(Keys.RControlKey, 14, 5), + new Key(Keys.Left, 15, 5), + new Key(Keys.Down, 16, 5), + new Key(Keys.Right, 17, 5), + new Key(Keys.NumPad0, 18, 5), + new Key(Keys.Decimal, 19, 5) + }; + } + + public static List UsEnglishOrionKeys { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs new file mode 100644 index 000000000..57f1ec167 --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs @@ -0,0 +1,111 @@ +namespace Artemis.KeyboardProviders.Logitech.Utilities +{ + public enum KeyboardNames + { + ESC = 0x01, + F1 = 0x3b, + F2 = 0x3c, + F3 = 0x3d, + F4 = 0x3e, + F5 = 0x3f, + F6 = 0x40, + F7 = 0x41, + F8 = 0x42, + F9 = 0x43, + F10 = 0x44, + F11 = 0x57, + F12 = 0x58, + PRINT_SCREEN = 0x137, + SCROLL_LOCK = 0x46, + PAUSE_BREAK = 0x45, + TILDE = 0x29, + ONE = 0x02, + TWO = 0x03, + THREE = 0x04, + FOUR = 0x05, + FIVE = 0x06, + SIX = 0x07, + SEVEN = 0x08, + EIGHT = 0x09, + NINE = 0x0A, + ZERO = 0x0B, + MINUS = 0x0C, + EQUALS = 0x0D, + BACKSPACE = 0x0E, + INSERT = 0x152, + HOME = 0x147, + PAGE_UP = 0x149, + NUM_LOCK = 0x145, + NUM_SLASH = 0x135, + NUM_ASTERISK = 0x37, + NUM_MINUS = 0x4A, + TAB = 0x0F, + Q = 0x10, + W = 0x11, + E = 0x12, + R = 0x13, + T = 0x14, + Y = 0x15, + U = 0x16, + I = 0x17, + O = 0x18, + P = 0x19, + OPEN_BRACKET = 0x1A, + CLOSE_BRACKET = 0x1B, + BACKSLASH = 0x2B, + KEYBOARD_DELETE = 0x153, + END = 0x14F, + PAGE_DOWN = 0x151, + NUM_SEVEN = 0x47, + NUM_EIGHT = 0x48, + NUM_NINE = 0x49, + NUM_PLUS = 0x4E, + CAPS_LOCK = 0x3A, + A = 0x1E, + S = 0x1F, + D = 0x20, + F = 0x21, + G = 0x22, + H = 0x23, + J = 0x24, + K = 0x25, + L = 0x26, + SEMICOLON = 0x27, + APOSTROPHE = 0x28, + ENTER = 0x1C, + NUM_FOUR = 0x4B, + NUM_FIVE = 0x4C, + NUM_SIX = 0x4D, + LEFT_SHIFT = 0x2A, + Z = 0x2C, + X = 0x2D, + C = 0x2E, + V = 0x2F, + B = 0x30, + N = 0x31, + M = 0x32, + COMMA = 0x33, + PERIOD = 0x34, + FORWARD_SLASH = 0x35, + RIGHT_SHIFT = 0x36, + ARROW_UP = 0x148, + NUM_ONE = 0x4F, + NUM_TWO = 0x50, + NUM_THREE = 0x51, + NUM_ENTER = 0x11C, + LEFT_CONTROL = 0x1D, + LEFT_WINDOWS = 0x15B, + LEFT_ALT = 0x38, + SPACE = 0x39, + RIGHT_ALT = 0x138, + RIGHT_WINDOWS = 0x15C, + APPLICATION_SELECT = 0x15D, + RIGHT_CONTROL = 0x11D, + ARROW_LEFT = 0x14B, + ARROW_DOWN = 0x150, + ARROW_RIGHT = 0x14D, + NUM_ZERO = 0x52, + NUM_PERIOD = 0x53, + TEST = 0x1 + }; +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs new file mode 100644 index 000000000..71a47313d --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs @@ -0,0 +1,95 @@ +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Artemis.KeyboardProviders.Logitech.Utilities +{ + public class LogitechGSDK + { + //LED SDK + private const int LOGI_DEVICETYPE_MONOCHROME_ORD = 0; + private const int LOGI_DEVICETYPE_RGB_ORD = 1; + private const int LOGI_DEVICETYPE_PERKEY_RGB_ORD = 2; + + public const int LOGI_DEVICETYPE_MONOCHROME = (1 << LOGI_DEVICETYPE_MONOCHROME_ORD); + public const int LOGI_DEVICETYPE_RGB = (1 << LOGI_DEVICETYPE_RGB_ORD); + public const int LOGI_DEVICETYPE_PERKEY_RGB = (1 << LOGI_DEVICETYPE_PERKEY_RGB_ORD); + public const int LOGI_LED_BITMAP_WIDTH = 21; + public const int LOGI_LED_BITMAP_HEIGHT = 6; + public const int LOGI_LED_BITMAP_BYTES_PER_KEY = 4; + + public const int LOGI_LED_BITMAP_SIZE = + LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY; + + public const int LOGI_LED_DURATION_INFINITE = 0; + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedInit(); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetTargetDevice(int targetDevice); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSaveCurrentLighting(); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedRestoreLighting(); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedFlashLighting(int redPercentage, int greenPercentage, int bluePercentage, + int milliSecondsDuration, int milliSecondsInterval); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedPulseLighting(int redPercentage, int greenPercentage, int bluePercentage, + int milliSecondsDuration, int milliSecondsInterval); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedStopEffects(); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLightingFromBitmap(byte[] bitmap); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLightingForKeyWithScanCode(int keyCode, int redPercentage, + int greenPercentage, int bluePercentage); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLightingForKeyWithHidCode(int keyCode, int redPercentage, + int greenPercentage, int bluePercentage); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLightingForKeyWithQuartzCode(int keyCode, int redPercentage, + int greenPercentage, int bluePercentage); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSetLightingForKeyWithKeyName(KeyboardNames keyCode, int redPercentage, + int greenPercentage, int bluePercentage); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedSaveLightingForKey(KeyboardNames keyName); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedRestoreLightingForKey(KeyboardNames keyName); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedFlashSingleKey(KeyboardNames keyName, int redPercentage, int greenPercentage, + int bluePercentage, int msDuration, int msInterval); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedPulseSingleKey(KeyboardNames keyName, int startRedPercentage, + int startGreenPercentage, int startBluePercentage, int finishRedPercentage, int finishGreenPercentage, + int finishBluePercentage, int msDuration, bool isInfinite); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool LogiLedStopEffectsOnKey(KeyboardNames keyName); + + [DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)] + public static extern void LogiLedShutdown(); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs new file mode 100644 index 000000000..41682dd9b --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs @@ -0,0 +1,60 @@ +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + +namespace Artemis.KeyboardProviders.Logitech.Utilities +{ + public static class OrionUtilities + { + public static byte[] BitmapToByteArray(Bitmap b) + { + if (b.Width > 21 || b.Height > 6) + b = ResizeImage(b, 21, 6); + + var rect = new Rectangle(0, 0, b.Width, b.Height); + var bitmapData = b.LockBits(rect, ImageLockMode.ReadWrite, b.PixelFormat); + + var depth = Image.GetPixelFormatSize(b.PixelFormat); + var step = depth/8; + var pixels = new byte[(21*6)*step]; + var iptr = bitmapData.Scan0; + + // Copy data from pointer to array + Marshal.Copy(iptr, pixels, 0, pixels.Length); + return pixels; + } + + /// + /// Resize the image to the specified width and height. + /// + /// The image to resize. + /// The width to resize to. + /// The height to resize to. + /// The resized image. + public static Bitmap ResizeImage(Image image, int width, int height) + { + var destRect = new Rectangle(0, 0, width, height); + var destImage = new Bitmap(width, height); + + destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + + using (var graphics = Graphics.FromImage(destImage)) + { + graphics.CompositingMode = CompositingMode.SourceCopy; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + using (var wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); + } + } + + return destImage; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs b/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs new file mode 100644 index 000000000..29c175ef2 --- /dev/null +++ b/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Artemis.KeyboardProviders.Corsair; +using Artemis.KeyboardProviders.Logitech; + +namespace Artemis.KeyboardProviders +{ + public static class ProviderHelper + { + public static List GetKeyboardProviders() + { + return new List + { + new Orion(), + new K70(), + new K95() + }; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/LogitechLedEnginesWrapper.dll b/Artemis/Artemis/LogitechLedEnginesWrapper.dll new file mode 100644 index 000000000..d28ee9e94 Binary files /dev/null and b/Artemis/Artemis/LogitechLedEnginesWrapper.dll differ diff --git a/Artemis/Artemis/MainWindow.xaml b/Artemis/Artemis/MainWindow.xaml new file mode 100644 index 000000000..57671ae01 --- /dev/null +++ b/Artemis/Artemis/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Artemis/Artemis/MainWindow.xaml.cs b/Artemis/Artemis/MainWindow.xaml.cs new file mode 100644 index 000000000..2598c1727 --- /dev/null +++ b/Artemis/Artemis/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/Artemis/Artemis/Models/EffectModel.cs b/Artemis/Artemis/Models/EffectModel.cs new file mode 100644 index 000000000..b62edb108 --- /dev/null +++ b/Artemis/Artemis/Models/EffectModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Drawing; + +namespace Artemis.Models +{ + public abstract class EffectModel : IDisposable + { + public string Name; + public abstract void Dispose(); + + // Called on creation + public abstract void Enable(); + + // Called every iteration + public abstract void Update(); + + // Called after every update + public abstract Bitmap GenerateBitmap(); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/EffectSettings.cs b/Artemis/Artemis/Models/EffectSettings.cs new file mode 100644 index 000000000..5595ed92e --- /dev/null +++ b/Artemis/Artemis/Models/EffectSettings.cs @@ -0,0 +1,20 @@ +namespace Artemis.Models +{ + public abstract class EffectSettings + { + /// + /// Loads the settings from the settings file + /// + public abstract void Load(); + + /// + /// Saves the settings to the settings file + /// + public abstract void Save(); + + /// + /// Returns the settings to their default value + /// + public abstract void ToDefault(); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/GameModel.cs b/Artemis/Artemis/Models/GameModel.cs new file mode 100644 index 000000000..6eba9c062 --- /dev/null +++ b/Artemis/Artemis/Models/GameModel.cs @@ -0,0 +1,8 @@ +namespace Artemis.Models +{ + public abstract class GameModel : EffectModel + { + public bool Enabled; + public string ProcessName; + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/MainModel.cs b/Artemis/Artemis/Models/MainModel.cs new file mode 100644 index 000000000..eea2f2674 --- /dev/null +++ b/Artemis/Artemis/Models/MainModel.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Artemis.Events; +using Artemis.KeyboardProviders; +using Artemis.Settings; +using Artemis.Utilities.GameSense; +using Artemis.Utilities.Memory; +using Caliburn.Micro; + +namespace Artemis.Models +{ + public class MainModel + { + private readonly BackgroundWorker _processWorker; + private readonly BackgroundWorker _updateWorker; + + public MainModel(IEventAggregator events) + { + EffectModels = new List(); + KeyboardProviders = ProviderHelper.GetKeyboardProviders(); + GameSenseWebServer = new GameSenseWebServer(); + + Events = events; + Fps = 25; + + _updateWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; + _processWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; + _updateWorker.DoWork += UpdateWorker_DoWork; + _processWorker.DoWork += ProcessWorker_DoWork; + } + + public EffectModel ActiveEffect { get; set; } + public List EffectModels { get; set; } + public KeyboardProvider ActiveKeyboard { get; set; } + public List KeyboardProviders { get; set; } + + public GameSenseWebServer GameSenseWebServer { get; set; } + public IEventAggregator Events { get; set; } + public int Fps { get; set; } + public bool Enabled { get; set; } + + #region Effect methods + + public void StartEffects() + { + LoadLastKeyboard(); + + // Start the webserver + GameSenseWebServer.Start(); + + // Load last non-game effect and enable + LoadLastEffect(); + + // Start the Background Workers + _updateWorker.RunWorkerAsync(); + _processWorker.RunWorkerAsync(); + } + + public void ShutdownEffects() + { + // Stop the Background Worker + _updateWorker.CancelAsync(); + _processWorker.CancelAsync(); + + // Dispose the current active effect + ActiveEffect?.Dispose(); + ActiveEffect = null; + + ActiveKeyboard?.Disable(); + ActiveKeyboard = null; + } + + private void LoadLastKeyboard() + { + var keyboard = KeyboardProviders.FirstOrDefault(k => k.Name == General.Default.LastKeyboard); + ChangeKeyboard(keyboard ?? KeyboardProviders.First(k => k.Name == "Logitech G910 Orion Spark RGB")); + } + + private void ChangeKeyboard(KeyboardProvider keyboardProvider) + { + if (ActiveKeyboard != null && keyboardProvider.Name == ActiveKeyboard.Name) + return; + + ActiveKeyboard?.Disable(); + ActiveKeyboard = keyboardProvider; + ActiveKeyboard.Enable(); + + General.Default.LastKeyboard = ActiveKeyboard.Name; + General.Default.Save(); + } + + private void LoadLastEffect() + { + var effect = EffectModels.FirstOrDefault(e => e.Name == General.Default.LastEffect); + ChangeEffect(effect ?? EffectModels.First(e => e.Name == "TypeWave")); + } + + private void ChangeEffect(EffectModel effectModel) + { + if (effectModel is OverlayModel) + throw new ArgumentException("Can't set an Overlay effect as the active effect"); + + + if (ActiveEffect != null && effectModel.Name == ActiveEffect.Name) + return; + + ActiveEffect?.Dispose(); + ActiveEffect = effectModel; + ActiveEffect.Enable(); + + if (ActiveEffect is GameModel) return; + + // Non-game effects are stored as the new LastEffect. + General.Default.LastEffect = ActiveEffect.Name; + General.Default.Save(); + + // Let the ViewModels know + Events.PublishOnUIThread(new ChangeActiveEffect(ActiveEffect.Name)); + } + + public void EnableEffect(EffectModel effectModel) + { + if (effectModel is GameModel || effectModel is OverlayModel) + return; + + ChangeEffect(effectModel); + } + + public bool IsEnabled(EffectModel effectModel) + { + if (effectModel is GameModel) + return false; + + return General.Default.LastEffect == effectModel.Name; + } + + #endregion Effect methods + + #region Workers + + private void UpdateWorker_DoWork(object sender, DoWorkEventArgs e) + { + var sw = new Stopwatch(); + while (!_updateWorker.CancellationPending) + { + sw.Start(); + + // Update the current effect + ActiveEffect.Update(); + + // Get ActiveEffect's bitmap + var bitmap = ActiveEffect.GenerateBitmap(); + + // Draw enabled overlays on top + foreach ( + var overlayModel in EffectModels.OfType().Where(overlayModel => overlayModel.Enabled)) + { + overlayModel.Update(); + bitmap = bitmap != null ? overlayModel.GenerateBitmap(bitmap) : overlayModel.GenerateBitmap(); + } + + // If it exists, send bitmap to the device + if (bitmap != null && ActiveKeyboard != null) + { + ActiveKeyboard.DrawBitmap(bitmap); + + // debugging + Events.PublishOnUIThread(new ChangeBitmap(bitmap)); + } + + // Sleep according to time left this frame + var sleep = (int) ((1000/Fps) - sw.ElapsedMilliseconds); + if (sleep > 0) + Thread.Sleep(sleep); + sw.Reset(); + } + } + + private void ProcessWorker_DoWork(object sender, DoWorkEventArgs e) + { + while (!_processWorker.CancellationPending) + { + var foundProcess = false; + + // ReSharper disable once LoopCanBePartlyConvertedToQuery + foreach (var effectModel in EffectModels.OfType()) + { + var process = MemoryHelpers.GetProcessIfRunning(effectModel.ProcessName); + if (process == null) + continue; + + ChangeEffect(effectModel); + foundProcess = true; + } + + // If no game process is found, but the active effect still belongs to a game, + // set it to a normal effect + if (!foundProcess && ActiveEffect is GameModel) + LoadLastEffect(); + + Thread.Sleep(1000); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/OverlayModel.cs b/Artemis/Artemis/Models/OverlayModel.cs new file mode 100644 index 000000000..aa1b3479c --- /dev/null +++ b/Artemis/Artemis/Models/OverlayModel.cs @@ -0,0 +1,41 @@ +using System.Drawing; + +namespace Artemis.Models +{ + public abstract class OverlayModel : EffectModel + { + private bool _enabled; + public string ProcessName; + + public bool Enabled + { + get { return _enabled; } + set + { + if (_enabled == value) + return; + + if (value) + Enable(); + else + Dispose(); + _enabled = value; + } + } + + public void SetEnabled(bool enabled) + { + if (Enabled == enabled) + return; + + if (enabled) + Enable(); + else + Dispose(); + + Enabled = enabled; + } + + public abstract Bitmap GenerateBitmap(Bitmap bitmap); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs new file mode 100644 index 000000000..5bb730c61 --- /dev/null +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using Artemis.Models; +using Artemis.Utilities; +using Artemis.Utilities.Audio; +using Artemis.Utilities.Keyboard; +using NAudio.CoreAudioApi; +using NAudio.Wave; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + public class AudioVisualizerModel : EffectModel + { + private const int FftLength = 2048; + private readonly SampleAggregator _sampleAggregator = new SampleAggregator(FftLength); + private bool _generating; + private IWaveIn _waveIn; + + public AudioVisualizerModel(AudioVisualizerSettings settings) + { + Settings = settings; + Name = "Audiovisualizer"; + DeviceIds = new List(); + SpectrumData = new List(); + SoundRectangles = new List(); + Scale = 4; + Lines = 21*Scale; + + // Fill list with device IDs + // Would rather just store a MMDevice object, but seems NAudio won't let me. + var deviceEnum = new MMDeviceEnumerator(); + var devices = deviceEnum.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).ToList(); + foreach (var mmDevice in devices) + { + DeviceIds.Add(mmDevice.ID); + } + + SelectedDeviceId = DeviceIds.FirstOrDefault(); + } + + public int Lines { get; set; } + + public int Scale { get; set; } + + public AudioVisualizerSettings Settings { get; set; } + public List SpectrumData { get; set; } + public List SoundRectangles { get; set; } + + public List DeviceIds { get; set; } + public string SelectedDeviceId { get; set; } + + public override void Dispose() + { + _sampleAggregator.PerformFFT = false; + _sampleAggregator.FftCalculated -= FftCalculated; + + _waveIn.StopRecording(); + _waveIn.DataAvailable -= OnDataAvailable; + _waveIn = null; + } + + public override void Enable() + { + _sampleAggregator.FftCalculated += FftCalculated; + _sampleAggregator.PerformFFT = true; + + _waveIn = new WasapiLoopbackCapture(); + _waveIn.DataAvailable += OnDataAvailable; + _waveIn.StartRecording(); + } + + public override void Update() + { + if (SelectedDeviceId == null) + return; + + var deviceEnum = new MMDeviceEnumerator(); + var devices = deviceEnum.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).ToList(); + var device = devices.FirstOrDefault(d => d.ID == SelectedDeviceId); + + if (device == null) + return; + + // Start filling the model + _generating = true; + + if (SpectrumData == null) + { + _generating = false; + return; + } + + // Clear the rectangle cache on Bars settings change + if (SoundRectangles.Count != Settings.Bars) + SoundRectangles.Clear(); + + // Parse spectrum data + for (var i = 0; i < Settings.Bars; i++) + { + int height; + if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0) + height = 0; + else + height = (int) (Math.Round(SpectrumData[i]/2.55)); + + if (SoundRectangles.Count <= i) + SoundRectangles.Add(new KeyboardRectangle(Scale, 0, 0, 21, 6, + new List + { + ColorHelpers.MediaColorToDrawingColor(Settings.MainColor), + ColorHelpers.MediaColorToDrawingColor(Settings.SecondaryColor) + }, LinearGradientMode.Vertical)); + + // Apply Sensitivity setting + height = height*Settings.Sensitivity; + if (height > SoundRectangles[i].Height) + SoundRectangles[i].Height = height; + else + SoundRectangles[i].Height = SoundRectangles[i].Height - Settings.FadeSpeed; + // Apply Bars setting + SoundRectangles[i].X = (int) Math.Ceiling((double) Lines/Settings.Bars)*i; + SoundRectangles[i].Width = (int) Math.Ceiling((double) Lines/Settings.Bars); + } + _generating = false; + } + + public override Bitmap GenerateBitmap() + { + // Lock the _spectrumData array while busy with it + _generating = true; + + if (SpectrumData == null) + { + _generating = false; + return null; + } + + var bitmap = new Bitmap(21*Scale, 6*Scale); + using (var g = Graphics.FromImage(bitmap)) + { + foreach (var soundRectangle in SoundRectangles) + soundRectangle.Draw(g); + } + _generating = false; + return bitmap; + } + + private void OnDataAvailable(object sender, WaveInEventArgs e) + { + var buffer = e.Buffer; + var bytesRecorded = e.BytesRecorded; + var bufferIncrement = _waveIn.WaveFormat.BlockAlign; + + for (var index = 0; index < bytesRecorded; index += bufferIncrement) + { + var sample32 = BitConverter.ToSingle(buffer, index); + _sampleAggregator.Add(sample32); + } + } + + private void FftCalculated(object sender, FftEventArgs e) + { + if (_generating) + return; + + int x; + var b0 = 0; + + SpectrumData.Clear(); + for (x = 0; x < Lines; x++) + { + float peak = 0; + var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1)); + if (b1 > 2047) + b1 = 2047; + if (b1 <= b0) + b1 = b0 + 1; + for (; b0 < b1; b0++) + { + if (peak < e.Result[1 + b0].X) + peak = e.Result[1 + b0].X; + } + var y = (int) (Math.Sqrt(peak)*3*255 - 4); + if (y > 255) + y = 255; + if (y < 0) + y = 0; + SpectrumData.Add((byte) y); + } + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs new file mode 100644 index 000000000..98778c6d4 --- /dev/null +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs @@ -0,0 +1,53 @@ +using System.Windows.Media; +using Artemis.Models; +using Artemis.Settings; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + public class AudioVisualizerSettings : EffectSettings + { + public AudioVisualizerSettings() + { + Load(); + } + + public int Sensitivity { get; set; } + public int Bars { get; set; } + public int Spread { get; set; } + public int FadeSpeed { get; set; } + public Color MainColor { get; set; } + public Color SecondaryColor { get; set; } + + public override sealed void Load() + { + Sensitivity = AudioVisualization.Default.Sensitivity; + Bars = AudioVisualization.Default.Bars; + Spread = AudioVisualization.Default.Spread; + FadeSpeed = AudioVisualization.Default.FadeSpeed; + MainColor = AudioVisualization.Default.MainColor; + SecondaryColor = AudioVisualization.Default.SecondaryColor; + } + + public override sealed void Save() + { + AudioVisualization.Default.Sensitivity = Sensitivity; + AudioVisualization.Default.Bars = Bars; + AudioVisualization.Default.Spread = Spread; + AudioVisualization.Default.FadeSpeed = FadeSpeed; + AudioVisualization.Default.MainColor = MainColor; + AudioVisualization.Default.SecondaryColor = SecondaryColor; + + AudioVisualization.Default.Save(); + } + + public override sealed void ToDefault() + { + Sensitivity = 4; + Bars = 21; + Spread = 1; + FadeSpeed = 3; + MainColor = Color.FromArgb(255, 0, 0, 255); + SecondaryColor = Color.FromArgb(255, 30, 144, 255); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml new file mode 100644 index 000000000..4eb9412cc --- /dev/null +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +