public LaunchpadSRenderer(MidiDevice device)
        {
            _device = device;

            // Cache id lookups
            var info = DeviceInfo.FromType(device.Type);

            _indexToMidi = new byte[256];
            _midiToIndex = new byte[256];
            for (int i = 0; i < _indexToMidi.Length; i++)
            {
                _indexToMidi[i] = 255;
            }
            for (int i = 0; i < _midiToIndex.Length; i++)
            {
                _midiToIndex[i] = 255;
            }
            for (byte y = 0; y < info.Height; y++)
            {
                for (byte x = 0; x < info.Width; x++)
                {
                    byte midi  = info.MidiLayout[info.Height - y - 1, x];
                    byte index = info.IndexLayout[info.Height - y - 1, x];
                    if (midi != 255 && index != 255)
                    {
                        _indexToMidi[index] = midi;
                        _midiToIndex[midi]  = index;
                    }
                }
            }

            // Register events
            var layoutMsg = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);

            layoutMsg[1] = 0x00;
            layoutMsg[2] = 0x01; // X-Y layout
            var clearMsg = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);

            clearMsg[1]        = 0x00;
            clearMsg[2]        = 0x00; // Clear all lights
            _device.Connected += () =>
            {
                SendBuffer(layoutMsg);
                SendBuffer(clearMsg);
                _lightsInvalidated = true;
            };
            _device.Disconnecting += () =>
            {
                SendBuffer(clearMsg);
            };

            // Create buffers
            _lights       = new Light[info.LightCount];
            _normalMsg    = Midi.CreateBuffer(MidiMessageType.NoteOn, 3, _lights.Length);
            _flashMsg     = Midi.CreateBuffer(MidiMessageType.NoteOn, 3, _lights.Length);
            _bufferMsg    = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);
            _bufferMsg[2] = 32; // Simple
        }
        public LaunchpadRGBRenderer(MidiDevice device)
        {
            _device = device;

            // Cache id lookups
            var info = DeviceInfo.FromType(device.Type);

            _indexToMidi = new byte[256];
            _midiToIndex = new byte[256];
            for (int i = 0; i < _indexToMidi.Length; i++)
            {
                _indexToMidi[i] = 255;
            }
            for (int i = 0; i < _midiToIndex.Length; i++)
            {
                _midiToIndex[i] = 255;
            }
            for (byte y = 0; y < info.Height; y++)
            {
                for (byte x = 0; x < info.Width; x++)
                {
                    byte midi  = info.MidiLayout[info.Height - y - 1, x];
                    byte index = info.IndexLayout[info.Height - y - 1, x];
                    if (midi != 255 && index != 255)
                    {
                        _indexToMidi[index] = midi;
                        _midiToIndex[midi]  = index;
                    }
                }
            }

            // Register events
            // Mode selection, Standalone mode (default)
            var modeMsg = SysEx.CreateBuffer(_device.Type, new byte[] { 0x21, 0x01 });
            // Standalone Layout select, Programmer
            var layoutMsg = SysEx.CreateBuffer(_device.Type, new byte[] { 0x2C, 0x03 });
            // Set all LEDs, color = 0
            var clearMsg = SysEx.CreateBuffer(_device.Type, new byte[] { 0x0E, 0x0 });

            _device.Connected += () =>
            {
                SendBuffer(modeMsg);
                SendBuffer(layoutMsg);
                SendBuffer(clearMsg);
                _lightsInvalidated = true;
            };
            _device.Disconnecting += () =>
            {
                SendBuffer(clearMsg);
            };

            // Create buffers
            _lights    = new Light[info.LightCount];
            _oldLights = new Light[info.LightCount];
            _clockMsg  = Midi.CreateBuffer(MidiMessageType.MidiClock, 1); // MIDI Clock
        }
        public LaunchpadSRenderer(MidiDevice device)
        {
            _device = device;

            // Cache id lookups
            var info = DeviceInfo.FromType(device.Type);

            _indexToMidi = new byte[256];
            _midiToIndex = new byte[256];
            for (int i = 0; i < _indexToMidi.Length; i++)
            {
                _indexToMidi[i] = 255;
            }
            for (int i = 0; i < _midiToIndex.Length; i++)
            {
                _midiToIndex[i] = 255;
            }
            for (byte y = 0, i = 0; y < info.Height; y++)
            {
                for (byte x = 0; x < info.Width; x++)
                {
                    byte midi = info.Layout[info.Height - y - 1, x];
                    if (midi != 255)
                    {
                        _indexToMidi[i]    = midi;
                        _midiToIndex[midi] = i;
                        i++;
                    }
                }
            }

            // Register events
            var layoutMsg = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);

            layoutMsg[1] = 0x00;
            layoutMsg[2] = 0x01; // X-Y layout
            var brightnessMsg = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);

            //layoutMsg[1] = 0x1E; // Brightness
            //layoutMsg[2] = 0x00; // 1/3 (max "safe")
            layoutMsg[1] = 0x1F; // Brightness
            layoutMsg[2] = 0x00; // 9/3
            var clearMsg = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);

            clearMsg[1]        = 0x00;
            clearMsg[2]        = 0x00; // Clear all lights
            _device.Connected += () =>
            {
                SendMidi(layoutMsg);
                SendMidi(brightnessMsg);
                SendMidi(clearMsg);
                _lightsInvalidated = true;
            };
            _device.Disconnecting += () =>
            {
                SendMidi(clearMsg);
            };

            // Create buffers
            _lights        = new Light[info.LightCount];
            _noteOn        = Midi.CreateBuffer(MidiMessageType.NoteOn, 1);
            _noteOff       = Midi.CreateBuffer(MidiMessageType.NoteOff, 1);
            _topNoteOn     = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);
            _topNoteOff    = Midi.CreateBuffer(MidiMessageType.ControlModeChange, 1);
            _topNoteOff[2] = 0x0C;
        }