Godtone
Joined 17 December 2020
→My Python 3 code: FIX CODE!!! (and add new features) |
ADD NEW COLOURING MODE!!! (autorelative=True on all models but relative=True on Launchpad Pro MK3 only for now (will make applicable to all in future)). ALSO: (hopefully) fix highlighting subsets for nontrivial rainbows, add 33- & 37-colour rainbows for more completeness and add notes about likely duplicate factory colors/colours found |
||
| Line 1,541: | Line 1,541: | ||
rb36br = [45, 80, 69, 49, 81, 94, 53, 82, 95, 57, 58, 120] # len-1=11 53 or 82 to be removed for smoothness; 80 to be removed for distinctness | rb36br = [45, 80, 69, 49, 81, 94, 53, 82, 95, 57, 58, 120] # len-1=11 53 or 82 to be removed for smoothness; 80 to be removed for distinctness | ||
rb36 = rb36ry[:-1] + rb36yg[:-1] + rb36gb[:-1] + rb36br[:-1] # maximal, but uneven, rainbow | rb36 = rb36ry[:-1] + rb36yg[:-1] + rb36gb[:-1] + rb36br[:-1] # maximal, but uneven, rainbow | ||
rb37 = [6] + rb36 | |||
rb35 = [c for c in rb36 if c!=126] | rb35 = [c for c in rb36 if c!=126] | ||
rb34 = [c for c in rb36 if c not in [61,62]] | rb34 = [c for c in rb36 if c not in [61,62]] | ||
| Line 1,552: | Line 1,553: | ||
rb31 = [120, 5] + rb30[1:] | rb31 = [120, 5] + rb30[1:] | ||
rb32 = [c for c in rb34 if c not in [85,96]] | rb32 = [c for c in rb34 if c not in [85,96]] | ||
rb33 = [c for c in rb34 if c!=85] | |||
rb29 = [c for c in rb30 if c!=75] | rb29 = [c for c in rb30 if c!=75] | ||
# 29 colours is a fairly ideal rainbow; we use it for indexing into, so as to derive a 17-colour palette. | # 29 colours is a fairly ideal rainbow; we use it for indexing into, so as to derive a 17-colour palette. | ||
| Line 1,564: | Line 1,566: | ||
rb25 = [c for c in rb26 if c!=74] | rb25 = [c for c in rb26 if c!=74] | ||
colmaps = { 12: rb12, 13: rb13, 16: cm16, 17: rb17v2, 18: rb18, 19: rb19, 25: rb25, 26: rb26, 27: rb27, 28: rb28, 29: rb29, 30: rb30, 31: rb31, 32: rb32, 34: rb34, 35: rb35, 36: rb36 } | colmaps = { 12: rb12, 13: rb13, 16: cm16, 17: rb17v2, 18: rb18, 19: rb19, 25: rb25, 26: rb26, 27: rb27, 28: rb28, 29: rb29, 30: rb30, 31: rb31, 32: rb32, 33: rb33, 34: rb34, 35: rb35, 36: rb36, 37: rb37 } | ||
# IMPORTANT: SUSPECTED DUPLICATE COLOURS: 45 = 67, 97 = 124, (a duplicate red i need to refind) | |||
# for example, if you're using 34 EDO and you want a 1\2 = 17\34 period | # for example, if you're using 34 EDO and you want a 1\2 = 17\34 period | ||
| Line 1,628: | Line 1,632: | ||
# use the same midi/mido output (mo) for the entire session: (the port is opened when you import the library) | # use the same midi/mido output (mo) for the entire session: (the port is opened when you import the library) | ||
mo = mido.open_output() if platform.system()!='Windows' else mido.open_output([ port for port in mido.get_output_names() if 'loop' in port ][0]) | mo = mido.open_output() if platform.system()!='Windows' else mido.open_output([ port for port in mido.get_output_names() if 'loop' in port ][0]) | ||
# IMPORTANT: to highlight a scale, use [a,b,c,...,p] where p is the number of MIDI notes corresponding to your period and a>0. | # IMPORTANT: to highlight a scale, use [a,b,c,...,p] where p is the number of MIDI notes corresponding to your period and a>0. | ||
# SEE: genindices() to generate a rank 2 scale and mode() to rotate an arbitrary scale. | # SEE: genindices() to generate a rank 2 scale and mode() to rotate an arbitrary scale. | ||
def iso(x=5, y=1, colmap_in=[34], highlight=[], **args): | def iso(x=5, y=1, colmap_in=[34], highlight=[], **args): | ||
autorelative = args.get('autorelative') or False | |||
relative = args.get('relative') or autorelative | |||
last_tuning_note = 0 | |||
global mo | global mo | ||
colmap = colmap_in # make default value immutable | colmap = colmap_in # make default value immutable | ||
| Line 1,647: | Line 1,655: | ||
print('no colmap in colmaps for',colmap,'notes; using default colmap') | print('no colmap in colmaps for',colmap,'notes; using default colmap') | ||
colmap = [4,5,6,7] | colmap = [4,5,6,7] | ||
# get arguments with default values | # get arguments with default values | ||
bottomleftnote = args.get('bottomleftnote') or args.get('blnote') or args.get('bl') or args.get('b') or 0 # WARNING: NOTE: used to be min(x,y) by default! | bottomleftnote = args.get('bottomleftnote') or args.get('blnote') or args.get('bl') or args.get('b') or 0 # WARNING: NOTE: used to be min(x,y) by default! | ||
| Line 1,684: | Line 1,688: | ||
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 | ||
colmap = circle(g,colmap) | colmap = circle(g,colmap) | ||
if highlight: # highlight subset scale | |||
highlight = sorted(list(set(highlight))) | |||
mul = math.lcm(len(colmap),highlight[-1]) | |||
colmap = [( colmap*mul )[i%len(colmap)] if i%highlight[-1] in [0]+highlight else 3 for i in range(mul)] | |||
# find launchpad output (what we send colour (col) data to) | # find launchpad output (what we send colour (col) data to) | ||
| Line 1,725: | Line 1,733: | ||
note_state[transform(k)] = 0 | note_state[transform(k)] = 0 | ||
shift_held = False | |||
with mido.open_input(launchpad_mi) as mi, mido.open_output(launchpad_col) as col: | with mido.open_input(launchpad_mi) as mi, mido.open_output(launchpad_col) as col: | ||
print('\ncolouring...') | print('\ncolouring...') | ||
| Line 1,731: | Line 1,740: | ||
note=k, velocity=colmap[ transform(k) % len(colmap) ] | note=k, velocity=colmap[ transform(k) % len(colmap) ] | ||
)) | )) | ||
print('starting midi event processing...') | print('starting midi event processing...') | ||
# transform the launchpad's midi input (mi) into custom midi output (mo) | # transform the launchpad's midi input (mi) into custom midi output (mo) | ||
| Line 1,738: | Line 1,748: | ||
note_vel = 0 | note_vel = 0 | ||
is_half_button = False | is_half_button = False | ||
is_shift = False | |||
if 'control' in str(msg): | if 'control' in str(msg): | ||
key = msg.control | key = msg.control | ||
note_vel = vel if msg.value else 0 | note_vel = vel if msg.value else 0 | ||
is_half_button = msg.control > 100 or msg.control < 10 | is_half_button = msg.control > 100 or msg.control < 10 | ||
is_shift = key==90 | |||
if is_shift: | |||
shift_held = bool(note_vel) | |||
elif str(msg).startswith('note'): | elif str(msg).startswith('note'): | ||
key = msg.note | key = msg.note | ||
| Line 1,751: | Line 1,765: | ||
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) | print('tuning:',tuning_note,'midi:',midi_note) | ||
if note_vel: # if we're pressing a key | if relative and (sum([ note_state[i] for i in note_state ])==0 and autorelative or shift_held): | ||
last_tuning_note = tuning_note | |||
# only in the situation where the last_tuning_note is set can the grid possibly be fully recoloured | |||
if autorelative or shift_held: | |||
for k in key_codes: | |||
col.send(mido.Message( 'note_on', channel=0, | |||
note=k, velocity=colmap[ (transform(k) - tuning_note) % len(colmap) ] | |||
)) | |||
if note_vel and (not is_shift or not relative or relative and autorelative): # if we're pressing a key | |||
note_vel = min(127,round( note_vel * 2**( -(tuning_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 | ||
| Line 1,771: | Line 1,793: | ||
if note_state[tuning_note]==0: # if we turn off all keys as a result... turn off | if note_state[tuning_note]==0: # if we turn off all keys as a result... turn off | ||
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) | ||
print('col='+str(colmap[ tuning_note % len(colmap) ]),to_send) | print('col='+str(colmap[ (tuning_note - last_tuning_note) % len(colmap) ]),to_send) | ||
mo.send(to_send) # turn off equivalent midi note | mo.send(to_send) # turn off equivalent midi note | ||
for k in key_codes: | for k in key_codes: | ||
if transform(k)==tuning_note: # if equivalent... set key to unpressed col | if transform(k)==tuning_note: # if equivalent... set key to unpressed col | ||
col.send(mido.Message('note_on', channel=0, | col.send(mido.Message('note_on', channel=0, | ||
note=k, velocity=colmap[ transform(k) % len(colmap) ] | note=k, velocity=colmap[ (transform(k) - last_tuning_note) % len(colmap) ] | ||
)) | )) | ||
</syntaxhighlight> | </syntaxhighlight> | ||