Godtone (talk | contribs)
Godtone (talk | contribs)
Isomorphic keyboard code for launchpads with programmer mode: fix error caused by velocity going out of [0, 127] range, add a way to manually specify the midi in and midi out to use for Launchpad X, and add the ability to consider half-buttons as distinct pitches
Line 1,469: Line 1,469:
or 1 ) # minimum velocity required (else ignored)
or 1 ) # minimum velocity required (else ignored)
half = args.get('half') or args.get('h') or 40 # how many midi notes to go up from bottomleft before the velocity is halved
half = args.get('half') or args.get('h') or 40 # how many midi notes to go up from bottomleft before the velocity is halved
extra = args.get('extra') or args.get('eleven') or False # whether to consider half-buttons as distinct notes of an uneven 10x11 grid on Launchpad Pro MK3 (off by default as weird to play with)
# these are for if you want or need to keep the colour mapping distinct from the midi notes EG in large EDO subsets
# these are for if you want or need to keep the colour mapping distinct from the midi notes EG in large EDO subsets
large = args.get('large') or (not args.get('small') and max(x*9+y*8,x*8+y*9) > 127) or False
large = args.get('large') or (not args.get('small') and max(x*9+y*8,x*8+y*9) > 127) or False
coverage = 10 # for now probably don't mess with the coverage parameter
coverage = 10 # probably shouldn't mess with this unless you know what you're doing
if large:
if large:
print('WARNING: the midi note range of your layout is too large, so x=1, y='+str(coverage)+'=c=coverage is being used.')
print('WARNING: the midi note range of your layout is too large, so x=1, y='+str(coverage)+'=c=coverage is being used.')
Line 1,489: Line 1,490:
distinct_half_buttons = ( args.get('distinct_half_buttons') or args.get('distinct_halves')
distinct_half_buttons = ( args.get('distinct_half_buttons') or args.get('distinct_halves')
or args.get('distinct_buttons') or args.get('distinct') or args.get('d') # (d for double)
or args.get('distinct_buttons') or args.get('distinct') or args.get('d') # (d for double)
or False ) # whether to interpret the half-buttons as being two buttons for the same note or a single button
or False ) # whether to interpret the half-buttons as being two buttons for the same note or a single button (off by default as weird to play with)
# generate circle of nths based on gen
# generate circle of nths based on gen
g = args.get('g') or args.get('gen') or args.get('similar') or 1
g = args.get('g') or args.get('gen') or args.get('similar') or 1
Line 1,500: Line 1,501:
print(i)
print(i)
print('selecting:')
print('selecting:')
launchpad_col = args.get('col')
launchpad_col = [i for i in midi_outputs if lpselect(i)][0]
if not launchpad_col:
launchpad_col = [i for i in midi_outputs if lpselect(i)][0]
print(launchpad_col)
print(launchpad_col)
# find launchpad input (what we get midi input (mi) data from)
# find launchpad input (what we get midi input (mi) data from)
Line 1,510: Line 1,509:
print(i)
print(i)
print('selecting:')
print('selecting:')
launchpad_mi = args.get('mi')
launchpad_mi = [i for i in midi_inputs if lpselect(i)][0]
if not launchpad_mi:
launchpad_mi = [i for i in midi_inputs if lpselect(i)][0]
print(launchpad_mi)
print(launchpad_mi)
Line 1,518: Line 1,515:
def transform(midi_note):
def transform(midi_note):
if midi_note < 100:
if midi_note < 100:
return midi_note%10 * x + midi_note//10 * y + bottomleftnote
return midi_note%10 * x + midi_note//10 * y + bottomleftnote + (10 if extra else 0)
else:
else:
return (midi_note - 100) * x + bottomleftnote
return (midi_note - 100) * x + bottomleftnote
def get_midi_note(midi_note):
def get_midi_note(midi_note):
if extra and midi_note < 10:
return midi_note # bottom row of half buttons has correct mapping already
if midi_note < 100:
if midi_note < 100:
return midi_note%10 + midi_note//10 * coverage
return midi_note%10 + midi_note//10 * coverage + (10 if extra else 0)
else:
else:
return midi_note - 100
return midi_note - 100 + (10 if extra else 0)
key_codes = range(1,109) # includes a few key codes not corresponding to anything on launchpads but shouldn't be an issue.
key_codes = range(1,109) # includes a few key codes not corresponding to anything on launchpads but shouldn't be an issue.
Line 1,557: Line 1,556:
tuning_note = transform(key)
tuning_note = transform(key)
midi_note = get_midi_note(key) if large else tuning_note
midi_note = get_midi_note(key) if large else tuning_note
print('tuning:',tuning_note,'midi:',midi_note)
if note_vel: # if we're pressing a key
if note_vel: # if we're pressing a key
note_vel = round( note_vel * 2**( -(midi_note-bottomleftnote)/half ) )
note_vel = min(127,round( note_vel * 2**( -(tuning_note-bottomleftnote)/half ) ))
if note_state[tuning_note]: # if one or more equivalent keys are already held
if note_state[tuning_note]: # if one or more equivalent keys are already held
to_send = mido.Message('note_on', channel=0, note=midi_note, velocity=0)
to_send = mido.Message('note_on', channel=0, note=midi_note, velocity=0)