@@ -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 ]
0 commit comments