From 57529ea2beb34342f5312c666a45c1c7c69378bf Mon Sep 17 00:00:00 2001 From: Zass Date: Mon, 6 Jan 2025 14:28:12 -0800 Subject: [PATCH 1/8] fix for issue where all notes were showing as 4th octave --- src/core.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core.py b/src/core.py index 930d754..f416368 100644 --- a/src/core.py +++ b/src/core.py @@ -2317,9 +2317,10 @@ def analyze(self, chord_notes): r = '' for i, note in enumerate(chord_notes): if note: - notes.append(NOTES[i % 12]) + n = mp.degree_to_note(i) + notes.append(n) if notes: - r = mp.alg.detect(mp.chord(','.join(notes))) + r = mp.alg.detect(mp.chord(notes)) # try: # r = r[0:self.chord.index(' sort')] # except ValueError: From 34e18c589f9e31aef602399f21ddeed8b23b041c Mon Sep 17 00:00:00 2001 From: Zass Date: Mon, 6 Jan 2025 14:32:07 -0800 Subject: [PATCH 2/8] fixed typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 904b47e..7cc9e86 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ LinnStrument Community Discord: https://discord.gg/h2BcrzmTXe ## Advantages -- Notes that sound good together are closer together. Notes that sound worse are furthest apart. Mistakes will be less likely and less obvious! +- Notes that sound good together are closer together. Notes that sound worse are furthest apart. Mistakes will be less likely and more obvious! - Like the LinnStrument's layout, it is also isomorphic (the same chord and scale shapes can be played anywhere) - The most common chords and scales are far easier to play and remember than other layouts. - Extended range compared to standard +5 tuning, making room for using a split. From 7639c4f46f885f06ad56f74ce4126546a75c3570 Mon Sep 17 00:00:00 2001 From: Zass Date: Tue, 7 Jan 2025 09:47:04 -0800 Subject: [PATCH 3/8] fixed bug where odd tonics display one octave off --- src/core.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/core.py b/src/core.py index f416368..23aca85 100644 --- a/src/core.py +++ b/src/core.py @@ -478,13 +478,6 @@ def mouse_hover(self, x, y): def get_octave(self, x, y): """Get octave for x, y""" y = self.board_h - y - 1 - # if self.flipped: - # if self.tonic % 2 == 0: - # y -= 1 - # octave = int(x + 4 + self.position.x + y * 2.5) // 6 - # else: - if self.tonic % 2: - y -= 1 octave = int(x + 4 + self.position.x + y * 2.5) // 6 return octave From b8ba0540945b386f3b6c488ff7a39818343ec583 Mon Sep 17 00:00:00 2001 From: Zass Date: Fri, 10 Jan 2025 12:53:24 -0800 Subject: [PATCH 4/8] fixed bug where keys on edge wouldn't light up after move pressed --- src/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core.py b/src/core.py index 23aca85..80496e6 100644 --- a/src/core.py +++ b/src/core.py @@ -2017,7 +2017,7 @@ def mark(self, midinote, state, use_lights=False, only_row=None): y = 0 for row in rows: x = 0 - for x in range(len(row)): + for x in range(-1 * self.position.x, len(row)-self.position.x): #this band aids bug for 1 move right idx = self.get_note_index(x, y, transpose=False) # print(x, y, midinote%12, idx) if midinote % 12 == idx: @@ -2164,10 +2164,10 @@ def logic(self, dt): self.dirty = self.dirty_lights = True self.clear_marks(use_lights=False) elif ev.ui_element == self.btn_move_left: - self.move_board(-1) + self.move_board(1) self.clear_marks(use_lights=False) elif ev.ui_element == self.btn_move_right: - self.move_board(1) + self.move_board(-1) self.clear_marks(use_lights=False) # elif ev.ui_element == self.btn_mode: # # TODO: toggle mode From c108210c702e9df074a0070180401ec0e54269ea Mon Sep 17 00:00:00 2001 From: Zass Date: Fri, 10 Jan 2025 14:11:44 -0800 Subject: [PATCH 5/8] implemented sharps/flats toggle --- src/constants.py | 5 ++++- src/core.py | 23 +++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/constants.py b/src/constants.py index a8c4b66..9c50940 100644 --- a/src/constants.py +++ b/src/constants.py @@ -2,7 +2,10 @@ TITLE = "midimech" # FOCUS = False -NOTES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] +#U+1D12C flat +#1D130 sharp +NOTES_SHARPS = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] +NOTES_FLATS = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"] WHOLETONE = True FONT_SZ = 32 BRIGHTNESS = 0.4 diff --git a/src/core.py b/src/core.py index 80496e6..33c2e7d 100644 --- a/src/core.py +++ b/src/core.py @@ -93,6 +93,15 @@ def next_mode(self, ofs=1): self.set_mode((self.mode_index + ofs) % self.scale_notes.count('x')) self.dirty = self.dirty_lights = True + def toggle_sharps_flats(self, ofs=1): + if (self.use_sharps): + self.use_sharps = False + self.NOTES = NOTES_FLATS + else: + self.use_sharps = True + self.NOTES = NOTES_SHARPS + self.dirty = self.dirty_lights = True + def prev_scale(self, ofs=1): self.next_scale(-ofs) @@ -324,7 +333,7 @@ def get_note_index(self, x, y, transpose=True): y = self.board_h - y - 1 x += self.options.base_offset tr = self.tonic if transpose else 0 - return (row_offset * y + column_offset * x + tr) % len(NOTES) + return (row_offset * y + column_offset * x + tr) % len(self.NOTES) # ofs = (self.board_h - y) // 2 + BASE_OFFSET # step = 2 if WHOLETONE else 1 # tr = self.tonic if transpose else 0 @@ -335,7 +344,7 @@ def get_note_index(self, x, y, transpose=True): def get_note(self, x, y, transpose=True): """Get note name for x, y""" - return NOTES[self.get_note_index(x, y, transpose=transpose)] + return self.NOTES[self.get_note_index(x, y, transpose=transpose)] def get_color(self, x, y): """Get color for x, y""" @@ -1629,6 +1638,11 @@ def __init__(self): text='MOD>', manager=self.gui ) + self.btn_sharps_flats = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((bs.x * 16 + 2, y), (bs.x, bs.y)), + text='#/b', + manager=self.gui + ) # self.next_scale = pygame_gui.elements.UIButton( # relative_rect=pygame.Rect((bs.x * 11 + 2, y), (bs.x, bs.y)), # text='SCL>', @@ -1695,6 +1709,9 @@ def __init__(self): self.linn_out = None self.midi_out = None self.split_out = None + self.use_sharps = True + self.NOTES = NOTES_SHARPS + outnames = rtmidi2.get_out_ports() for i in range(len(outnames)): @@ -2223,6 +2240,8 @@ def logic(self, dt): self.next_mode() elif ev.ui_element == self.btn_prev_mode: self.prev_mode() + elif ev.ui_element == self.btn_sharps_flats: + self.toggle_sharps_flats() # elif ev.type == pygame_gui.UI_HORIZONTAL_SLIDER_MOVED: # if ev.ui_element == self.slider_velocity: # global self.options.velocity_curve From b4f9e14c8fb3e3036aed2d00a8d7edef85b0a1c2 Mon Sep 17 00:00:00 2001 From: Zass Date: Mon, 13 Jan 2025 15:49:14 -0800 Subject: [PATCH 6/8] updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7cc9e86..7081076 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ That being said, I hope you enjoy it and have fun! ### Windows -- [Download (Win)](https://github.com/flipcoder/midimech/releases) +- [Download (Win)](https://github.com/zass30/midimech/releases) After downloading, make sure to follow the instructions under `Setup`. @@ -87,7 +87,7 @@ After downloading, make sure to follow the instructions under `Setup`. - Download the project by typing the following commands in terminal: ``` -git clone https://github.com/flipcoder/midimech +git clone https://github.com/zass30/midimech ``` - Switch to the new project folder: From 879f2bbdb494e694e3c82f1492d74a7935a2e092 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 28 Jan 2025 19:54:57 +0000 Subject: [PATCH 7/8] Ensure MIDI CC & Pressure messages go to correct midi output (midi_out or split_out) --- src/core.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core.py b/src/core.py index 33c2e7d..6be41c9 100644 --- a/src/core.py +++ b/src/core.py @@ -1056,11 +1056,8 @@ def cb_midi_in(self, data, timestamp, force_channel=None): # self.midi_write(self.split_out, data, timestamp) # else: # self.midi_write(self.midi_out, data, timestamp) - elif note and note.location is not None: - col = note.location.x - row = note.location.y - split_chan = self.channel_from_split(col, row) - if split_chan: + elif note and note.split is not None: + if note.split: self.midi_write(self.split_out, data, timestamp) else: self.midi_write(self.midi_out, data, timestamp) From f8da9dcbe9c47bcd6b8589b20d0525815190c39c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 28 Jan 2025 19:56:00 +0000 Subject: [PATCH 8/8] Add Explicit Quit button Improve UX, to prompt user to explicitly quit and reset state of connected device --- src/core.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core.py b/src/core.py index 6be41c9..eeaa1fb 100644 --- a/src/core.py +++ b/src/core.py @@ -1638,6 +1638,11 @@ def __init__(self): self.btn_sharps_flats = pygame_gui.elements.UIButton( relative_rect=pygame.Rect((bs.x * 16 + 2, y), (bs.x, bs.y)), text='#/b', + manager=self.gui + ) + self.btn_quit = pygame_gui.elements.UIButton( + relative_rect=pygame.Rect((bs.x * 17 + 2, y), (bs.x, bs.y)), + text='QUIT', manager=self.gui ) # self.next_scale = pygame_gui.elements.UIButton( @@ -2239,6 +2244,8 @@ def logic(self, dt): self.prev_mode() elif ev.ui_element == self.btn_sharps_flats: self.toggle_sharps_flats() + elif ev.ui_element == self.btn_quit: + self.quit() # elif ev.type == pygame_gui.UI_HORIZONTAL_SLIDER_MOVED: # if ev.ui_element == self.slider_velocity: # global self.options.velocity_curve