Skip to content

Commit 8c721e5

Browse files
committed
add lp vibrato "off" option, specific channel send, started jazz mode
1 parent aa50886 commit 8c721e5

5 files changed

Lines changed: 75 additions & 35 deletions

File tree

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ rtmidi2
55
launchpad-py
66
musicpy
77
pyyaml
8+
webcolors

scales.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
- Melodic Minor
2525
- Assyrian
2626
- Lydian Augmented
27-
- Acoustic
27+
- Acoustic # Lydian Dominant
2828
- Melodic Major
2929
- Half Dim
3030
- Altered

src/articulation.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ def __init__(self, core):
2929
self.mod_changed = True
3030
self.last_midi_message = None
3131

32-
self.mode = self.core.options.vibrato
33-
if self.mode not in ('mod', 'pitch'):
32+
self.mode = self.core.options.vibrato.lower()
33+
if self.mode in ('false', 'off'):
34+
self.mode = None
35+
elif self.mode not in ('mod', 'pitch'):
3436
print('Vibrato option must be mod or pitch. Using mod.')
3537
self.mode = 'mod'
3638
self.t = 0.0
@@ -116,7 +118,8 @@ def tick(self):
116118
if msg != self.last_midi_message:
117119
self.core.midi_write(self.core.midi_out, msg)
118120
self.last_midi_message = msg
119-
self.mod_changed = False
121+
if self.mode:
122+
self.mod_changed = False
120123

121124
# held_note_count = self.core.held_note_count()
122125
# if held_note_count == 0:

src/core.py

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@ def init_board(self):
397397
for i, note in enumerate(self.notes):
398398
self.notes[i] = Note()
399399

400+
# These are midi numbers, not indicies, so they only have to be 127
401+
self.left_chord_notes = [False] * 127
400402
self.chord_notes = [False] * 127
401403
self.note_set = set()
402404

@@ -419,7 +421,7 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
419421
msg = (data[0] & 0xF0) >> 4
420422
aftertouch = (msg == 10)
421423
if self.options.one_channel:
422-
data[0] = d0 & 0xF0 # send all to channel 0 if enabled
424+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1) # send all to channel 0 if enabled
423425
row = None
424426
col = None
425427

@@ -476,9 +478,11 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
476478
data[1] += (self.octave + self.octave_base) * 12
477479
data[1] += BASE_OFFSET
478480
midinote = data[1] - 24 + self.transpose * 2
479-
split_chan = 0
481+
side = self.channel_from_split(col, row, force=True)
480482
if self.is_split():
481-
split_chan = self.channel_from_split(col, row)
483+
split_chan = side
484+
else:
485+
split_chan = 0
482486
if not aftertouch:
483487
self.mark(midinote, 1, only_row=row)
484488
data[1] += self.out_octave * 12 + self.transpose * 2
@@ -515,9 +519,14 @@ def note_on(self, data, timestamp, width=None, curve=True, mpe=None):
515519
note.midinote = data[1]
516520
note.split = split_chan
517521

518-
self.chord_notes[data[1]] = True
519-
self.note_set.add(data[1])
520-
self.dirty_chord = True
522+
if self.options.jazz:
523+
if side == 0:
524+
self.left_chord_notes[data[1]] = True
525+
# self.dirty_left_chord = True
526+
527+
self.chord_notes[data[1]] = True
528+
self.note_set.add(data[1])
529+
self.dirty_chord = True
521530

522531
if self.is_split():
523532
if split_chan == 0:
@@ -537,7 +546,7 @@ def note_off(self, data, timestamp, width=None, mpe=None):
537546
ch = d0 & 0x0F
538547
msg = (data[0] & 0xF0) >> 4
539548
if self.options.one_channel:
540-
data[0] = d0 & 0xF0 # send all to channel 0 if enabled
549+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
541550
row = None
542551
col = None
543552

@@ -605,15 +614,26 @@ def note_off(self, data, timestamp, width=None, mpe=None):
605614
data[1] += (self.octave + self.octave_base) * 12
606615
data[1] += BASE_OFFSET
607616
midinote = data[1] - 24 + self.transpose * 2
617+
side = self.channel_from_split(col, row, force=True)
608618
if self.is_split():
609-
split_chan = self.channel_from_split(col, row)
619+
split_chan = side
620+
else:
621+
split_chan = 0
610622
self.mark(midinote, 0, only_row=row)
611623
data[1] += self.out_octave * 12 + self.transpose * 2
612624
if self.flipped:
613625
data[1] += 7
614626

627+
if self.options.jazz:
628+
if side == 0:
629+
self.left_chord_notes[data[1]] = False
630+
# self.dirty_left_chord = True
631+
615632
self.chord_notes[data[1]] = False
616-
self.note_set.remove(data[1])
633+
try:
634+
self.note_set.remove(data[1])
635+
except KeyError:
636+
pass
617637
self.dirty_chord = True
618638

