#launchpad #midi #novation #api-access #api-bindings #midi-controller #lightshow

launchy

Low-level bindings and high-level abstractions for the Novation Launchpad MIDI devices

3 releases (breaking)

0.3.0 May 2, 2023
0.2.0 Sep 16, 2021
0.1.0 Jul 11, 2020

#169 in Rendering

27 downloads per month

MIT license

170KB
3K SLoC

launchy

docs.rs crates.io License

An exhaustive Rust API for the Novation Launchpad devices, optimized for maximum expressiveness and minimum boilerplate!


Launchy is a library for the Novation Launchpad MIDI devices, for the Rust programming language.

Features

  • the Canvas API provides a powerful and concise way to control your Launchpads, for games or small lightshows
  • the direct Input/Output API provides absolute control over your device and fine-grained access to the entire MIDI API of your device
  • it's possible to chain multiple Launchpads together and use them as if it was one single big device
  • optional support for embedded-graphics
  • very modular design: it's very easy to add support for new devices, or to add new features to Canvas

Supported devices

  • Launchpad
  • Launchpad S
  • Launchpad Mini
  • Launchpad Control
  • Launchpad Control XL
  • Launchpad Pro
  • Launchpad MK2
  • Launchpad X
  • Launchpad Mini MK3
  • Launchpad Pro MK2

Canvas API

Launchy provides a Canvas trait that allows you to abstract over the hardware-specific details of your Launchpad and write concise, performant and Launchpad-agnostic code.

The Canvas API even allows you to chain multiple Launchpads together and use them as if they were a single device. See CanvasLayout for that.

Direct Input/Output API

In cases where you need direct access to your device's API, the abstraction provided by the Canvas API gets in your way.

Say if you wanted to programmatically retrieve the firmware version of your Launchpad MK2:

let input = launchy::mk2::Input::guess_polling()?;
let mut output = launchy::mk2::Output::guess()?;

output.request_version_inquiry()?;
for msg in input.iter() {
    if let launchy::mk2::Message::VersionInquiry { firmware_version, .. } = msg {
        println!("The firmware version is {}", firmware_version);
    }
}

Examples

Satisfying pulse light effect

// Setup devices
let (mut canvas, poller) = launchy::CanvasLayout::new_polling();
canvas.add_by_guess_rotated::<launchy::control::Canvas>(0, 14, launchy::Rotation::Right)?;
canvas.add_by_guess_rotated::<launchy::mk2::Canvas>(10, 18, launchy::Rotation::UpsideDown)?;
canvas.add_by_guess_rotated::<launchy::s::Canvas>(2, 8, launchy::Rotation::Right)?;
let mut canvas = canvas.into_padded();

// Do the actual animation
for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
    for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
        canvas[msg.pad()] = color * 60.0;
    }
    canvas.flush()?;

    for pad in canvas.iter() {
        let surrounding_color = pad.neighbors_5().iter()
                .map(|&p| canvas.get(p).unwrap_or(Color::BLACK))
                .sum::<Color>() / 5.0 / 1.05;

        canvas[pad] = canvas[pad].mix(surrounding_color, 0.4);
    }
}

Seamless text scrolling across multiple Launchpads (leveraging embedded_graphics)

(This image shows the first three letters of the word "Hello")

use embedded_graphics::{fonts::{Font6x8, Text}, prelude::{Drawable, Point}, style::TextStyle};

// Setup the Launchpad layout
let mut canvas = launchy::CanvasLayout::new(|_msg| {});
canvas.add_by_guess_rotated::<launchy::control::Canvas>(0, 14, launchy::Rotation::Right)?;
canvas.add_by_guess_rotated::<launchy::mk2::Canvas>(10, 18, launchy::Rotation::UpsideDown)?;
canvas.add_by_guess_rotated::<launchy::s::Canvas>(2, 8, launchy::Rotation::Right)?;

// Do the text scrolling
let mut x_offset = 19;
loop {
    canvas.clear();

    let t = Text::new("Hello world! :)", Point::new(x_offset, 3))
        .into_styled(TextStyle::new(Font6x8, Color::RED.into()))
        .draw(&mut canvas).unwrap();

    canvas.flush()?;

    sleep(100);
    x_offset -= 1;
}

Why not just use launch-rs?

  • Last commit in 2017
  • Only supports Launchpad MK2
  • Only low-level access to the Launchpad is provided. There is no way to write high-level, concise interfacing code
  • Uses the PortMidi crate which is not as actively developed as midir, which Launchy uses
  • Doesn't have any of the advanced features that Launchy provides

Dependencies

~0.2–32MB
~394K SLoC