|
|
|
|
using IntelOrca.Launchpad;
|
|
|
|
|
using Midi;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
namespace IntelOrca.LaunchpadTests
|
|
|
|
|
{
|
|
|
|
|
class RainSequencer
|
|
|
|
|
{
|
|
|
|
|
const int NumCols = 16;
|
|
|
|
|
const int NumRows = 8;
|
|
|
|
|
|
|
|
|
|
private LaunchpadDevice mLaunchpadDevice;
|
|
|
|
|
|
|
|
|
|
private bool[,] mSequence = new bool[NumCols, NumRows];
|
|
|
|
|
private bool[] mRemove = new bool[NumCols];
|
|
|
|
|
private int mSequenceOffset;
|
|
|
|
|
private int mColumnOffset;
|
|
|
|
|
private int mMode, mSoundType;
|
|
|
|
|
private int mConfirmTime;
|
|
|
|
|
private bool mForceDraw;
|
|
|
|
|
|
|
|
|
|
private int mTempo = 8 * 60;
|
|
|
|
|
|
|
|
|
|
OutputDevice mOutputDevice;
|
|
|
|
|
private int mInstrument = 0;
|
|
|
|
|
private int mPercussion = 0;
|
|
|
|
|
|
|
|
|
|
public RainSequencer(LaunchpadDevice device)
|
|
|
|
|
{
|
|
|
|
|
mLaunchpadDevice = device;
|
|
|
|
|
mOutputDevice = OutputDevice.InstalledDevices[0];
|
|
|
|
|
mOutputDevice.Open();
|
|
|
|
|
|
|
|
|
|
mLaunchpadDevice.ButtonPressed += mLaunchpadDevice_ButtonPressed;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Random rand = new Random();
|
|
|
|
|
for (int y = 0; y < NumRows; y++)
|
|
|
|
|
for (int x = 0; x < NumRows; x++)
|
|
|
|
|
if (rand.Next(0, 12) == 0)
|
|
|
|
|
mSequence[x, y] = true;
|
|
|
|
|
* */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int SeqYtoButtonY(int y)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int ButtonYtoSeqY(int y)
|
|
|
|
|
{
|
|
|
|
|
return (y + NumRows - mSequenceOffset) % NumRows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int ButtonXtoColX(int x)
|
|
|
|
|
{
|
|
|
|
|
return (x + NumCols - mColumnOffset) % NumCols;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mLaunchpadDevice_ButtonPressed(object sender, ButtonPressEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Type == ButtonType.Grid) {
|
|
|
|
|
if (e.Y == 7) {
|
|
|
|
|
mRemove[ButtonXtoColX(e.X)] = !mRemove[ButtonXtoColX(e.X)];
|
|
|
|
|
if (mMode == 1)
|
|
|
|
|
PlayNoise(e.X);
|
|
|
|
|
} else {
|
|
|
|
|
mSequence[ButtonXtoColX(e.X), ButtonYtoSeqY(e.Y)] = !mSequence[ButtonXtoColX(e.X), ButtonYtoSeqY(e.Y)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mForceDraw = true;
|
|
|
|
|
} else if (e.Type == ButtonType.Toolbar) {
|
|
|
|
|
switch (e.ToolbarButton) {
|
|
|
|
|
case ToolbarButton.Up:
|
|
|
|
|
mSequenceOffset = (mSequenceOffset + NumRows - 1) % NumRows;
|
|
|
|
|
break;
|
|
|
|
|
case ToolbarButton.Down:
|
|
|
|
|
mSequenceOffset = (mSequenceOffset + 1) % NumRows;
|
|
|
|
|
break;
|
|
|
|
|
case ToolbarButton.Left:
|
|
|
|
|
mColumnOffset = (mColumnOffset + NumCols - 1) % NumCols;
|
|
|
|
|
break;
|
|
|
|
|
case ToolbarButton.Right:
|
|
|
|
|
mColumnOffset = (mColumnOffset + 1) % NumCols;
|
|
|
|
|
break;
|
|
|
|
|
case ToolbarButton.Mixer:
|
|
|
|
|
mMode = (mMode == 0 ? 1 : 0);
|
|
|
|
|
break;
|
|
|
|
|
case ToolbarButton.Session:
|
|
|
|
|
if (mConfirmTime > 0) {
|
|
|
|
|
for (int y = 0; y < NumRows; y++)
|
|
|
|
|
for (int x = 0; x < NumCols; x++)
|
|
|
|
|
mSequence[x, y] = false;
|
|
|
|
|
mConfirmTime = 0;
|
|
|
|
|
} else {
|
|
|
|
|
mConfirmTime = 1000;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
mForceDraw = true;
|
|
|
|
|
} else if (e.Type == ButtonType.Side) {
|
|
|
|
|
switch (e.SidebarButton) {
|
|
|
|
|
case SideButton.Volume:
|
|
|
|
|
if (mTempo < 1980)
|
|
|
|
|
mTempo += 20;
|
|
|
|
|
break;
|
|
|
|
|
case SideButton.Pan:
|
|
|
|
|
if (mTempo > 20)
|
|
|
|
|
mTempo -= 20;
|
|
|
|
|
break;
|
|
|
|
|
case SideButton.SoundA:
|
|
|
|
|
if (mSoundType == 0) {
|
|
|
|
|
mPercussion = (mPercussion + 1) % (Percussion.OpenTriangle - Percussion.BassDrum2 + 1);
|
|
|
|
|
mOutputDevice.SendProgramChange(Channel.Channel1, (Instrument)mInstrument);
|
|
|
|
|
} else {
|
|
|
|
|
mSoundType = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SideButton.SoundB:
|
|
|
|
|
if (mSoundType == 1) {
|
|
|
|
|
mInstrument = (mInstrument + 1) % 127;
|
|
|
|
|
mOutputDevice.SendProgramChange(Channel.Channel1, (Instrument)mInstrument);
|
|
|
|
|
} else {
|
|
|
|
|
mSoundType = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SideButton.Arm:
|
|
|
|
|
mSequenceOffset = 0;
|
|
|
|
|
mColumnOffset = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Run()
|
|
|
|
|
{
|
|
|
|
|
long last_tick = Environment.TickCount;
|
|
|
|
|
long delay = 1;
|
|
|
|
|
long duration = 0;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
delay = (int)(1000.0 / (mTempo / 60.0));
|
|
|
|
|
duration = Environment.TickCount - last_tick;
|
|
|
|
|
if (duration < delay) {
|
|
|
|
|
if (mForceDraw) {
|
|
|
|
|
Draw();
|
|
|
|
|
mForceDraw = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
last_tick = Environment.TickCount;
|
|
|
|
|
mConfirmTime = Math.Max(0, mConfirmTime - (int)duration);
|
|
|
|
|
|
|
|
|
|
Update();
|
|
|
|
|
Draw();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PlayNoise(int tone)
|
|
|
|
|
{
|
|
|
|
|
new Thread(new ThreadStart(() => {
|
|
|
|
|
if (mSoundType == 0) {
|
|
|
|
|
mOutputDevice.SendPercussion(Percussion.BassDrum2 + mPercussion + tone, 127);
|
|
|
|
|
} else {
|
|
|
|
|
mOutputDevice.SendNoteOn(Channel.Channel1, Pitch.A4 + tone, 127);
|
|
|
|
|
Thread.Sleep((int)(1000.0 / (mTempo / 60.0)));
|
|
|
|
|
mOutputDevice.SendNoteOff(Channel.Channel1, Pitch.A4 + tone, 127);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Console.Beep(100 * (tone + 3), 100);
|
|
|
|
|
})).Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DiscardRedBeats()
|
|
|
|
|
{
|
|
|
|
|
int y = ButtonYtoSeqY(7);
|
|
|
|
|
for (int x = 0; x < NumCols; x++)
|
|
|
|
|
if (mSequence[x, y] && mRemove[x])
|
|
|
|
|
mSequence[x, y] = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PlayBeats()
|
|
|
|
|
{
|
|
|
|
|
int y = ButtonYtoSeqY(7);
|
|
|
|
|
for (int x = 0; x < NumCols; x++)
|
|
|
|
|
if (mSequence[x, y])
|
|
|
|
|
PlayNoise(x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
{
|
|
|
|
|
if (mMode == 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
DiscardRedBeats();
|
|
|
|
|
mSequenceOffset = (mSequenceOffset + 1) % NumRows;
|
|
|
|
|
PlayBeats();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Draw()
|
|
|
|
|
{
|
|
|
|
|
ButtonBrightness[,] redgrid = new ButtonBrightness[8, 8];
|
|
|
|
|
ButtonBrightness[,] greengrid = new ButtonBrightness[8, 8];
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < 7; y++)
|
|
|
|
|
for (int x = 0; x < 8; x++)
|
|
|
|
|
if (mSequence[ButtonXtoColX(x), ButtonYtoSeqY(y)])
|
|
|
|
|
redgrid[x, y] = greengrid[x, y] = ButtonBrightness.Full;
|
|
|
|
|
|
|
|
|
|
for (int x = 0; x < 8; x++) {
|
|
|
|
|
ButtonBrightness brightness = (mSequence[ButtonXtoColX(x), ButtonYtoSeqY(7)] ? ButtonBrightness.Full : ButtonBrightness.Low);
|
|
|
|
|
|
|
|
|
|
if (!mRemove[ButtonXtoColX(x)])
|
|
|
|
|
greengrid[x, 7] = brightness;
|
|
|
|
|
else
|
|
|
|
|
redgrid[x, 7] = brightness;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < 8; y++)
|
|
|
|
|
for (int x = 0; x < 8; x++)
|
|
|
|
|
mLaunchpadDevice[x, y].SetBrightness(redgrid[x, y], greengrid[x, y]);
|
|
|
|
|
|
|
|
|
|
if (mConfirmTime > 0)
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Session).TurnOnLight();
|
|
|
|
|
else
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Session).TurnOffLight();
|
|
|
|
|
|
|
|
|
|
if (mMode == 1)
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Mixer).SetBrightness(ButtonBrightness.Full, ButtonBrightness.Off);
|
|
|
|
|
else
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Mixer).SetBrightness(ButtonBrightness.Off, ButtonBrightness.Full);
|
|
|
|
|
|
|
|
|
|
if (mSoundType == 0) {
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.SoundA).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.SoundB).TurnOffLight();
|
|
|
|
|
} else {
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.SoundA).TurnOffLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.SoundB).TurnOnLight();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Up).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Down).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Left).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(ToolbarButton.Right).TurnOnLight();
|
|
|
|
|
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.Volume).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.Pan).TurnOnLight();
|
|
|
|
|
mLaunchpadDevice.GetButton(SideButton.Arm).TurnOnLight();
|
|
|
|
|
|
|
|
|
|
mLaunchpadDevice.Refresh();
|
|
|
|
|
|
|
|
|
|
Console.SetCursorPosition(0, 0);
|
|
|
|
|
for (int y = 0; y < NumRows; y++) {
|
|
|
|
|
for (int x = 0; x < NumCols; x++) {
|
|
|
|
|
if (mSequence[x, y])
|
|
|
|
|
Console.Write("X");
|
|
|
|
|
else
|
|
|
|
|
Console.Write(".");
|
|
|
|
|
}
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|