launchpad-control- High and low-level interface to the Novation Launchpad midi controller.

Safe HaskellNone




A framework to create functional Launchpad "apps".

See the modules below System.MIDI.Launchpad.Apps for examples.


  • Both Ableton and the Launchpad embedded software seems to be somewhat buggy... If you experience issues, try resetting the Launchpad, try to launch Ableton and your app in the opposite order, etc...
  • ALWAYS compile with the threaded runtime (ghc option -threaded)
  • When the programs start, the Launchpad is reseted, and Session mode is assumed. Press User mode 2 to start playing with the app. Sometimes you have to press Session mode / User mode 2 a few times so that Ableton and the launchpad app thinks the same thing about the state...
  • How to setup Ableton: Use a loopback device (eg. IAC Bus 1 on OSX) to communicate between the app and Ableton. In Ableton midi setup, enable the track and remote MIDI input for the loopback device, and enable the sync MIDI output for the loopback device; disable everything else. Also disable all Launchpad MIDI inputs and outputs (it can remain a control surface).


simple colors

pure interface

data PureApp cfg mode state Source

We suppose an application can have different modes (similarly as in Ableton one can have session, session overview, different mixer modes, etc), which are basically different "screens" on the Launchpad; and also a global state. See the example applications how it is intended to be used.




pAppConfig :: cfg

application-specific configuration

pAppIniState :: (mode, state)

initial state of the application

pAppStartStop :: cfg -> Bool -> state -> state

what to do when get start or stop playing MIDI signal

pAppRender :: cfg -> mode -> state -> Maybe Int -> [(Button, Color)]

render the screen (it will optimized, don't worry)

pAppButton :: cfg -> ButtonPress -> (mode, state) -> ((mode, state), [MidiMessage'])

the user presses a button

pAppSync :: cfg -> mode -> state -> Int -> (state, [MidiMessage'])

external MIDI sync signal (24 times per quarter note)

runPureApp :: GlobalConfig -> PureApp cfg mode state -> IO ()Source

Executes a pure application

monadic interface

data MonadicApp cfg mode state Source

Monadic application (equivalent to the above pure application, but may be more convenient to use)




mAppConfig :: cfg
mAppIniState :: (mode, state)
mAppStartStop :: cfg -> Bool -> state -> state

start or stop playing

mAppRender :: cfg -> mode -> state -> Maybe Int -> RenderMonad ()

render the screen (it will optimized, don't worry); the Maybe Int is the sync signal

mAppButton :: cfg -> ButtonPress -> ButtonMonad mode state ()

the user presses a button

mAppSync :: cfg -> mode -> Int -> SyncMonad state ()

external MIDI sync signal (24 times per quarter note)

runMonadicApp :: GlobalConfig -> MonadicApp cfg mode state -> IO ()Source

Executes a monadic application

data ButtonMonad mode state a Source


getMode :: ButtonMonad mode state modeSource

setMode :: mode -> ButtonMonad mode state ()Source

class CanChangeState m whereSource


getState :: Monad (m state) => m state stateSource

setState :: Monad (m state) => state -> m state ()Source

modifyState :: (CanChangeState m, Monad (m state)) => (state -> state) -> m state ()Source

global configuration

data GlobalConfig Source

Global configuration of an app




defaultLaunchpadDevice :: String

Should be probably "Launchpad"

defaultMidiOutputDevice :: String

default output device name (eg. "IAC Bus 1")

outputChannel :: Int

The midi channel we send the messages (towards the DAW or synth)

onlyUserMode2 :: Bool

If we want to be Ableton-compatible, we should only do anything in "User mode 2"

defaultGlobalConfig :: GlobalConfigSource

A default global state