diff --git a/NuGet/RGB.NET.Devices.Novation.nuspec b/NuGet/RGB.NET.Devices.Novation.nuspec new file mode 100644 index 0000000..afac9ee --- /dev/null +++ b/NuGet/RGB.NET.Devices.Novation.nuspec @@ -0,0 +1,31 @@ + + + + RGB.NET.Devices.Novation + RGB.NET.Devices.Novation + 1.0.0.0 + Darth Affe + Darth Affe + https://github.com/DarthAffe/RGB.NET + https://raw.githubusercontent.com/DarthAffe/RGB.NET/master/LICENSE + true + Novation-Device-Implementations of RGB.NET + + Novation-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals + Copyright © Wyrez 2017 + en-US + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Core/Devices/RGBDeviceType.cs b/RGB.NET.Core/Devices/RGBDeviceType.cs index 7345bab..c02be47 100644 --- a/RGB.NET.Core/Devices/RGBDeviceType.cs +++ b/RGB.NET.Core/Devices/RGBDeviceType.cs @@ -33,6 +33,11 @@ /// /// Represents a LED-stipe. /// - LedStripe + LedStripe, + + /// + /// Represents a LED-matrix + /// + LedMatrix } } diff --git a/RGB.NET.Devices.Novation/Attributes/ColorCapabilityAttribute.cs b/RGB.NET.Devices.Novation/Attributes/ColorCapabilityAttribute.cs new file mode 100644 index 0000000..d02aa60 --- /dev/null +++ b/RGB.NET.Devices.Novation/Attributes/ColorCapabilityAttribute.cs @@ -0,0 +1,33 @@ +using System; + +namespace RGB.NET.Devices.Novation.Attributes +{ + /// + /// Specifies the color-capability of a field. + /// + [AttributeUsage(AttributeTargets.Field)] + public class ColorCapabilityAttribute : Attribute + { + #region Properties & Fields + + /// + /// Gets the Id. + /// + public NovationColorCapabilities Capability { get; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The capability. + public ColorCapabilityAttribute(NovationColorCapabilities capability) + { + this.Capability = capability; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Attributes/DeviceIdAttribute.cs b/RGB.NET.Devices.Novation/Attributes/DeviceIdAttribute.cs new file mode 100644 index 0000000..75a4066 --- /dev/null +++ b/RGB.NET.Devices.Novation/Attributes/DeviceIdAttribute.cs @@ -0,0 +1,33 @@ +using System; + +namespace RGB.NET.Devices.Novation.Attributes +{ + /// + /// Specifies the device-id of a field. + /// + [AttributeUsage(AttributeTargets.Field)] + public class DeviceIdAttribute : Attribute + { + #region Properties & Fields + + /// + /// Gets the Id. + /// + public string Id { get; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The id. + public DeviceIdAttribute(string id) + { + this.Id = id; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Enum/NovationColorCapabilities.cs b/RGB.NET.Devices.Novation/Enum/NovationColorCapabilities.cs new file mode 100644 index 0000000..9f7091a --- /dev/null +++ b/RGB.NET.Devices.Novation/Enum/NovationColorCapabilities.cs @@ -0,0 +1,16 @@ +#pragma warning disable 1591 +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents the color-capabilities of a novation device. + /// + public enum NovationColorCapabilities + { + None, + RGB, + LimitedRG + } +} diff --git a/RGB.NET.Devices.Novation/Enum/NovationDevices.cs b/RGB.NET.Devices.Novation/Enum/NovationDevices.cs new file mode 100644 index 0000000..ca16a62 --- /dev/null +++ b/RGB.NET.Devices.Novation/Enum/NovationDevices.cs @@ -0,0 +1,18 @@ +#pragma warning disable 1591 +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +using RGB.NET.Devices.Novation.Attributes; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a specific novation device. + /// + public enum NovationDevices + { + [DeviceId("Launchpad S")] + [ColorCapability(NovationColorCapabilities.LimitedRG)] + LaunchpadS + } +} diff --git a/RGB.NET.Devices.Novation/Enum/NovationLedIds.cs b/RGB.NET.Devices.Novation/Enum/NovationLedIds.cs new file mode 100644 index 0000000..4023634 --- /dev/null +++ b/RGB.NET.Devices.Novation/Enum/NovationLedIds.cs @@ -0,0 +1,107 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Novation +{ + /// + /// Contains list of all LEDs available for all Novation devices. + /// They are represented as Hex 0x[00][11] where [00] is the status flag, [1] the id of the led. + /// + //TODO DarthAffe 15.08.2017: Check if this is really correct for all devices + public enum NovationLedIds + { + Invalid = -1, + + Grid1 = 0x9000, + Grid2 = 0x9001, + Grid3 = 0x9002, + Grid4 = 0x9003, + Grid5 = 0x9004, + Grid6 = 0x9005, + Grid7 = 0x9006, + Grid8 = 0x9007, + + Grid9 = 0x9010, + Grid10 = 0x9011, + Grid11 = 0x9012, + Grid12 = 0x9013, + Grid13 = 0x9014, + Grid14 = 0x9015, + Grid15 = 0x9016, + Grid16 = 0x9017, + + Grid17 = 0x9020, + Grid18 = 0x9021, + Grid19 = 0x9022, + Grid20 = 0x9023, + Grid21 = 0x9024, + Grid22 = 0x9025, + Grid23 = 0x9026, + Grid24 = 0x9027, + + Grid25 = 0x9030, + Grid26 = 0x9031, + Grid27 = 0x9032, + Grid28 = 0x9033, + Grid29 = 0x9034, + Grid30 = 0x9035, + Grid31 = 0x9036, + Grid32 = 0x9037, + + Grid33 = 0x9040, + Grid34 = 0x9041, + Grid35 = 0x9042, + Grid36 = 0x9043, + Grid37 = 0x9044, + Grid38 = 0x9045, + Grid39 = 0x9046, + Grid40 = 0x9047, + + Grid41 = 0x9050, + Grid42 = 0x9051, + Grid43 = 0x9052, + Grid44 = 0x9053, + Grid45 = 0x9054, + Grid46 = 0x9055, + Grid47 = 0x9056, + Grid48 = 0x9057, + + Grid49 = 0x9060, + Grid50 = 0x9061, + Grid51 = 0x9062, + Grid52 = 0x9063, + Grid53 = 0x9064, + Grid54 = 0x9065, + Grid55 = 0x9066, + Grid56 = 0x9067, + + Grid57 = 0x9070, + Grid58 = 0x9071, + Grid59 = 0x9072, + Grid60 = 0x9073, + Grid61 = 0x9074, + Grid62 = 0x9075, + Grid63 = 0x9076, + Grid64 = 0x9077, + + Up = 0xB068, + Down = 0xB069, + Left = 0xB06A, + Right = 0xB06B, + Session = 0xB06C, + User1 = 0xB06D, + User2 = 0xB06E, + Mix = 0xB06F, + + Scene1 = 0x9009, + Scene2 = 0x9019, + Scene3 = 0x9029, + Scene4 = 0x9039, + Scene5 = 0x9049, + Scene6 = 0x9059, + Scene7 = 0x9069, + Scene8 = 0x9079 + } +} diff --git a/RGB.NET.Devices.Novation/Generic/NovationLedId.cs b/RGB.NET.Devices.Novation/Generic/NovationLedId.cs new file mode 100644 index 0000000..45d87bb --- /dev/null +++ b/RGB.NET.Devices.Novation/Generic/NovationLedId.cs @@ -0,0 +1,107 @@ +using System.Diagnostics; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a Id of a on a . + /// + [DebuggerDisplay("{" + nameof(LedId) + "}")] + public class NovationLedId : ILedId + { + #region Properties & Fields + + internal readonly NovationLedIds LedId; + + /// + public IRGBDevice Device { get; } + + /// + public bool IsValid => LedId != NovationLedIds.Invalid; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The the belongs to. + /// The of the represented . + public NovationLedId(IRGBDevice device, NovationLedIds ledId) + { + this.Device = device; + this.LedId = ledId; + } + + #endregion + + #region Methods + + /// + /// Converts the Id of this to a human-readable string. + /// + /// A string that contains the Id of this . For example "Enter". + public override string ToString() + { + return LedId.ToString(); + } + + /// + /// Tests whether the specified object is a and is equivalent to this . + /// + /// The object to test. + /// true if is a equivalent to this ; otherwise, false. + public override bool Equals(object obj) + { + NovationLedId compareLedId = obj as NovationLedId; + if (ReferenceEquals(compareLedId, null)) + return false; + + if (ReferenceEquals(this, compareLedId)) + return true; + + if (GetType() != compareLedId.GetType()) + return false; + + return compareLedId.LedId == LedId; + } + + /// + /// Returns a hash code for this . + /// + /// An integer value that specifies the hash code for this . + public override int GetHashCode() + { + return LedId.GetHashCode(); + } + + #endregion + + #region Operators + + /// + /// Returns a value that indicates whether two specified are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(NovationLedId ledId1, NovationLedId ledId2) + { + return ReferenceEquals(ledId1, null) ? ReferenceEquals(ledId2, null) : ledId1.Equals(ledId2); + } + + /// + /// Returns a value that indicates whether two specified are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(NovationLedId ledId1, NovationLedId ledId2) + { + return !(ledId1 == ledId2); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Generic/NovationRGBDevice.cs b/RGB.NET.Devices.Novation/Generic/NovationRGBDevice.cs new file mode 100644 index 0000000..f3de7dd --- /dev/null +++ b/RGB.NET.Devices.Novation/Generic/NovationRGBDevice.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using RGB.NET.Core; +using RGB.NET.Core.Layout; +using Sanford.Multimedia.Midi; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a generic Novation-device. (launchpad). + /// + public abstract class NovationRGBDevice : AbstractRGBDevice + { + #region Properties & Fields + + private readonly OutputDevice _outputDevice; + private readonly NovationRGBDeviceInfo _deviceInfo; + + /// + /// Gets information about the . + /// + public override IRGBDeviceInfo DeviceInfo => _deviceInfo; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The generic information provided by Novation for the device. + protected NovationRGBDevice(NovationRGBDeviceInfo info) + { + _deviceInfo = info; + + _outputDevice = new OutputDevice(info.DeviceId); + } + + #endregion + + #region Methods + + + /// + /// Initializes the device. + /// + internal void Initialize() + { + InitializeLayout(); + + if (InternalSize == null) + { + Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle)); + InternalSize = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y); + } + } + + /// + /// Initializes the and of the device. + /// + protected abstract void InitializeLayout(); + + /// + /// Applies the given layout. + /// + /// The file containing the layout. + /// The name of the layout used to get the images of the leds. + /// The path images for this device are collected in. + protected void ApplyLayoutFromFile(string layoutPath, string imageLayout, string imageBasePath) + { + DeviceLayout layout = DeviceLayout.Load(layoutPath); + if (layout != null) + { + LedImageLayout ledImageLayout = layout.LedImageLayouts.FirstOrDefault(x => string.Equals(x.Layout, imageLayout, StringComparison.OrdinalIgnoreCase)); + + InternalSize = new Size(layout.Width, layout.Height); + + if (layout.Leds != null) + foreach (LedLayout layoutLed in layout.Leds) + { + NovationLedIds ledId; + if (Enum.TryParse(layoutLed.Id, true, out ledId)) + { + Led led; + if (LedMapping.TryGetValue(new NovationLedId(this, ledId), out led)) + { + led.LedRectangle.Location.X = layoutLed.X; + led.LedRectangle.Location.Y = layoutLed.Y; + led.LedRectangle.Size.Width = layoutLed.Width; + led.LedRectangle.Size.Height = layoutLed.Height; + + led.Shape = layoutLed.Shape; + led.ShapeData = layoutLed.ShapeData; + + LedImage image = ledImageLayout?.LedImages.FirstOrDefault(x => x.Id == layoutLed.Id); + led.Image = (!string.IsNullOrEmpty(image?.Image)) + ? new Uri(Path.Combine(imageBasePath, image.Image), UriKind.Absolute) + : new Uri(Path.Combine(imageBasePath, "Missing.png"), UriKind.Absolute); + } + } + } + } + } + + /// + protected override void UpdateLeds(IEnumerable ledsToUpdate) + { + List leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList(); + + if (leds.Count > 0) + { + foreach (Led led in leds) + { + NovationLedId ledId = led.Id as NovationLedId; + if (ledId == null) continue; + + int color = ConvertColor(led.Color); + SendMessage(ledId.LedId.GetStatus(), ledId.LedId.GetId(), color); + } + } + } + + /// + /// Resets the back top default. + /// + public virtual void Reset() => SendMessage(0xB0, 0, 0); + + /// + /// Convert a to its novation-representation depending on the of the . + /// + /// The to convert. + /// The novation-representation of the . + protected virtual int ConvertColor(Color color) + { + switch (_deviceInfo.ColorCapabilities) + { + case NovationColorCapabilities.RGB: + return ConvertColorFull(color); + case NovationColorCapabilities.LimitedRG: + return ConvertColorLimited(color); + default: + return 0; + } + } + + /// + /// Convert a to its novation-representation depending on the of the . + /// The conversion uses the full rgb-range. + /// + /// The to convert. + /// The novation-representation of the . + protected virtual int ConvertColorFull(Color color) + { + //TODO DarthAffe 16.08.2017: How are colors for full rgb devices encoded? + return 0; + } + + /// + /// Convert a to its novation-representation depending on the of the . + /// The conversion uses only a limited amount of colors (3 red, 3 yellow, 3 green). + /// + /// The to convert. + /// The novation-representation of the . + protected virtual int ConvertColorLimited(Color color) + { + if ((color.Hue >= 330) || (color.Hue < 30)) + return (int)Math.Ceiling(color.Value * 3); // red with brightness 1, 2 or 3 + + if ((color.Hue >= 30) && (color.Hue < 90)) // yellow with brightness 17, 34 or 51 + return (int)Math.Ceiling(color.Value * 3) * 17; + + if ((color.Hue >= 90) && (color.Hue < 150)) // green with brightness 16, 32 or 48 + return (int)Math.Ceiling(color.Value * 3) * 16; + + return 0; + } + + /// + /// Sends a message to the . + /// + /// The status-code of the message. + /// The first data-package of the message. + /// The second data-package of the message. + protected virtual void SendMessage(int status, int data1, int data2) + { + ShortMessage shortMessage = new ShortMessage(Convert.ToByte(status), Convert.ToByte(data1), Convert.ToByte(data2)); + _outputDevice.SendShort(shortMessage.Message); + } + + /// + public override void Dispose() + { + Reset(); + _outputDevice.Dispose(); + + base.Dispose(); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Generic/NovationRGBDeviceInfo.cs b/RGB.NET.Devices.Novation/Generic/NovationRGBDeviceInfo.cs new file mode 100644 index 0000000..dbc703d --- /dev/null +++ b/RGB.NET.Devices.Novation/Generic/NovationRGBDeviceInfo.cs @@ -0,0 +1,59 @@ +using System; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a generic information for a Corsair-. + /// + public class NovationRGBDeviceInfo : IRGBDeviceInfo + { + #region Properties & Fields + + /// + public RGBDeviceType DeviceType { get; } + + /// + public string Manufacturer => "Novation"; + + /// + public string Model { get; } + + /// + public Uri Image { get; protected set; } + + /// + public RGBDeviceLighting Lighting => RGBDeviceLighting.Key; + + /// + /// Gets the of the . + /// + public NovationColorCapabilities ColorCapabilities { get; } + + /// + /// Gets the (midi)-id of the .. + /// + public int DeviceId { get; } + + #endregion + + #region Constructors + + /// + /// Internal constructor of managed . + /// + /// The type of the . + /// The represented device model. + /// The (midi)-id of the . + /// The of the . + internal NovationRGBDeviceInfo(RGBDeviceType deviceType, string model, int deviceId, NovationColorCapabilities colorCapabilities) + { + this.DeviceType = deviceType; + this.Model = model; + this.DeviceId = deviceId; + this.ColorCapabilities = colorCapabilities; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Helper/EnumExtension.cs b/RGB.NET.Devices.Novation/Helper/EnumExtension.cs new file mode 100644 index 0000000..9be8305 --- /dev/null +++ b/RGB.NET.Devices.Novation/Helper/EnumExtension.cs @@ -0,0 +1,40 @@ +using System; +using System.Reflection; +using RGB.NET.Devices.Novation.Attributes; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Offers some extensions and helper-methods for enum related things. + /// + internal static class EnumExtension + { + /// + /// Gets the value of the . + /// + /// The enum value to get the description from. + /// The value of the of the source. + internal static string GetDeviceId(this Enum source) => source.GetAttribute()?.Id; + + /// + /// Gets the value of the . + /// + /// The enum value to get the description from. + /// The value of the of the source. + internal static NovationColorCapabilities GetColorCapability(this Enum source) => source.GetAttribute()?.Capability ?? NovationColorCapabilities.None; + + /// + /// Gets the attribute of type T. + /// + /// The enum value to get the attribute from + /// The generic attribute type + /// The . + private static T GetAttribute(this Enum source) + where T : Attribute + { + FieldInfo fi = source.GetType().GetField(source.ToString()); + T[] attributes = (T[])fi.GetCustomAttributes(typeof(T), false); + return attributes.Length > 0 ? attributes[0] : null; + } + } +} diff --git a/RGB.NET.Devices.Novation/Helper/NovationLedIdsExtension.cs b/RGB.NET.Devices.Novation/Helper/NovationLedIdsExtension.cs new file mode 100644 index 0000000..a68c150 --- /dev/null +++ b/RGB.NET.Devices.Novation/Helper/NovationLedIdsExtension.cs @@ -0,0 +1,47 @@ +namespace RGB.NET.Devices.Novation +{ + /// + /// Offers some extensions and helper-methods for NovationLedIds related things. + /// + public static class NovationLedIdsExtension + { + #region Methods + + /// + /// Gets the status-flag associated with the id. + /// + /// The whose status-flag should be determinated. + /// The status-flag of the . + public static int GetStatus(this NovationLedIds ledId) => ((int)ledId & 0xFF00) >> 8; + + /// + /// Gets the id associated with the id. + /// + /// The whose idshould be determinated. + /// The id of the . + public static int GetId(this NovationLedIds ledId) => (int)ledId & 0x00FF; + + /// + /// Tests if the given is a grid-button. + /// + /// the to test. + /// true if is a grid-button; otherwise, false. + public static bool IsGrid(this NovationLedIds ledId) => (ledId.GetStatus() == 0x90) && ((ledId.GetId() / 0x10) < 0x08) && ((ledId.GetId() % 0x10) < 0x08); + + /// + /// Tests if the given is a scene-button. + /// + /// the to test. + /// true if is a scene-button; otherwise, false. + public static bool IsScene(this NovationLedIds ledId) => (ledId.GetStatus() == 0x90) && ((ledId.GetId() / 0x10) < 0x08) && ((ledId.GetId() % 0x10) == 0x09); + + /// + /// Tests if the given is custom-button. + /// + /// the to test. + /// true if is a custom-button; otherwise, false. + public static bool IsCustom(this NovationLedIds ledId) => (ledId.GetStatus() == 0xB0) && ((ledId.GetId() / 0x10) == 0x06) && ((ledId.GetId() % 0x10) > 0x07); + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Grid.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Grid.png new file mode 100644 index 0000000..7a492cb Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Grid.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter1.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter1.png new file mode 100644 index 0000000..351d439 Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter1.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter2.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter2.png new file mode 100644 index 0000000..1b45cf7 Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter2.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter3.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter3.png new file mode 100644 index 0000000..592d3e5 Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter3.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter4.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter4.png new file mode 100644 index 0000000..988a19b Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/GridCenter4.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Round.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Round.png new file mode 100644 index 0000000..fc3437f Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/Buttons/Round.png differ diff --git a/RGB.NET.Devices.Novation/Images/Novation/Launchpads/LaunchpadS.png b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/LaunchpadS.png new file mode 100644 index 0000000..51970ea Binary files /dev/null and b/RGB.NET.Devices.Novation/Images/Novation/Launchpads/LaunchpadS.png differ diff --git a/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDevice.cs b/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDevice.cs new file mode 100644 index 0000000..7625423 --- /dev/null +++ b/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDevice.cs @@ -0,0 +1,62 @@ +using System; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a Novation launchpad. + /// + public class NovationLaunchpadRGBDevice : NovationRGBDevice + { + #region Properties & Fields + + /// + /// Gets information about the . + /// + public NovationLaunchpadRGBDeviceInfo LaunchpadDeviceInfo { get; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The specific information provided by Novation for the launchpad + internal NovationLaunchpadRGBDevice(NovationLaunchpadRGBDeviceInfo info) + : base(info) + { + this.LaunchpadDeviceInfo = info; + } + + #endregion + + #region Methods + + /// + protected override void InitializeLayout() + { + //TODO DarthAffe 15.08.2017: Check if all launchpads are using the same basic layout + const int BUTTON_SIZE = 20; + foreach (NovationLedIds ledId in Enum.GetValues(typeof(NovationLedIds))) + { + Rectangle rectangle; + if (ledId.IsCustom()) + rectangle = new Rectangle(BUTTON_SIZE * (ledId.GetId() - 0x68), 0, BUTTON_SIZE, BUTTON_SIZE); + else if (ledId.IsScene()) + rectangle = new Rectangle(8 * BUTTON_SIZE, BUTTON_SIZE * (((int)ledId.GetId() / 0x10) + 1), BUTTON_SIZE, BUTTON_SIZE); + else if (ledId.IsGrid()) + rectangle = new Rectangle(BUTTON_SIZE * ((int)ledId.GetId() % 0x10), BUTTON_SIZE * (((int)ledId.GetId() / 0x10) + 1), BUTTON_SIZE, BUTTON_SIZE); + else continue; + + InitializeLed(new NovationLedId(this, ledId), rectangle); + } + + string model = LaunchpadDeviceInfo.Model.Replace(" ", string.Empty).ToUpper(); + ApplyLayoutFromFile(PathHelper.GetAbsolutePath( + $@"Layouts\Novation\Launchpads\{model.ToUpper()}.xml"), "Default", PathHelper.GetAbsolutePath(@"Images\Novation\Launchpads")); + } + + #endregion + } +} \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDeviceInfo.cs b/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDeviceInfo.cs new file mode 100644 index 0000000..6a47179 --- /dev/null +++ b/RGB.NET.Devices.Novation/Launchpad/NovationLaunchpadRGBDeviceInfo.cs @@ -0,0 +1,27 @@ +using System; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a generic information for a . + /// + public class NovationLaunchpadRGBDeviceInfo : NovationRGBDeviceInfo + { + #region Constructors + + /// + /// Internal constructor of managed . + /// + /// The represented device model. + /// + /// The of the . + internal NovationLaunchpadRGBDeviceInfo(string model, int deviceId, NovationColorCapabilities colorCapabilities) + : base(RGBDeviceType.LedMatrix, model, deviceId, colorCapabilities) + { + Image = new Uri(PathHelper.GetAbsolutePath($@"Images\Novation\Launchpads\{Model.Replace(" ", string.Empty).ToUpper()}.png"), UriKind.Absolute); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Layouts/DeviceLayout.xsd b/RGB.NET.Devices.Novation/Layouts/DeviceLayout.xsd new file mode 100644 index 0000000..92690b3 --- /dev/null +++ b/RGB.NET.Devices.Novation/Layouts/DeviceLayout.xsd @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadS.xml b/RGB.NET.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadS.xml new file mode 100644 index 0000000..f9dda31 --- /dev/null +++ b/RGB.NET.Devices.Novation/Layouts/Novation/Launchpads/LaunchpadS.xml @@ -0,0 +1,425 @@ + + + Launchpad S + Launchpad S (8x8-Pad Grid) + LedMatrix + Key + Novation + Launchpad S + 240 + 240 + 20 + 20 + + + + Circle + 16 + 18 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + Circle + +8 + 16mm + 16mm + + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + M0,0 L0,1 L0.75,1 L1,0.75 L1,0 Z + + + +4 + M0,0 L0,0.75 L0.25,1 L1,1 L1,0 Z + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + M0,0 L0,1 L1,1 L1,0.25 L0.75,0 Z + + + +4 + M0,0.25 L0,1 L1,1 L1,0 L0.25,0 Z + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + 14 + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + +4 + + + + + Circle + +4 + 40 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + Circle + ~ + +8 + 16mm + 16mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/NovationDeviceProvider.cs b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs new file mode 100644 index 0000000..40d2de9 --- /dev/null +++ b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs @@ -0,0 +1,116 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedMember.Global + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using RGB.NET.Core; +using Sanford.Multimedia.Midi; + +namespace RGB.NET.Devices.Novation +{ + /// + /// Represents a device provider responsible for Novation devices. + /// + public class NovationDeviceProvider : IRGBDeviceProvider + { + #region Properties & Fields + + private static NovationDeviceProvider _instance; + /// + /// Gets the singleton instance. + /// + public static NovationDeviceProvider Instance => _instance ?? new NovationDeviceProvider(); + + /// + /// Indicates if the SDK is initialized and ready to use. + /// + public bool IsInitialized { get; private set; } + + /// + /// Gets whether the application has exclusive access to the SDK or not. + /// + public bool HasExclusiveAccess => false; + + /// + public IEnumerable Devices { get; private set; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// Thrown if this constructor is called even if there is already an instance of this class. + private NovationDeviceProvider() + { + if (_instance != null) throw new InvalidOperationException($"There can be only one instanc of type {nameof(NovationDeviceProvider)}"); + _instance = this; + } + + #endregion + + #region Methods + + /// + public bool Initialize(bool exclusiveAccessIfPossible = false, bool throwExceptions = false) + { + IsInitialized = false; + + try + { + IList devices = new List(); + + try + { + for (int index = 0; index < OutputDeviceBase.DeviceCount; index++) + { + MidiOutCaps outCaps = OutputDeviceBase.GetDeviceCapabilities(index); + if (outCaps.name == null) continue; + + NovationDevices? deviceId = (NovationDevices?)Enum.GetValues(typeof(NovationDevices)).Cast() + .FirstOrDefault(x => string.Equals(x.GetDeviceId(), outCaps.name, StringComparison.OrdinalIgnoreCase)); + + if (deviceId == null) continue; + + NovationRGBDevice device = new NovationLaunchpadRGBDevice(new NovationLaunchpadRGBDeviceInfo(outCaps.name, index, deviceId.GetColorCapability())); + device.Initialize(); + devices.Add(device); + } + } + catch + { + if (throwExceptions) + throw; + } + + Devices = new ReadOnlyCollection(devices); + } + catch + { + if (throwExceptions) + throw; + else + return false; + } + + IsInitialized = true; + + return true; + } + + /// + public void ResetDevices() + { + foreach (IRGBDevice device in Devices) + { + NovationLaunchpadRGBDevice novationDevice = device as NovationLaunchpadRGBDevice; + novationDevice?.Reset(); + } + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Novation/Properties/AssemblyInfo.cs b/RGB.NET.Devices.Novation/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..85ae5fe --- /dev/null +++ b/RGB.NET.Devices.Novation/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RGB.NET.Devices.Novation")] +[assembly: AssemblyDescription("Novation-Device-Implementations of RGB.NET")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Wyrez")] +[assembly: AssemblyProduct("RGB.NET.Devices.Novation")] +[assembly: AssemblyCopyright("Copyright © Wyrez 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dda8c4c2-8abf-4fa0-9af9-c47ad0bfe47d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj new file mode 100644 index 0000000..92a372d --- /dev/null +++ b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {DB2911F6-404C-4BC8-B35F-232A7450755F} + Library + Properties + RGB.NET.Devices.Novation + RGB.NET.Devices.Novation + v4.5 + 512 + + + true + full + false + ..\bin\ + DEBUG;TRACE + prompt + 4 + ..\bin\RGB.NET.Devices.Novation.XML + + + pdbonly + true + ..\bin\ + TRACE + prompt + 4 + ..\bin\RGB.NET.Devices.Novation.XML + + + + ..\packages\Sanford.Multimedia.Midi.6.4.1\lib\net20\Sanford.Multimedia.Midi.dll + + + + + + ..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + {5a4f9a75-75fe-47cd-90e5-914d5b20d232} + RGB.NET.Core + + + + + Designer + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj.DotSettings b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj.DotSettings new file mode 100644 index 0000000..b5910ca --- /dev/null +++ b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj.DotSettings @@ -0,0 +1,5 @@ + + True + True + True + True \ No newline at end of file diff --git a/RGB.NET.Devices.Novation/packages.config b/RGB.NET.Devices.Novation/packages.config new file mode 100644 index 0000000..a386c00 --- /dev/null +++ b/RGB.NET.Devices.Novation/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/RGB.NET.sln b/RGB.NET.sln index 224592c..f4fde81 100644 --- a/RGB.NET.sln +++ b/RGB.NET.sln @@ -32,6 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{06416566 NuGet\RGB.NET.Devices.CoolerMaster.nuspec = NuGet\RGB.NET.Devices.CoolerMaster.nuspec NuGet\RGB.NET.Devices.Corsair.nuspec = NuGet\RGB.NET.Devices.Corsair.nuspec NuGet\RGB.NET.Devices.Logitech.nuspec = NuGet\RGB.NET.Devices.Logitech.nuspec + NuGet\RGB.NET.Devices.Novation.nuspec = NuGet\RGB.NET.Devices.Novation.nuspec NuGet\RGB.NET.Effects.nuspec = NuGet\RGB.NET.Effects.nuspec NuGet\RGB.NET.Groups.nuspec = NuGet\RGB.NET.Groups.nuspec NuGet\RGB.NET.Input.Corsair.nuspec = NuGet\RGB.NET.Input.Corsair.nuspec @@ -47,6 +48,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGB.NET.Devices.Logitech", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGB.NET.Devices.CoolerMaster", "RGB.NET.Devices.CoolerMaster\RGB.NET.Devices.CoolerMaster.csproj", "{85609427-D433-44E2-A249-CE890B66D845}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGB.NET.Devices.Novation", "RGB.NET.Devices.Novation\RGB.NET.Devices.Novation.csproj", "{DB2911F6-404C-4BC8-B35F-232A7450755F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -93,6 +96,10 @@ Global {85609427-D433-44E2-A249-CE890B66D845}.Debug|Any CPU.Build.0 = Debug|Any CPU {85609427-D433-44E2-A249-CE890B66D845}.Release|Any CPU.ActiveCfg = Release|Any CPU {85609427-D433-44E2-A249-CE890B66D845}.Release|Any CPU.Build.0 = Release|Any CPU + {DB2911F6-404C-4BC8-B35F-232A7450755F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB2911F6-404C-4BC8-B35F-232A7450755F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB2911F6-404C-4BC8-B35F-232A7450755F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB2911F6-404C-4BC8-B35F-232A7450755F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -107,5 +114,6 @@ Global {8D6C4FE6-0046-4E98-876F-4C0B87249989} = {BD7C9994-1747-4595-9C21-298E8FDCB657} {E7B2F174-FCC6-4FC7-9970-3138B5F4C921} = {33D5E279-1C4E-4AB6-9D1E-6D18109A6C25} {85609427-D433-44E2-A249-CE890B66D845} = {33D5E279-1C4E-4AB6-9D1E-6D18109A6C25} + {DB2911F6-404C-4BC8-B35F-232A7450755F} = {33D5E279-1C4E-4AB6-9D1E-6D18109A6C25} EndGlobalSection EndGlobal