You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
5.7 KiB
C#

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<ButtonPressEventArgs> 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<LaunchpadButton> 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; }
}
}
}