Skip to content

Commit 310de84

Browse files
committed
fixed split on ls200, added forced channel for launchpad
1 parent ebc5ed8 commit 310de84

2 files changed

Lines changed: 39 additions & 17 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ test.py
55
midimech.spec
66
build/
77
dist/
8+
.idea/

src/core.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -454,16 +454,20 @@ def next_free_note(self):
454454
def is_mpe(self):
455455
return self.options.one_channel == 0
456456

457-
def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
457+
def note_on(self, data, timestamp, width=None, curve=True, mpe=None, force_channel=None):
458458
# if mpe is None:
459459
# mpe = self.options.mpe
460460
d0 = data[0]
461461
# print(data)
462462
ch = d0 & 0x0F
463463
msg = (data[0] & 0xF0) >> 4
464464
aftertouch = (msg == 10)
465-
if not self.is_mpe():
465+
466+
if force_channel:
467+
data[0] = (d0 & 0xF0) + (force_channel-1)
468+
elif not self.is_mpe():
466469
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
470+
467471
row = None
468472
col = None
469473

@@ -500,6 +504,7 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
500504
# if mpe:
501505
row = data[1] // width
502506
col = data[1] % width
507+
col_full = col + (left_width if within_hardware_split else 0)
503508
if within_hardware_split:
504509
data[1] += left_width
505510
data[1] = col + 30 + 2.5 * row
@@ -520,7 +525,7 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
520525
data[1] += (self.octave + self.octave_base) * 12
521526
data[1] += BASE_OFFSET
522527
midinote = data[1] - 24 + self.transpose * 2
523-
side = self.channel_from_split(col, row, force=True)
528+
side = self.channel_from_split(col_full, row, force=True)
524529
if self.is_split():
525530
split_chan = side
526531
else:
@@ -579,16 +584,18 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
579584
else:
580585
self.midi_write(self.midi_out, data, timestamp)
581586

582-
def note_off(self, data, timestamp, width=None, mpe=None):
587+
def note_off(self, data, timestamp, width=None, mpe=None, force_channel=None):
583588
# if mpe is None:
584589
# mpe = self.options.mpe
585590

586591
d0 = data[0]
587592
# print(data)
588593
ch = d0 & 0x0F
589594
msg = (data[0] & 0xF0) >> 4
590-
if not self.is_mpe():
591-
data[0] = (d0 & 0xF0) | (self.options.one_channel-1)
595+
if force_channel:
596+
data[0] = (d0 & 0xF0) + (force_channel-1)
597+
elif not self.is_mpe():
598+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
592599
row = None
593600
col = None
594601

@@ -639,6 +646,7 @@ def note_off(self, data, timestamp, width=None, mpe=None):
639646
# data[1] += self.board_w
640647
row = data[1] // width
641648
col = data[1] % width
649+
col_full = col + (left_width if within_hardware_split else 0)
642650
if within_hardware_split:
643651
data[1] += left_width
644652
data[1] = col + 30 + 2.5 * row
@@ -656,7 +664,7 @@ def note_off(self, data, timestamp, width=None, mpe=None):
656664
data[1] += (self.octave + self.octave_base) * 12
657665
data[1] += BASE_OFFSET
658666
midinote = data[1] - 24 + self.transpose * 2
659-
side = self.channel_from_split(col, row, force=True)
667+
side = self.channel_from_split(col_full, row, force=True)
660668
if self.is_split():
661669
split_chan = side
662670
else:
@@ -687,14 +695,16 @@ def note_off(self, data, timestamp, width=None, mpe=None):
687695
self.midi_write(self.midi_out, data, timestamp)
688696
# print('note off: ', data)
689697

690-
def device_to_xy(self, data):
698+
def device_to_xy(self, data, force_channel=None):
691699
# mpe = self.options.mpe
692700

693701
d0 = data[0]
694702
ch = d0 & 0x0F
695703
msg = (data[0] & 0xF0) >> 4
696-
if not self.is_mpe():
697-
data[0] = (d0 & 0xF0) | (self.options.one_channel-1)
704+
if force_channel:
705+
data[0] = (d0 & 0xF0) + (force_channel-1)
706+
elif not self.is_mpe():
707+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
698708
row = None
699709
col = None
700710

