using Midi; using System; using System.Collections.Generic; using System.Linq; namespace IntelOrca.Launchpad { public enum ToolbarButton { Up, Down, Left, Right, Session, User1, User2, Mixer } public enum SideButton { Volume, Pan, SoundA, SoundB, Stop, TrackOn, Solo, Arm } public class LaunchpadDevice { private InputDevice mInputDevice; private OutputDevice mOutputDevice; private bool mDoubleBuffered; private bool mDoubleBufferedState; private readonly LaunchpadButton[] mToolbar = new LaunchpadButton[8]; private readonly LaunchpadButton[] mSide = new LaunchpadButton[8]; private readonly LaunchpadButton[,] mGrid = new LaunchpadButton[8, 8]; public event EventHandler ButtonPressed; public LaunchpadDevice() : this(0) { } public LaunchpadDevice(int index) { InitialiseButtons(); int i = 0; mInputDevice = InputDevice.InstalledDevices.Where(x => x.Name.Contains("Launchpad")). FirstOrDefault(x => i++ == index); i = 0; mOutputDevice = OutputDevice.InstalledDevices.Where(x => x.Name.Contains("Launchpad")). FirstOrDefault(x => i++ == index); if (mInputDevice == null) throw new LaunchpadException("Unable to find input device."); if (mOutputDevice == null) throw new LaunchpadException("Unable to find output device."); mInputDevice.Open(); mOutputDevice.Open(); mInputDevice.StartReceiving(new Clock(120)); mInputDevice.NoteOn += mInputDevice_NoteOn; mInputDevice.ControlChange += mInputDevice_ControlChange; Reset(); } private void InitialiseButtons() { for (int i = 0; i < 8; i++) { mToolbar[i] = new LaunchpadButton(this, ButtonType.Toolbar, 104 + i); mSide[i] = new LaunchpadButton(this, ButtonType.Side, i * 16 + 8); } for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) mGrid[x, y] = new LaunchpadButton(this, ButtonType.Grid, y * 16 + x); } private void StartDoubleBuffering() { mDoubleBuffered = true; mDoubleBufferedState = false; mOutputDevice.SendControlChange(Channel.Channel1, (Control)0, 32 | 16 | 1); } public void Refresh() { if (!mDoubleBufferedState) mOutputDevice.SendControlChange(Channel.Channel1, (Control)0, 32 | 16 | 4); else mOutputDevice.SendControlChange(Channel.Channel1, (Control)0, 32 | 16 | 1); mDoubleBufferedState = !mDoubleBufferedState; } private void EndDoubleBuffering() { mOutputDevice.SendControlChange(Channel.Channel1, (Control)0, 32 | 16); mDoubleBuffered = false; } public void Reset() { mOutputDevice.SendControlChange(Channel.Channel1, (Control)0, 0); Buttons.ToList().ForEach(x => x.RedBrightness = x.GreenBrightness = ButtonBrightness.Off); } private void mInputDevice_NoteOn(NoteOnMessage msg) { LaunchpadButton button = GetButton(msg.Pitch); if (button == null) return; button.State = (ButtonPressState)msg.Velocity; if (ButtonPressed != null && button.State == ButtonPressState.Down) { if ((int)msg.Pitch % 16 == 8) ButtonPressed.Invoke(this, new ButtonPressEventArgs((SideButton)((int)msg.Pitch / 16))); else ButtonPressed.Invoke(this, new ButtonPressEventArgs((int)msg.Pitch % 16, (int)msg.Pitch / 16)); } } private void mInputDevice_ControlChange(ControlChangeMessage msg) { ToolbarButton toolbarButton = (ToolbarButton)((int)msg.Control - 104); LaunchpadButton button = GetButton(toolbarButton); if (button == null) return; button.State = (ButtonPressState)msg.Value; if (ButtonPressed != null && button.State == ButtonPressState.Down) { ButtonPressed.Invoke(this, new ButtonPressEventArgs(toolbarButton)); } } public LaunchpadButton GetButton(ToolbarButton toolbarButton) { return mToolbar[(int)toolbarButton]; } public LaunchpadButton GetButton(SideButton sideButton) { return mSide[(int)sideButton]; } private LaunchpadButton GetButton(Pitch pitch) { int x = (int)pitch % 16; int y = (int)pitch / 16; if (x < 8 && y < 8) return mGrid[x, y]; else if (x == 8 && y < 8) return mSide[y]; return null; } public bool DoubleBuffered { get { return mDoubleBuffered; } set { if (mDoubleBuffered) EndDoubleBuffering(); else StartDoubleBuffering(); } } public LaunchpadButton this[int x, int y] { get { return mGrid[x, y]; } } public IEnumerable Buttons { get { for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) yield return mGrid[x, y]; } } internal OutputDevice OutputDevice { get { return mOutputDevice; } } } }