From f20e434113f2c0ca03d8514c32e7fbb3f8c7875f Mon Sep 17 00:00:00 2001 From: hijera Date: Tue, 12 Apr 2022 09:15:40 +0300 Subject: [PATCH 1/3] Added LaunchkeyMini Mk3 support (partially) --- launchpad_py/launchpad.py | 148 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/launchpad_py/launchpad.py b/launchpad_py/launchpad.py index 3e66e2a..0097040 100644 --- a/launchpad_py/launchpad.py +++ b/launchpad_py/launchpad.py @@ -17,10 +17,12 @@ # >>> # +import math import string import random import sys import array +import colorsys from pygame import midi from pygame import time @@ -2059,7 +2061,153 @@ def InputFlush( self ): def InputChanged( self ): return self.midi.ReadCheck() +######################################################################################## +### CLASS LaunchKey Mini Mk3 +### +### For multicolor LaunchKey Keyboards +######################################################################################## +class LaunchKeyMiniMk3( LaunchpadBase ): + # COLORS = {'black': 0, 'off': 0, 'white': 3, 'red': 5, 'green': 17} +# COLORS_RGB = [0:[1,1,1],1:[127,0,0],2:[1,],3:[],4:[],5:[],6:[]] + def getPadSessionMatrix(self): + return + def getPadDrumMatrix(self): + return [[40,41,42,43,48,49,50,51,52],[36,37,38,39,44,45,46,47]] + + def setDrumMode(self,mode=True): + self.drumMode=mode + def Reset(self): + if (self.drumMode): + for x in range(36,53): + self.LedCtrlRaw(x,0) + else: + for x in range(96,120): + self.LedCtrlRaw(x,0) + def Open( self, number = 0, name = "AUTO" ): + retval = super( LaunchKeyMiniMk3, self ).Open( number = number, name = name ) + nameList = [ "(Launchkey Mini MK3", "(2- Launchkey Mini MK3", "(3- Launchkey Mini MK3" ] + if name != "AUTO": + # mhh, better not this way + # nameList.insert( 0, name ) + nameList = [ name ] + for name in nameList: + rval = super( LaunchKeyMiniMk3, self ).Open( number = number, name = name ) + if rval: + self.drumMode = False + self.setDawMode() + print(self.idIn) + return rval +# self.standAloneIn=self.midi.SearchDevice('MIDIIN2.*?'+name,True,False) +# self.standAloneOut=self.midi.SearchDevice('MIDIOUT*'+name,False,True) +# print(self.standAloneIn) + return False + + def cOpen( self, number = 0, nameIn = "Launchpad" ,nameOut="Launchpad"): + LaunchpadBase.idOut = self.midi.SearchDevice( nameOut, True, False, number = number ) + LaunchpadBase.idIn = self.midi.SearchDevice( nameIn, False, True, number = number ) + if LaunchpadBase.idOut is None or LaunchpadBase.idIn is None: + return False + if self.midi.OpenOutput(LaunchpadBase.idOut) == False: + return False + return self.midi.OpenInput(LaunchpadBase.idIn) + def rawOpen(self,number=0,idIn=0,idOut=0): + LaunchpadBase.idOut = idOut + LaunchpadBase.idIn = idIn + if LaunchpadBase.idOut is None or LaunchpadBase.idIn is None: + return False + if self.midi.OpenOutput(LaunchpadBase.idOut) == False: + return False + return self.midi.OpenInput(LaunchpadBase.idIn) + def Check( self, number = 0, name = "LaunchKey Mini MK3" ): + return super( LaunchKeyMiniMk3, self ).Check( number = number, name = name ) + + def InputFlush( self ): + return self.ButtonFlush() + + def InputChanged( self ): + return self.midi.ReadCheck() + def LedCtrlXYByCode(self,x,y,colorcode): + + if (self.drumMode): + matrix=self.getPadDrumMatrix() + else: + matrix=[[96,97,98,99,100,101,102,103],[112,113,114,115,116,117,118,119]] + led =matrix[y][x] + + self.LedCtrlRaw(led, colorcode) + def LedCtrlXY(self, x, y, red, green, blue): + if x < 0 or x > 9 or y < 0 or y > 2: + return + # rotate matrix to the right, column 9 overflows from right to left, same row + if (self.drumMode): + matrix=self.getPadDrumMatrix() + else: + matrix = [[96, 97, 98, 99, 100, 101, 102, 103], [112, 113, 114, 115, 116, 117, 118, 119]] + led =matrix[y][x] +# print(str(red)+" "+str(green)+" "+str(blue)) + c_array=colorsys.rgb_to_hsv(float(red/127.0), float(green/127.0),float(blue/127.0)) + + limit = lambda n, mini, maxi: max(min(maxi, n), mini) +# print(c_array) + if (c_array[1]<=0.25 and c_array[2]<=0.25): + colorcode=round(3*c_array[2]) + colorcode=limit(colorcode,0,3) + else: + if (c_array[1] <= 0.5 and c_array[2] >= 0.5): + s=0 + else: + s=1 + v=math.ceil(4*(1-c_array[2])) + h=round(54*c_array[0]) + colorcode=h+s+v+4 +# print("colorcode:"+str(colorcode)) + self.LedCtrlRaw(led, colorcode) + def LedCtrlRawCmd(self,cmd, number,data2,channel): + self.midi.RawWrite(cmd+channel, number ,data2) + def LedCtrlRawByCode(self, number, colorcode, channel ): + + #if number < 96 or number > 103: + # return + + +# self.midi.RawWriteSysEx([0, 32, 41, 2, 13, 3, 3, number, red, green, blue]) + self.midi.RawWrite(0x90 + channel, number ,colorcode) + def setDawMode(self): + self.LedCtrlRawCmd(0x90, 12, 1, 15) + def setStandAloneMode(self): + self.midi.RawWrite(0x9F,12,0) + def LedCtrlRaw(self,number,colorcode): + if (self.drumMode): + self.midi.RawWrite(0x90+9, number ,colorcode) + else: + self.midi.RawWrite(0x90, number ,colorcode) +# self.midi.RawWriteSysEx([0, 32, 41, 2, 13, 3, 3, number, red, green, blue])) + def ButtonStateXY( self ): + if self.midi.ReadCheck(): + a = self.midi.ReadRaw() + #print(a[0][0][1]) + button_id=a[0][0][1] + matrixDrum=self.getPadDrumMatrix() + + # whatever that is, does not belong here... + if (a[0][0][1]>=36 and a[0][0][1]<=52): + if (button_id in matrixDrum[0]): + index_1 = matrixDrum[0].index(button_id) + return [index_1,0,0] + elif (button_id in matrixDrum[1]): + index_2 = matrixDrum[1].index(button_id) + return [index_2,1,0] + elif(a[0][0][1]>=96 and a[0][0][1]<=119): + x=(button_id - 96)%8 + y=int((button_id-96)/8*0.5) + + return [x,y,0] + return [] + else: + return [] + def Close(self): + super( LaunchKeyMiniMk3, self ).Close() ######################################################################################## ### CLASS Dicer ### From 540125b99e9285837c472a8dee3473ba43520768 Mon Sep 17 00:00:00 2001 From: hijera Date: Tue, 12 Apr 2022 19:20:35 +0300 Subject: [PATCH 2/3] Cleanup and fixes --- launchpad_py/launchpad.py | 100 ++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/launchpad_py/launchpad.py b/launchpad_py/launchpad.py index 0097040..0b15e77 100644 --- a/launchpad_py/launchpad.py +++ b/launchpad_py/launchpad.py @@ -2067,13 +2067,11 @@ def InputChanged( self ): ### For multicolor LaunchKey Keyboards ######################################################################################## class LaunchKeyMiniMk3( LaunchpadBase ): - # COLORS = {'black': 0, 'off': 0, 'white': 3, 'red': 5, 'green': 17} -# COLORS_RGB = [0:[1,1,1],1:[127,0,0],2:[1,],3:[],4:[],5:[],6:[]] - def getPadSessionMatrix(self): - return - def getPadDrumMatrix(self): - return [[40,41,42,43,48,49,50,51,52],[36,37,38,39,44,45,46,47]] - +### +# Most of the ids equal to Launchkey MK3 Programmers guide, so need to check if it works with Launchkey Mk3 37/49/61 +### + drumPadMatrix=[[40,41,42,43,48,49,50,51,52],[36,37,38,39,44,45,46,47]] + sessionPadMatrix=[[96,97,98,99,100,101,102,103],[112,113,114,115,116,117,118,119]] def setDrumMode(self,mode=True): self.drumMode=mode def Reset(self): @@ -2083,6 +2081,12 @@ def Reset(self): else: for x in range(96,120): self.LedCtrlRaw(x,0) + #------------------------------------------------------------------------------------- + #-- Opens one of the attached LaunchKey Mini Mk3 devices. + #-- New Launchkey requires enter DAW mode to change colors properly,and have 2 Midi channels so send noteOn trough + #-- second midi channel + #------------------------------------------------------------------------------------- + # Overrides "LaunchpadBase" method def Open( self, number = 0, name = "AUTO" ): retval = super( LaunchKeyMiniMk3, self ).Open( number = number, name = name ) nameList = [ "(Launchkey Mini MK3", "(2- Launchkey Mini MK3", "(3- Launchkey Mini MK3" ] @@ -2097,27 +2101,8 @@ def Open( self, number = 0, name = "AUTO" ): self.setDawMode() print(self.idIn) return rval -# self.standAloneIn=self.midi.SearchDevice('MIDIIN2.*?'+name,True,False) -# self.standAloneOut=self.midi.SearchDevice('MIDIOUT*'+name,False,True) -# print(self.standAloneIn) return False - def cOpen( self, number = 0, nameIn = "Launchpad" ,nameOut="Launchpad"): - LaunchpadBase.idOut = self.midi.SearchDevice( nameOut, True, False, number = number ) - LaunchpadBase.idIn = self.midi.SearchDevice( nameIn, False, True, number = number ) - if LaunchpadBase.idOut is None or LaunchpadBase.idIn is None: - return False - if self.midi.OpenOutput(LaunchpadBase.idOut) == False: - return False - return self.midi.OpenInput(LaunchpadBase.idIn) - def rawOpen(self,number=0,idIn=0,idOut=0): - LaunchpadBase.idOut = idOut - LaunchpadBase.idIn = idIn - if LaunchpadBase.idOut is None or LaunchpadBase.idIn is None: - return False - if self.midi.OpenOutput(LaunchpadBase.idOut) == False: - return False - return self.midi.OpenInput(LaunchpadBase.idIn) def Check( self, number = 0, name = "LaunchKey Mini MK3" ): return super( LaunchKeyMiniMk3, self ).Check( number = number, name = name ) @@ -2126,29 +2111,32 @@ def InputFlush( self ): def InputChanged( self ): return self.midi.ReadCheck() - def LedCtrlXYByCode(self,x,y,colorcode): + def LedCtrlXYByCode(self,x,y,colorcode): if (self.drumMode): - matrix=self.getPadDrumMatrix() + matrix=self.drumPadMatrix else: - matrix=[[96,97,98,99,100,101,102,103],[112,113,114,115,116,117,118,119]] + matrix=self.sessionPadMatrix led =matrix[y][x] - self.LedCtrlRaw(led, colorcode) + #------------------------------------------------------------------------------------- + #-- Controls a grid LED by its / coordinates and a . + #-- / 0..7 + #-- // 0..127 r g b + #-- uses custom code for conversion rgb to colorcodes + #-- Seems like, that color table is something like HSV palette + #------------------------------------------------------------------------------------- def LedCtrlXY(self, x, y, red, green, blue): if x < 0 or x > 9 or y < 0 or y > 2: return - # rotate matrix to the right, column 9 overflows from right to left, same row if (self.drumMode): - matrix=self.getPadDrumMatrix() + matrix=self.drumPadMatrix else: - matrix = [[96, 97, 98, 99, 100, 101, 102, 103], [112, 113, 114, 115, 116, 117, 118, 119]] + matrix = self.sessionPadMatrix led =matrix[y][x] -# print(str(red)+" "+str(green)+" "+str(blue)) c_array=colorsys.rgb_to_hsv(float(red/127.0), float(green/127.0),float(blue/127.0)) limit = lambda n, mini, maxi: max(min(maxi, n), mini) -# print(c_array) if (c_array[1]<=0.25 and c_array[2]<=0.25): colorcode=round(3*c_array[2]) colorcode=limit(colorcode,0,3) @@ -2160,52 +2148,56 @@ def LedCtrlXY(self, x, y, red, green, blue): v=math.ceil(4*(1-c_array[2])) h=round(54*c_array[0]) colorcode=h+s+v+4 -# print("colorcode:"+str(colorcode)) self.LedCtrlRaw(led, colorcode) - def LedCtrlRawCmd(self,cmd, number,data2,channel): - self.midi.RawWrite(cmd+channel, number ,data2) - def LedCtrlRawByCode(self, number, colorcode, channel ): - #if number < 96 or number > 103: - # return - - -# self.midi.RawWriteSysEx([0, 32, 41, 2, 13, 3, 3, number, red, green, blue]) + def LedCtrlRawByCode(self, number, colorcode, channel ): self.midi.RawWrite(0x90 + channel, number ,colorcode) + ###### + #-- Turns on DAW Mode, where color function works + #### def setDawMode(self): - self.LedCtrlRawCmd(0x90, 12, 1, 15) + self.midi.RawWrite(0x9F,12,1) + ##### + #-- Turns Standalone mode,where you cant color any pad :( (Unused for now, but must be called at Close) + #### def setStandAloneMode(self): self.midi.RawWrite(0x9F,12,0) + def LedCtrlRaw(self,number,colorcode): if (self.drumMode): self.midi.RawWrite(0x90+9, number ,colorcode) else: self.midi.RawWrite(0x90, number ,colorcode) -# self.midi.RawWriteSysEx([0, 32, 41, 2, 13, 3, 3, number, red, green, blue])) + + # ------------------------------------------------------------------------------------- + # -- Returns the raw value of the last button change (pressed/unpressed) as a list + # -- [ , , ], in which and are the buttons coordinates and + # -- is the intensity from 0..127. + # ------------------------------------------------------------------------------------- def ButtonStateXY( self ): if self.midi.ReadCheck(): a = self.midi.ReadRaw() - #print(a[0][0][1]) button_id=a[0][0][1] - matrixDrum=self.getPadDrumMatrix() - - # whatever that is, does not belong here... + matrixDrum=self.drumPadMatrix if (a[0][0][1]>=36 and a[0][0][1]<=52): if (button_id in matrixDrum[0]): index_1 = matrixDrum[0].index(button_id) - return [index_1,0,0] + return [index_1,0,a[0][0][2]] elif (button_id in matrixDrum[1]): index_2 = matrixDrum[1].index(button_id) - return [index_2,1,0] + return [index_2,1,a[0][0][2]] elif(a[0][0][1]>=96 and a[0][0][1]<=119): x=(button_id - 96)%8 y=int((button_id-96)/8*0.5) - - return [x,y,0] + return [x,y,a[0][0][2]] return [] else: return [] + #------------------------------------------------------------------------------------- + #-- Here should be setStandAloneMode called, but it must be called before destroying "midi" + #-- + #------------------------------------------------------------------------------------- def Close(self): super( LaunchKeyMiniMk3, self ).Close() ######################################################################################## From d1972d6045f96032616c8b08ae3ff6adacc77a49 Mon Sep 17 00:00:00 2001 From: hijera Date: Tue, 12 Apr 2022 20:29:23 +0300 Subject: [PATCH 3/3] Update __init__.py --- launchpad_py/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/launchpad_py/__init__.py b/launchpad_py/__init__.py index 254a25c..e2b85cd 100644 --- a/launchpad_py/__init__.py +++ b/launchpad_py/__init__.py @@ -11,4 +11,5 @@ from launchpad_py.launchpad import MidiFighter64 from launchpad_py.launchpad import MidiFighter3D from launchpad_py.launchpad import LaunchpadProMk3 +from launchpad_py.launchpad import LaunchKeyMiniMk3 from launchpad_py import charset