@@ -741,7 +751,7 @@ def device_to_xy(self, data):
741751

742752
return col, row
743753

744-
def cb_midi_in(self, data, timestamp):
754+
def cb_midi_in(self, data, timestamp, force_channel=None):
745755
"""LinnStrument MIDI Callback"""
746756
# d4 = None
747757
# if len(data)==4:
@@ -751,8 +761,6 @@ def cb_midi_in(self, data, timestamp):
751761
# print(data)
752762
ch = d0 & 0x0F
753763
msg = (data[0] & 0xF0) >> 4
754-
if not self.is_mpe():
755-
data[0] = (d0 & 0xF0) | (self.options.one_channel-1)
756764
row = None
757765
col = None
758766
# if not self.options.mpe:
@@ -767,9 +775,16 @@ def cb_midi_in(self, data, timestamp):
767775
elif msg == 8: # note off
768776
self.note_off(data, timestamp)
769777
elif 0xF0 <= msg <= 0xF7: # sysex
778+
# rewrite the output channel based on app's MPE settings
770779
self.midi_write(self.midi_out, data, timestamp)
771780
else:
772781
# pitch bend
782+
# rewrite the output channel based on app's MPE settings
783+
if force_channel:
784+
data[0] = (d0 & 0xF0) + (force_channel-1)
785+
elif not self.is_mpe():
786+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
787+
773788
skip = False
774789
if msg == 14:
775790
if self.is_split():
@@ -894,7 +909,7 @@ def cb_launchpad_in(self, event, timestamp=0):
894909
vel = event[2]
895910
note = y * 8 + x
896911
if not self.is_macro_button(x, 8 - y - 1):
897-
self.note_on([160, note, event[2]], timestamp, width=8)
912+
self.note_on([160, note, event[2]], timestamp, width=8, force_channel=self.options.launchpad_channel)
898913
self.articulation.pressure(vel / 127)
899914
else:
900915
self.macro(x, 8 - y - 1, vel / 127)
@@ -905,7 +920,7 @@ def cb_launchpad_in(self, event, timestamp=0):
905920
self.reset_launchpad_light(x, y)
906921
if not self.is_macro_button(x, 8 - y - 1):
907922
note = y * 8 + x
908-
self.note_off([128, note, event[2]], timestamp, width=8)
923+
self.note_off([128, note, event[2]], timestamp, width=8, force_channel=self.options.launchpad_channel)
909924
else:
910925
self.macro(x, 8 - y - 1, False)
911926
else: # note on
@@ -915,7 +930,7 @@ def cb_launchpad_in(self, event, timestamp=0):
915930
note = y * 8 + x
916931
self.set_launchpad_light(x, y, 0) # red
917932
if not self.is_macro_button(x, 8 - y - 1):
918-
self.note_on([144, note, event[2]], timestamp, width=8)
933+
self.note_on([144, note, event[2]], timestamp, width=8, force_channel=self.options.launchpad_channel)
919934
else:
920935
self.macro(x, 8 - y - 1, True)
921936
else:
@@ -1157,14 +1172,20 @@ def __init__(self):
11571172
print("Invalid sustain split value. Options: left, right, both.")
11581173
sys.exit(1)
11591174

1175+
hardware_split = False
11601176
self.options.size = get_option(opts, "size", DEFAULT_OPTIONS.size)
11611177
if self.options.size == 128:
11621178
self.options.width = 16
11631179
elif self.options.size == 200:
11641180
self.options.width = 25
1165-
self.options.hardware_split = True
1181+
hardware_split = True
1182+
1183+
# Note: The default below is what is determined by size above.
1184+
# Overriding hardware_split is only useful for 128 user testing 200 behavior
1185+
self.options.hardware_split = get_option(opts, "hardware_split", hardware_split)
11661186

11671187
self.options.launchpad = get_option(opts, 'launchpad', True)
1188+
self.options.launchpad_channel = get_option(opts, 'launchpad_channel', 1)
11681189
self.options.experimental = get_option(opts, 'experimental', False)
11691190
self.options.debug = get_option(opts, 'debug', False)
11701191
self.options.stabilizer = get_option(opts, 'stabilizer', False)

0 commit comments

Comments
 (0)