619639
if self.is_split():
@@ -632,7 +652,7 @@ def device_to_xy(self, data):
632652
ch = d0 & 0x0F
633653
msg = (data[0] & 0xF0) >> 4
634654
if self.options.one_channel:
635-
data[0] = d0 & 0xF0 # send all to channel 0 if enabled
655+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
636656
row = None
637657
col = None
638658

@@ -689,7 +709,7 @@ def cb_midi_in(self, data, timestamp):
689709
ch = d0 & 0x0F
690710
msg = (data[0] & 0xF0) >> 4
691711
if self.options.one_channel:
692-
data[0] = d0 & 0xF0 # send all to channel 0 if enabled
712+
data[0] = (d0 & 0xF0) + (self.options.one_channel-1)
693713
row = None
694714
col = None
695715
if not self.options.mpe:
@@ -1055,13 +1075,14 @@ def __init__(self):
10551075
# ) or get_option(
10561076
# opts, "no_overlap", DEFAULT_OPTIONS.mpe
10571077
# )
1058-
self.options.mpe = True
10591078
self.options.vibrato = get_option(opts, "vibrato", DEFAULT_OPTIONS.vibrato)
10601079
self.options.midi_out = get_option(opts, "midi_out", DEFAULT_OPTIONS.midi_out)
10611080
self.options.split_out = get_option(
10621081
opts, "split_out", DEFAULT_OPTIONS.split_out
10631082
)
10641083
self.options.fps = get_option(opts, "fps", DEFAULT_OPTIONS.fps)
1084+
self.options.fps = get_option(opts, "jazz", DEFAULT_OPTIONS.jazz)
1085+
self.options.chord_analyzer = get_option(opts, "chord_analyzer", DEFAULT_OPTIONS.chord_analyzer)
10651086
self.split_state = self.options.split = get_option(
10661087
opts, "split", DEFAULT_OPTIONS.split
10671088
)
@@ -1423,6 +1444,7 @@ def __init__(self):
14231444
self.dirty = True
14241445
self.dirty_lights = True
14251446
self.dirty_chord = False
1447+
# self.dirty_left_chord = False
14261448

14271449
w = self.max_width
14281450
h = self.board_h
@@ -1871,28 +1893,40 @@ def logic(self, dt):
18711893
# # if self.config_save_timer <= 0.0:
18721894
# # save()
18731895

1874-
# TODO: if notes changed
1875-
if self.dirty_chord:
1876-
notes = []
1877-
for i, note in enumerate(self.chord_notes):
1878-
if note:
1879-
notes.append(NOTES[i % 12])
1880-
if notes:
1881-
self.chord = mp.alg.detect(mp.chord(','.join(notes)))
1882-
try:
1883-
self.chord = self.chord[0:self.chord.index(' sort')]
1884-
except ValueError:
1885-
pass
1886-
if self.chord.startswith('note '):
1887-
self.chord = self.chord[len('note '):-1]
1888-
else:
1889-
self.chord = ''
1890-
self.dirty_chord = False
1891-
self.dirty = True
1896+
# chord analysis for jazz mod
1897+
if self.options.jazz:
1898+
if self.dirty_chord:
1899+
self.left_chord = self.analyze(self.left_chord_notes)
1900+
1901+
# chord analyzer
1902+
if self.options.chord_analyzer:
1903+
if self.dirty_chord:
1904+
self.chord = self.analyze(self.chord_notes)
1905+
1906+
self.dirty_chord = False
18921907

18931908
if not self.options.lite:
18941909
self.gui.update(dt)
18951910

1911+
def analyze(self, chord_notes):
1912+
notes = []
1913+
r = ''
1914+
for i, note in enumerate(chord_notes):
1915+
if note:
1916+
notes.append(NOTES[i % 12])
1917+
if notes:
1918+
r = mp.alg.detect(mp.chord(','.join(notes)))
1919+
# try:
1920+
# r = r[0:self.chord.index(' sort')]
1921+
# except ValueError:
1922+
# pass
1923+
# if self.chord.startswith('note '):
1924+
# r = r[len('note '):-1]
1925+
else:
1926+
r = ''
1927+
self.dirty = True
1928+
return r
1929+
18961930
def sustainable_devices(self):
18971931
if not self.is_split() or not self.options.sustain_split:
18981932
return [self.midi_out]

src/options.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Options:
55
version: int = 0
66
lights: str = "4,7,3,7,3,3,7,3,7,3,7,3"
77
split_lights: str = "4,7,5,7,5,5,7,5,7,5,7,5"
8-
one_channel: bool = False
8+
one_channel: int = 0
99
lite: bool = False # lite mode (no gfx)
1010
velocity_curve: float = 1.0
1111
velocity_curve_low: float = 0.5
@@ -26,6 +26,8 @@ class Options:
2626
width: int = 16
2727
height: int = 8
2828
vibrato: str = 'mod'
29+
jazz: bool = False
30+
chord_analyzer: bool = True
2931

3032
DEFAULT_OPTIONS = Options()
3133

0 commit comments

Comments
 (0)