Skip to content

Commit

Permalink
Merge pull request FMMT666#51 from NullMember/master
Browse files Browse the repository at this point in the history
added support for the Launchpad X
  • Loading branch information
FMMT666 committed Apr 19, 2020
2 parents aee0a9f + 6c730c0 commit 24eb466
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 18 deletions.
1 change: 1 addition & 0 deletions launchpad_py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
from launchpad_py.launchpad import LaunchKeyMini
from launchpad_py.launchpad import Dicer
from launchpad_py.launchpad import LaunchpadMk3
from launchpad_py.launchpad import LaunchpadLPX
from launchpad_py import charset
100 changes: 82 additions & 18 deletions launchpad_py/launchpad.py
Original file line number Diff line number Diff line change
Expand Up @@ -2438,23 +2438,22 @@ class LaunchpadLPX( LaunchpadPro ):

#-------------------------------------------------------------------------------------
#-- Opens one of the attached Launchpad MIDI devices.
#-- Uses search string "Mk3", by default.
#-- Uses search string "LPX", by default.
#-------------------------------------------------------------------------------------
# Overrides "LaunchpadPro" method
# TODO: Find a fix for the two MK3 MIDI devices
def Open( self, number = 0, name = "LPX" ):
retval = super( LaunchpadLPX, self ).Open( number = number, name = name )
if retval == True:
self.LedSetMode( 0 )
self.LedSetLayout( 127 )
self.LedSetMode( 1 )

return retval


#-------------------------------------------------------------------------------------
#-- Checks if a device exists, but does not open it.
#-- Does not check whether a device is in use or other, strange things...
#-- Uses search string "Pro", by default.
#-- Uses search string "LPX", by default.
#-------------------------------------------------------------------------------------
# Overrides "LaunchpadBase" method
def Check( self, number = 0, name = "LPX" ):
Expand All @@ -2464,27 +2463,24 @@ def Check( self, number = 0, name = "LPX" ):
#-------------------------------------------------------------------------------------
#-- Sets the button layout (and codes) to the set, specified by <mode>.
#-- Valid options:
#-- 00 - Session, 01 - Drum Rack, 02 - Chromatic Note, 03 - User (Drum)
#-- 04 - Audio, 05 -Fader, 06 - Record Arm, 07 - Track Select, 08 - Mute
#-- 09 - Solo, 0A - Volume
#-- Until now, we'll need the "Session" (0x00) settings.
#-- 00 - Session, 01 - Note Mode, 04 - Custom 1, 05 - Custom 2, 06 - Custom 3
#-- 07 - Custom 4, 0D - DAW Faders (available if Session enabled), 7F - Programmer
#-------------------------------------------------------------------------------------
# TODO: ASkr, Undocumented!
# TODO: return value
def LedSetLayout( self, mode ):

# TODO!
# if mode < 0 or mode > 0x0d:
# return
ValidModes = [0x00, 0x01, 0x04, 0x05, 0x06, 0x07, 0x0d, 0x7F]
if mode not in ValidModes:
return

self.midi.RawWriteSysEx( [ 0, 32, 41, 2, 12, 0, mode ] )
time.wait(10)


#-------------------------------------------------------------------------------------
#-- Selects the LPX's mode.
#-- <mode> -> 0 -> "Ableton Live mode" (what we need)
#-- 1 -> "Programmer mode" (power up default)
#-- <mode> -> 0 -> "Ableton Live mode"
#-- 1 -> "Programmer mode" (what we need)
#-------------------------------------------------------------------------------------
def LedSetMode( self, mode ):
if mode < 0 or mode > 1:
Expand All @@ -2510,6 +2506,7 @@ def LedSetButtonLayoutSession( self ):
#-- to emulate the old brightness feeling :)
#-- Notice that each message requires 10 bytes to be sent. For a faster, but
#-- unfortunately "not-RGB" method, see "LedCtrlRawByCode()"
#-- LPX color data extended to 7-bit but for compatibility we still using 6-bit values
#-------------------------------------------------------------------------------------
def LedCtrlRaw( self, number, red, green, blue = None ):

Expand All @@ -2520,13 +2517,80 @@ def LedCtrlRaw( self, number, red, green, blue = None ):
blue = 0
red *= 21
green *= 21

limit = lambda n, mini, maxi: max(min(maxi, n), mini)

red = limit( red, 0, 63 )
green = limit( green, 0, 63 )
blue = limit( blue, 0, 63 )
red = limit( red, 0, 63 ) << 1
green = limit( green, 0, 63 ) << 1
blue = limit( blue, 0, 63 ) << 1

self.midi.RawWriteSysEx( [ 0, 32, 41, 2, 12, 3, 3, number, red, green, blue ] )


#-------------------------------------------------------------------------------------
#-- Same as LedCtrlRawByCode, but with a pulsing LED.
#-- Pulsing can be stoppped by another Note-On/Off or SysEx message.
#-------------------------------------------------------------------------------------
def LedCtrlPulseByCode( self, number, colorcode = None ):

if number < 0 or number > 99:
return

if colorcode is None:
colorcode = LaunchpadPro.COLORS['white']

colorcode = min(127, max(0, colorcode))

self.midi.RawWrite( 146, number, colorcode )


#-------------------------------------------------------------------------------------
#-- Same as LedCtrlPulseByCode, but with a dual color flashing LED.
#-- The first color is the one that is already enabled, the second one is the
#-- <colorcode> argument in this method.
#-- Flashing can be stoppped by another Note-On/Off or SysEx message.
#-------------------------------------------------------------------------------------
def LedCtrlFlashByCode( self, number, colorcode = None ):

if number < 0 or number > 99:
return

if colorcode is None:
colorcode = LaunchpadPro.COLORS['white']
secondcolorcode = LaunchpadPro.COLORS['black']

colorcode = min(127, max(0, colorcode))

self.midi.RawWrite( 145, number, colorcode )


#-------------------------------------------------------------------------------------
#-- Quickly sets all all LEDs to the same color, given by <colorcode>.
#-- If <colorcode> is omitted, "white" is used.
#-------------------------------------------------------------------------------------
def LedAllOn( self, colorcode = None ):
if colorcode is None:
colorcode = LaunchpadPro.COLORS['white']

colorcode = min(127, max(0, colorcode))

for x in range(9):
for y in range(9):
self.midi.RawWrite(144, (x + 1) + ((y + 1) * 10), colorcode)


#-------------------------------------------------------------------------------------
#-- (fake to) reset the Launchpad
#-- Turns off all LEDs
#-------------------------------------------------------------------------------------
def Reset( self ):
self.LedAllOn( 0 )


#-------------------------------------------------------------------------------------
#-- Go back to custom modes before closing connection
#-- Otherwise Launchpad will stuck in programmer mode
#-------------------------------------------------------------------------------------
def Close( self ):
self.midi.CloseInput()
self.midi.CloseOutput()

0 comments on commit 24eb466

Please sign in to comment.