333 lines
13 KiB
C#
333 lines
13 KiB
C#
#nullable enable
|
||
using System.Diagnostics.CodeAnalysis;
|
||
using NAudio;
|
||
using NAudio.Midi;
|
||
using T3.Editor.Gui.Interaction.Midi.CommandProcessing;
|
||
using T3.Editor.Gui.Interaction.Variations;
|
||
using T3.Editor.Gui.Interaction.Variations.Model;
|
||
|
||
namespace T3.Editor.Gui.Interaction.Midi.CompatibleDevices;
|
||
|
||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||
[MidiDeviceProduct("APC mini mk2")]
|
||
public sealed class ApcMiniMk2 : CompatibleMidiDevice
|
||
{
|
||
public ApcMiniMk2()
|
||
{
|
||
CommandTriggerCombinations
|
||
= new List<CommandTriggerCombination>
|
||
{
|
||
new(SnapshotActions.ActivateOrCreateSnapshotAtIndex, InputModes.Default, new[] { SceneTrigger1To64 },
|
||
CommandTriggerCombination.ExecutesAt.SingleRangeButtonPressed),
|
||
|
||
new(SnapshotActions.SaveSnapshotAtIndex, InputModes.Save, new[] { SceneTrigger1To64 },
|
||
CommandTriggerCombination.ExecutesAt.SingleRangeButtonPressed),
|
||
|
||
new(SnapshotActions.RemoveSnapshotAtIndex, InputModes.Delete, new[] { SceneTrigger1To64 },
|
||
CommandTriggerCombination.ExecutesAt.SingleRangeButtonPressed),
|
||
|
||
new(BlendActions.StartBlendingSnapshots, InputModes.Default, new[] { SceneTrigger1To64 },
|
||
CommandTriggerCombination.ExecutesAt.AllCombinedButtonsReleased),
|
||
|
||
new(BlendActions.StartBlendingTowardsSnapshot, InputModes.BlendTo, new[] { SceneTrigger1To64 },
|
||
CommandTriggerCombination.ExecutesAt.SingleRangeButtonPressed),
|
||
|
||
new(BlendActions.StopBlendingTowards, InputModes.Default, new[] { SceneLaunch8ClipStopAll },
|
||
CommandTriggerCombination.ExecutesAt.SingleActionButtonPressed),
|
||
|
||
new(BlendActions.UpdateBlendingTowardsProgress, InputModes.Default, new[] { Slider9 },
|
||
CommandTriggerCombination.ExecutesAt.ControllerChange),
|
||
|
||
new(BlendActions.UpdateBlendValues, InputModes.Default, new[] { Sliders1To8 },
|
||
CommandTriggerCombination.ExecutesAt.ControllerChange),
|
||
};
|
||
|
||
ModeButtons = new List<ModeButton>
|
||
{
|
||
new(Shift, InputModes.BlendTo),
|
||
new(SceneLaunch1ClipStop, InputModes.Delete),
|
||
};
|
||
}
|
||
|
||
protected override void UpdateVariationVisualization()
|
||
{
|
||
_updateCount++;
|
||
|
||
UpdateRangeLeds(SceneTrigger1To64,
|
||
mappedIndex =>
|
||
{
|
||
var color = Colors.Off;
|
||
if (!SymbolVariationPool.TryGetSnapshot(mappedIndex, out var variation))
|
||
{
|
||
return (int)color;
|
||
}
|
||
|
||
if (variation.State == Variation.States.Active)
|
||
{
|
||
return (int)Colors.Red;
|
||
}
|
||
|
||
switch (variation.State)
|
||
{
|
||
case Variation.States.Undefined:
|
||
color = Colors.Off;
|
||
break;
|
||
case Variation.States.InActive:
|
||
color = Colors.Green;
|
||
break;
|
||
case Variation.States.Active:
|
||
color = Colors.Red;
|
||
break;
|
||
case Variation.States.Modified:
|
||
color = Colors.Orange;
|
||
break;
|
||
case Variation.States.IsBlended:
|
||
color = Colors.BrightPurpleBlue;
|
||
break;
|
||
}
|
||
|
||
return AddModeHighlight(mappedIndex, (int)color);
|
||
});
|
||
}
|
||
|
||
private int AddModeHighlight(int index, int orgColor)
|
||
{
|
||
var indicatedStatus = (_updateCount + index / 8) % 30 < 4;
|
||
if (!indicatedStatus)
|
||
{
|
||
return orgColor;
|
||
}
|
||
|
||
return ActiveMode switch
|
||
{
|
||
InputModes.Save => (int)Colors.Yellow,
|
||
InputModes.BlendTo => (int)Colors.Yellow,
|
||
InputModes.Delete => (int)Colors.Red,
|
||
_ => orgColor
|
||
};
|
||
}
|
||
|
||
private int _updateCount;
|
||
|
||
protected override void SendColor(MidiOut midiOut, int apcControlIndex, int colorCode)
|
||
{
|
||
if (CacheControllerColors[apcControlIndex] == colorCode)
|
||
return;
|
||
|
||
//const int = 150;
|
||
var noteOnEvent = new NoteOnEvent(0, (int)LedStatesMidiChannels.On100, apcControlIndex, colorCode, 50);
|
||
try
|
||
{
|
||
midiOut.Send(noteOnEvent.GetAsShortMessage());
|
||
}
|
||
catch (MmException e)
|
||
{
|
||
Log.Warning("Failed setting midi color message:" + e.Message);
|
||
}
|
||
|
||
CacheControllerColors[apcControlIndex] = colorCode;
|
||
}
|
||
|
||
private enum LedStatesBytes
|
||
{
|
||
On010 = 144,
|
||
On025 = 145,
|
||
On050 = 146,
|
||
On065 = 147,
|
||
On075 = 148,
|
||
On090 = 149,
|
||
On100 = 150,
|
||
Pulsing1By16 = 151,
|
||
Pulsing1By8 = 152,
|
||
Pulsing1By4 = 153,
|
||
Pulsing1By2 = 154,
|
||
Blinking1By24 = 154,
|
||
Blinking1By16 = 155,
|
||
Blinking1By8 = 156,
|
||
Blinking1By4 = 157,
|
||
Blinking1By2 = 158,
|
||
}
|
||
|
||
private enum LedStatesMidiChannels
|
||
{
|
||
On010 = 0,
|
||
On025 = 1,
|
||
On050 = 2,
|
||
On065 = 3,
|
||
On075 = 4,
|
||
On090 = 5,
|
||
On100 = 6,
|
||
Pulsing1By16 = 7,
|
||
Pulsing1By8 = 8,
|
||
Pulsing1By4 = 9,
|
||
Pulsing1By2 = 10,
|
||
Blinking1By24 = 11,
|
||
Blinking1By16 = 12,
|
||
Blinking1By8 = 13,
|
||
Blinking1By4 = 14,
|
||
Blinking1By2 = 15,
|
||
}
|
||
|
||
private enum Colors
|
||
{
|
||
Off = 0, //000000
|
||
Charcoal = 1, //1E1E1E
|
||
Gray = 2, //7F7F7F
|
||
White = 3, //FFFFFF
|
||
RedOrange = 4, //FF4C4C
|
||
Red = 5, //FF0000
|
||
DarkRed = 6, //590000
|
||
VeryDarkRed = 7, //190000
|
||
Peach = 8, //FFBD6C
|
||
Orange = 9, //FF5400
|
||
BurntOrange = 10, //591D00
|
||
DarkBrown = 11, //271B00
|
||
LemonYellow = 12, //FFFF4C
|
||
Yellow = 13, //FFFF00
|
||
Olive = 14, //595900
|
||
DarkOlive = 15, //191900
|
||
LightLime = 16, //88FF4C
|
||
LimeGreen = 17, //54FF00
|
||
DarkLimeGreen = 18, //1D5900
|
||
VeryDarkLimeGreen = 19, //142B00
|
||
BrightGreen = 20, //4CFF4C
|
||
Green = 21, //00FF00
|
||
DarkGreen = 22, //005900
|
||
VeryDarkGreen = 23, //001900
|
||
MintGreen = 24, //4CFF5E
|
||
BrightMintGreen = 25, //00FF19
|
||
ForestGreen = 26, //00590D
|
||
VeryDarkForestGreen = 27, //001902
|
||
LightAquamarine = 28, //4CFF88
|
||
Aquamarine = 29, //00FF55
|
||
DarkAquamarine = 30, //00591D
|
||
VeryDarkAquamarine = 31, //001F12
|
||
LightSeaGreen = 32, //4CFFB7
|
||
SeaGreen = 33, //00FF99
|
||
DarkSeaGreen = 34, //005935
|
||
VeryDarkSeaGreen = 35, //001912
|
||
LightSkyBlue = 36, //4CC3FF
|
||
SkyBlue = 37, //00A9FF
|
||
DarkSkyBlue = 38, //004152
|
||
VeryDarkSkyBlue = 39, //001019
|
||
LightAzure = 40, //4C88FF
|
||
Azure = 41, //0055FF
|
||
MidnightBlue = 42, //001D59
|
||
DarkNavyBlue = 43, //000819
|
||
LightRoyalBlue = 44, //4C4CFF
|
||
Blue = 45, //0000FF
|
||
NavyBlue = 46, //000059
|
||
VeryDarkNavyBlue = 47, //000019
|
||
LightViolet = 48, //874CFF
|
||
Violet = 49, //5400FF
|
||
DarkViolet = 50, //190064
|
||
VeryDarkViolet = 51, //0F0030
|
||
LightMagenta = 52, //FF4CFF
|
||
Magenta = 53, //FF00FF
|
||
DarkMagenta = 54, //590059
|
||
VeryDarkMagenta = 55, //190019
|
||
LightPink = 56, //FF4C87
|
||
Pink = 57, //FF0054
|
||
DarkPink = 58, //59001D
|
||
VeryDarkPink = 59, //220013
|
||
BrightRed = 60, //FF1500
|
||
Chestnut = 61, //993500
|
||
DarkChestnut = 62, //795100
|
||
ForestGreenBrown = 63, //436400
|
||
VeryDarkGreenBrown = 64, //033900
|
||
DarkTealGreen = 65, //005735
|
||
DarkCeruleanBlue = 66, //00547F
|
||
ElectricBlue = 67, //0000FF
|
||
DarkCyanBlue = 68, //00454F
|
||
CobaltBlue = 69, //2500CC
|
||
MediumGray = 70, //7F7F7F
|
||
DarkGray = 71, //202020
|
||
BrightLimeYellow = 72, //BDFF2D
|
||
ChartreuseYellow = 73, //AFED06
|
||
NeonGreenYellow = 74, //64FF09
|
||
DarkForestGreen = 75, //108B00
|
||
TurquoiseGreen = 76, //00FF87
|
||
SkyBlueGreen = 77, //00A9FF
|
||
SapphireBlue = 78, //002AFF
|
||
BrightPurpleBlue = 79, //3F00FF
|
||
ElectricPurpleBlue = 80, //7A00FF
|
||
DeepMagentaPink = 81, //B21A7D
|
||
DarkCoffeeBrown = 82, //402100
|
||
BrightOrangeRed = 83, //FF4A00
|
||
LimeGreenYellow = 84, //88E106
|
||
BrightLimeGreenYellow = 85, //72FF15
|
||
BrightGreenYellow = 86, //00FF00
|
||
LightGreenYellow = 87, //3BFF26
|
||
MintGreenYellow = 88, //59FF71
|
||
LightTurquoiseGreen = 89, //38FFCC
|
||
BrightBlueGreen = 90, //5B8AFF
|
||
LightBlueGreen = 91, //3151C6
|
||
LightLavenderBlue = 92, //877FE9
|
||
BrightMagentaPink = 93, //D31DFF
|
||
MagentaPinkRed = 94, //FF005D
|
||
BrightOrangeYellow = 95, //FF7F00
|
||
YellowOliveGreen = 96, //B9B000
|
||
NeonGreenYellow2 = 97, //90FF00
|
||
BrownYellow = 98, //835D07
|
||
DarkOliveYellow = 99, //392B00
|
||
VeryDarkGreenYellow = 100, //144C10
|
||
DarkTealGreenBlue = 101, //0D5038
|
||
DarkNavyBlueGray = 102, //15152A
|
||
DarkBlueGray = 103, //16205A
|
||
VeryDarkChestnut = 104, //693C1C
|
||
CrimsonRed = 105, //A8000A
|
||
LightRedOrange = 106, //DE513D
|
||
BurntOrangeRed = 107, //D86A1C
|
||
YellowGold = 108, //FFE126
|
||
LimeGreenGold = 109, //9EE12F
|
||
DarkLimeGreenGold = 110, //67B50F
|
||
CharcoalGray = 111, //1E1E30
|
||
LightYellowGreen = 112, //DCFF6B
|
||
LightTurquoiseBlue = 113, //80FFBD
|
||
LightLavenderPurple = 114, //9A99FF
|
||
LightPurpleBlue = 115, //8E66FF
|
||
MediumGrayBlue = 116, //404040
|
||
MediumGrayBrown = 117, //757575
|
||
LightCyanBlue = 118, //E0FFFF
|
||
CrimsonRedDark = 119, //A00000
|
||
DarkRedBrown = 120, //350000
|
||
NeonGreenDark = 121, //1AD000
|
||
ForestGreenDark = 122, //074200
|
||
YellowOliveBrown = 123, //B9B000
|
||
OliveBrownYellow = 124, //3F3100
|
||
OliveBrown = 125, //3F3100
|
||
BurntOrange2 = 126, //B35F00
|
||
DarkRed2 = 127, //4B1502
|
||
}
|
||
|
||
// Same bottom-up 8×8 grid as the APC Mini (note 0 = bottom-left); flip rows so the canonical
|
||
// snapshot index 0 lands on the physical top-left pad, for both LED output and button input.
|
||
private static readonly ButtonRange SceneTrigger1To64 = new(0, 63, mapToIndex: position => (8 - 1 - position / 8) * 8 + position % 8);
|
||
private static readonly ButtonRange Sliders1To9 = new(48, 48 + 8);
|
||
private static readonly ButtonRange Sliders1To8 = new(48, 48 + 7);
|
||
private static readonly ButtonRange Slider9 = new(48 + 8, 48 + 8);
|
||
|
||
private static readonly ButtonRange TrackButtons1To8 = new(100, 107);
|
||
|
||
private static readonly ButtonRange TrackButton1ButtonVolume = new(100);
|
||
private static readonly ButtonRange TrackButton2ButtonPan = new(101);
|
||
private static readonly ButtonRange TrackButton3ButtonSend = new(102);
|
||
private static readonly ButtonRange TrackButton4ButtonDevice = new(103);
|
||
private static readonly ButtonRange TrackButton5ButtonUp = new(104);
|
||
private static readonly ButtonRange TrackButton6ButtonDown = new(105);
|
||
private static readonly ButtonRange TrackButton7ButtonLeft = new(106);
|
||
private static readonly ButtonRange TrackButton8ButtonRight = new(107);
|
||
|
||
private static readonly ButtonRange SceneLaunch1To8 = new(112, 119);
|
||
|
||
private static readonly ButtonRange SceneLaunch1ClipStop = new(112);
|
||
private static readonly ButtonRange SceneLaunch2Solo = new(113);
|
||
private static readonly ButtonRange SceneLaunch3Mute = new(114);
|
||
private static readonly ButtonRange SceneLaunch4RecArm = new(115);
|
||
private static readonly ButtonRange SceneLaunch5Select = new(116);
|
||
private static readonly ButtonRange SceneLaunch6Drum = new(117);
|
||
private static readonly ButtonRange SceneLaunch7Note = new(118);
|
||
private static readonly ButtonRange SceneLaunch8ClipStopAll = new(119);
|
||
|
||
private static readonly ButtonRange Shift = new(123);
|
||
} |