Code Monkey home page Code Monkey logo

launchy's Introduction

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

launchy's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

launchy's Issues

[FEAT] Support for Launchpad Mini Mk3

Would love to add (even if just partial) support for the Launchpad Mini Mk3.
Using this issue to document my findings so far & any progress.

As per the manual the device has two operational modes: "Live" & "Programmer".

In order to get the device to input & output proper midi, one must:

  • Hold the Session button for 3 seconds
  • Press the Stop Solo Mute button to enter "Programmer"-mode
  • Profit, your device is now in programmer mode!

To undo, either reboot/replug your device, or:

  • Hold the Session button for 3 seconds
  • Press the > button (above Stop Solo Mute) to enter "Live"-mode (made for Ableton Live specifically)
  • Profit, you are now a regular musician again

In addition to the above I discovered the device exposes two midi devices:
image

It appears the Launchpad Mini MK3 LPMiniMK3 MI does the magic. The DA variant I have yet to figure out what its for lol

A patched version (so far but still in progress) can be found on my temporary fork at lucemans/launchy.

Hope this helps! And I will keep you updated!

Error type is no longer Sync in Linux

The following program fails to compile against the lp-mini branch:

use launchy::prelude::*;
use launchy::mini::{Input, Output, Color, Button};

fn main() -> anyhow::Result<()> {
    let mut output = Output::guess()?;

    for i in 0..4 {
        for j in 0..4 {
            output.light(Button::GridButton { x: i, y: j }, Color::new(i, j))?;
        }
    }

    Ok(())
}

Here is an excerpt of the compilation error:

error[E0277]: `*mut alsa_sys::_snd_seq` cannot be shared between threads safely                                        
 --> src/main.rs:9:39                                                                                                  
  |                                                                                                                    
9 |     let input = Input::guess_polling()?;                                                                           
  |                                       ^ `*mut alsa_sys::_snd_seq` cannot be shared between threads safely          
  |                                                                                                                    
  = help: within `MidiError`, the trait `Sync` is not implemented for `*mut alsa_sys::_snd_seq`                        
  = note: required because it appears within the type `alsa::seq::Seq`                                                 
  = note: required because it appears within the type `Option<alsa::seq::Seq>`                                         
  = note: required because it appears within the type `midir::backend::alsa::MidiInput`                                
  = note: required because it appears within the type `midir::common::MidiInput`                                       
  = note: required because it appears within the type `midir::errors::ConnectError<midir::common::MidiInput>`          
  = note: required because it appears within the type `MidiError`                                                      
  = note: required because of the requirements on the impl of `From<MidiError>` for `anyhow::Error`                    
  = note: required by `from`                                                                                           
                                                                                                                       
error[E0277]: `Cell<bool>` cannot be shared between threads safely                                                     
 --> src/main.rs:9:39                                                                                                  
  |                                                                                                                    
9 |     let input = Input::guess_polling()?;                                                                           
  |                                       ^ `Cell<bool>` cannot be shared between threads safely                       
  |                                                                                                                    
  = help: within `MidiError`, the trait `Sync` is not implemented for `Cell<bool>`                                     
  = note: required because it appears within the type `alsa::seq::Seq`                                                 
  = note: required because it appears within the type `Option<alsa::seq::Seq>`                                         
  = note: required because it appears within the type `midir::backend::alsa::MidiInput`                                
  = note: required because it appears within the type `midir::common::MidiInput`                                       
  = note: required because it appears within the type `midir::errors::ConnectError<midir::common::MidiInput>`          
  = note: required because it appears within the type `MidiError`                                                      
  = note: required because of the requirements on the impl of `From<MidiError>` for `anyhow::Error`                    
  = note: required by `from`

...

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `lp-control`

To learn more, run the command again with --verbose.

[FEAT] Add aunchpad pro

Hi, I'm Erwann, just an IT student.

I happen to own a Launchpad Pro (1st gen) and am willing to contribute.
I'm going to fork the repo and fiddle with it, as I need the Pro support anyways, but if you want I could make a PR.

See you around.

Add gitignore file

I switch between a number of editors, but one of them is VSCode which attempts to watch all non-ignored files for changes. Without a .gitignore, this includes all the files in the target directory, so it watches all dependency files for changes as well. Additionally, tools like rg use the gitignore to ignore what files to search, otherwise I continuously find results when looking for text in target/rls/debug/deps/save-analysis/launchy-b1e0490dd979d0b7.json.

Would it be possible to add a basic .gitignore so at least the target directory (and hopefully Cargo.lock) can be ignored? These are files which should never be committed to the repo, so it makes sense to have them be gitignored.

I'm opening this issue to start the discussion since when I accidentally added it in the Launchpad Mini PR, you ended up reverting that change in your lp-mini branch, so I assume you have a reason for not wanting to have one.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.