use pm;
use color::nearest_palette;
pub type Color = u8;
pub struct LaunchpadMk2 {
input_port: pm::InputPort,
output_port: pm::OutputPort,
midi: Option<pm::PortMidi>,
}
#[derive(Debug)]
pub struct ColorLed {
pub color: Color,
pub position: u8,
}
#[derive(Debug)]
pub struct ColorColumn {
pub color: Color,
pub column: u8,
}
#[derive(Debug)]
pub struct ColorRow {
pub color: Color,
pub row: u8,
}
pub const SCROLL_SLOWEST: &'static str = "\u{01}";
pub const SCROLL_SLOWER: &'static str = "\u{02}";
pub const SCROLL_SLOW: &'static str = "\u{03}";
pub const SCROLL_NORMAL: &'static str = "\u{04}";
pub const SCROLL_FAST: &'static str = "\u{05}";
pub const SCROLL_FASTER: &'static str = "\u{06}";
pub const SCROLL_FASTEST: &'static str = "\u{07}";
impl LaunchpadMk2 {
pub fn guess() -> LaunchpadMk2 {
let midi = pm::PortMidi::new().expect("Failed to open PortMidi Instance!");
let mut retval = Self::guess_from(&midi);
retval.midi = Some(midi);
retval
}
pub fn guess_from(midi: &pm::PortMidi) -> LaunchpadMk2 {
let devs = midi.devices().expect("Failed to get Midi Device!");
let mut input: Option<i32> = None;
let mut output: Option<i32> = None;
for d in devs {
if !d.name().contains("Launchpad MK2") {
continue;
}
if input.is_none() && d.is_input() {
input = Some(d.id() as i32);
}
if output.is_none() && d.is_output() {
output = Some(d.id() as i32);
}
if input.is_some() && output.is_some() {
break;
}
}
let input_port = input.expect("No Launchpad Mk2 Input Found!");
let output_port = output.expect("No Launchpad Mk2 Output Found!");
let input_device = midi.device(input_port)
.expect("No Launchpad Input found!");
let output_device = midi.device(output_port)
.expect("No Launchpad Output found!");
let input = midi.input_port(input_device, 1024)
.expect("Failed to open port");
let output = midi.output_port(output_device, 1024)
.expect("Failed to open port");
LaunchpadMk2 {
input_port: input,
output_port: output,
midi: None,
}
}
pub fn light_all(&mut self, color: Color) {
assert_color(color);
self.output_port
.write_sysex(0, &[0xF0, 0x00, 0x20, 0x29, 0x02, 0x18, 0x0E, color, 0xF7])
.expect("Fail");
}
pub fn flash_single(&mut self, led: &ColorLed) {
assert_position(led.position);
assert_color(led.color);
self.output_port.write_message([0x91, led.position, led.color]).expect("Fail");
}
pub fn pulse_single(&mut self, led: &ColorLed) {
self.output_port.write_message([0x92, led.position, led.color]).expect("Fail");
}
pub fn light_led(&mut self, led: &ColorLed) {
self.light_leds(&[led])
}
pub fn light_leds(&mut self, leds: &[&ColorLed]) {
assert!(leds.len() <= 80);
for led in leds {
assert_position(led.position);
assert_color(led.color);
self.output_port
.write_sysex(0,
&[0xF0,
0x00,
0x20,
0x29,
0x02,
0x18,
0x0A,
led.position,
led.color,
0xF7])
.expect("Fail");
}
}
pub fn light_column(&mut self, col: &ColorColumn) {
self.light_columns(&[col])
}
pub fn light_columns(&mut self, cols: &[&ColorColumn]) {
assert!(cols.len() <= 9);
for col in cols {
assert_column(col.column);
assert_color(col.color);
self.output_port
.write_sysex(0,
&[0xF0, 0x00, 0x20, 0x29, 0x02, 0x18, 0x0C, col.column, col.color,
0xF7])
.expect("Fail");
}
}
pub fn light_row(&mut self, row: &ColorRow) {
self.light_rows(&[row])
}
pub fn light_rows(&mut self, rows: &[&ColorRow]) {
assert!(rows.len() <= 9);
for row in rows {
assert_row(row.row);
assert_color(row.color);
self.output_port
.write_sysex(0,
&[0xF0, 0x00, 0x20, 0x29, 0x02, 0x18, 0x0D, row.row, row.color, 0xF7])
.expect("Fail");
}
}
pub fn scroll_text(&mut self, color: Color, doloop: bool, text: &str) {
assert_color(color);
let mut msg: Vec<u8> =
vec![0xF0, 0x00, 0x20, 0x29, 0x02, 0x18, 0x14, color, if doloop { 0x01 } else { 0x00 }];
msg.extend_from_slice(text.as_bytes());
msg.push(0xF7);
self.output_port.write_sysex(0, &msg).expect("Fail");
}
pub fn light_fuzzy_rgb(&mut self, position: u8, red: u8, green: u8, blue: u8) {
self.light_led(&ColorLed {
position: position,
color: nearest_palette(red, green, blue),
})
}
pub fn poll(&self) -> Option<Vec<pm::MidiEvent>> {
self.input_port.poll().expect("Closed Stream");
self.input_port.read_n(1024).expect("Failed to read")
}
}
fn assert_position(pos: u8) {
if !match pos {
11...19 => true,
21...29 => true,
31...39 => true,
41...49 => true,
51...59 => true,
61...69 => true,
71...79 => true,
81...89 => true,
104...111 => true,
_ => false,
} {
panic!("Bad Positon!")
}
}
fn assert_color(clr: u8) {
if clr > 127 {
panic!("Bad Color!");
}
}
fn assert_column(col: u8) {
if col > 8 {
panic!("Bad Column");
}
}
fn assert_row(row: u8) {
if row > 8 {
panic!("Bad Row");
}
}