From 42dd8412a77677f3300771b8783623ec90fc5330 Mon Sep 17 00:00:00 2001 From: stephen322 Date: Fri, 13 Oct 2023 11:42:24 -0400 Subject: [PATCH 1/6] Reorganise midi parsing --- visualizer.py | 87 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/visualizer.py b/visualizer.py index 884c92b..658bcbd 100755 --- a/visualizer.py +++ b/visualizer.py @@ -158,7 +158,7 @@ def log_unhandled_exception(exc_type, exc_value, exc_traceback): midiports.last_activity = time.time() hotspot.hotspot_script_time = time.time() -last_control_change = 0 +last_sustain = 0 pedal_deadzone = 10 ledshow_timestamp = time.time() color_mode_name = "" @@ -335,7 +335,7 @@ def start_webserver(): if ledsettings.mode == "Velocity" or ledsettings.mode == "Pedal": # If sustain pedal is off and note is off, turn off fade processing - if int(last_control_change) < pedal_deadzone and ledstrip.keylist_status[n] == 0: + if int(last_sustain) < pedal_deadzone and ledstrip.keylist_status[n] == 0: ledstrip.keylist[n] = 0 red, green, blue = (0, 0, 0) led_changed = True @@ -375,44 +375,17 @@ def start_webserver(): print(e) midiports.last_activity = time.time() - note = find_between(str(msg), "note=", " ") - original_note = note - note = int(note) - if "note_off" in str(msg): - velocity = 0 - else: - velocity = find_between(str(msg), "velocity=", " ") - - control_change = find_between(str(msg), "value=", " ") - if control_change: - last_control_change = control_change - - if ledsettings.sequence_active: - - control = find_between(str(msg), "control=", " ") - value = find_between(str(msg), "value=", " ") - try: - if "+" in ledsettings.next_step: - if int(value) > int(ledsettings.next_step) and control == ledsettings.control_number: - ledsettings.set_sequence(0, 1) - else: - if int(value) < int(ledsettings.next_step) and control == ledsettings.control_number: - ledsettings.set_sequence(0, 1) - except TypeError as e: - pass - except Exception as e: - print(f"An unexpected exception occurred: {e}") - traceback.print_exc() - # changing offset to adjust the distance between the LEDs to the key spacing - note_position = get_note_position(note, ledstrip, ledsettings) - if (note_position >= ledstrip.led_number or note_position < 0) and control_change is False: - continue - - elapsed_time = time.time() - saving.start_time + # when a note is lifted (off) + # midi note off can be triggered 2 ways: note_off or note_on with velocity 0 + if (msg.type == "note_off" or (msg.type == "note_on" and msg.velocity == 0)) and ledsettings.mode != "Disabled": + velocity = 0 + # changing offset to adjust the distance between the LEDs to the key spacing + note_position = get_note_position(msg.note, ledstrip, ledsettings) + if note_position >= ledstrip.led_number or note_position < 0: + continue - if int(velocity) == 0 and int(note) > 0 and ledsettings.mode != "Disabled": # when a note is lifted (off) ledstrip.keylist_status[note_position] = 0 if ledsettings.mode == "Fading": ledstrip.keylist[note_position] = 1000 @@ -435,8 +408,15 @@ def start_webserver(): ledstrip.set_adjacent_colors(note_position, Color(0, 0, 0), False) if saving.is_recording: - saving.add_track("note_off", original_note, velocity, midiports.last_activity) - elif int(velocity) > 0 and int(note) > 0 and ledsettings.mode != "Disabled": # when a note is pressed + saving.add_track("note_off", msg.note, velocity, midiports.last_activity) + + # when a note is pressed + elif msg.type == 'note_on' and msg.velocity > 0 and ledsettings.mode != "Disabled": + velocity = msg.velocity + note_position = get_note_position(msg.note, ledstrip, ledsettings) + if note_position >= ledstrip.led_number or note_position < 0: + continue + color = color_mode.NoteOn(msg, None, note_position) if color is not None: red, green, blue = color @@ -484,15 +464,34 @@ def start_webserver(): # Saving if saving.is_recording: if ledsettings.color_mode == "Multicolor": - saving.add_track("note_on", original_note, velocity, midiports.last_activity, + saving.add_track("note_on", msg.note, velocity, midiports.last_activity, wc.rgb_to_hex((red, green, blue))) else: - saving.add_track("note_on", original_note, velocity, midiports.last_activity) + saving.add_track("note_on", msg.note, velocity, midiports.last_activity) # Midi control change event - else: - control = find_between(str(msg), "control=", " ") - value = find_between(str(msg), "value=", " ") + elif msg.type == "control_change": + control = msg.control + value = msg.value + + # midi control 64 = sustain pedal + if control == 64: + last_sustain = value + + if ledsettings.sequence_active and ledsettings.next_step is not None: + try: + if "+" in ledsettings.next_step: + if int(value) > int(ledsettings.next_step) and control == ledsettings.control_number: + ledsettings.set_sequence(0, 1) + else: + if int(value) < int(ledsettings.next_step) and control == ledsettings.control_number: + ledsettings.set_sequence(0, 1) + except TypeError as e: + pass + except Exception as e: + print(f"An unexpected exception occurred: {e}") + traceback.print_exc() + if saving.is_recording: saving.add_control_change("control_change", 0, control, value, midiports.last_activity) From 7447cdc611b1b83d6df602a29fbc31a6cce6f26e Mon Sep 17 00:00:00 2001 From: stephen322 Date: Fri, 13 Oct 2023 11:46:02 -0400 Subject: [PATCH 2/6] SaveMidi: Fix midi start time to first note --- lib/savemidi.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/savemidi.py b/lib/savemidi.py index d08493e..e639b9a 100644 --- a/lib/savemidi.py +++ b/lib/savemidi.py @@ -54,12 +54,9 @@ def save(self, filename): self.mid = MidiFile(None, None, 0, 20000) # 20000 is a ticks_per_beat value self.track = MidiTrack() self.mid.tracks.append(self.track) - previous_message_time = None + previous_message_time = self.first_note_time for message in multicolor_track: - if previous_message_time is not None: - time_delay = message[1] - previous_message_time - else: - time_delay = 0 + time_delay = message[1] - previous_message_time previous_message_time = message[1] if message[0] == "note": From 1c582fcdff2b0dcc5f661afc6514743e78779a76 Mon Sep 17 00:00:00 2001 From: stephen322 Date: Fri, 13 Oct 2023 12:43:42 -0400 Subject: [PATCH 3/6] Add incoming midi timestamps via mido callback This allows tracking the accurate time a midi event came in, instead of waiting to timestamp in our potentially slow or laggy event loop. Also needs a non-thread-blocking led render. Needed for accurate midi file recording. --- lib/functions.py | 7 ++++--- lib/learnmidi.py | 6 +++++- lib/midiports.py | 18 ++++++++++++------ visualizer.py | 28 +++++++++++----------------- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/lib/functions.py b/lib/functions.py index ffb5dee..caaf4c9 100644 --- a/lib/functions.py +++ b/lib/functions.py @@ -59,7 +59,7 @@ def shift(lst, num_shifts): def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): - midiports.pending_queue.append(mido.Message('note_on')) + midiports.midifile_queue.append((mido.Message('note_on'), time.time())) if song_path in saving.is_playing_midi.keys(): menu.render_message(song_path, "Already playing", 2000) @@ -94,14 +94,15 @@ def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): if delay < 0: delay = 0 + msg_timestamp = time.time() + delay if delay > 0: time.sleep(delay) if not message.is_meta: midiports.playport.send(message) - midiports.pending_queue.append(message.copy(time=0)) + midiports.midifile_queue.append((message.copy(time=0), msg_timestamp)) else: - midiports.pending_queue.clear() + midiports.midifile_queue.clear() strip = ledstrip.strip fastColorWipe(strip, True, ledsettings) break diff --git a/lib/learnmidi.py b/lib/learnmidi.py index e0583ea..f72226e 100644 --- a/lib/learnmidi.py +++ b/lib/learnmidi.py @@ -350,7 +350,11 @@ def learn_midi(self): wrong_notes = [] self.predict_future_notes(absolute_idx, end_idx, notes_to_press) while not set(notes_to_press).issubset(notes_pressed) and self.is_started_midi: - for msg_in in self.midiports.inport.iter_pending(): + while self.midiports.midi_queue: + msg_in, msg_timestamp = self.midiports.midi_queue.popleft() + if msg_in.type not in ("note_on", "note_off"): + continue + note = int(find_between(str(msg_in), "note=", " ")) if "note_off" in str(msg_in): diff --git a/lib/midiports.py b/lib/midiports.py index 11f5836..a29d347 100644 --- a/lib/midiports.py +++ b/lib/midiports.py @@ -1,21 +1,24 @@ import mido from lib import connectall import time +from collections import deque class MidiPorts: def __init__(self, usersettings): self.usersettings = usersettings - self.pending_queue = [] + # midi queues will contain a tuple (midi_msg, timestamp) + self.midifile_queue = deque() + self.midi_queue = deque() self.last_activity = 0 self.inport = None self.playport = None - self.midipending = [] + self.midipending = None # checking if the input port was previously set by the user port = self.usersettings.get_setting_value("input_port") if port != "default": try: - self.inport = mido.open_input(port) + self.inport = mido.open_input(port, callback=self.msg_callback) print("Inport loaded and set to " + port) except: print("Can't load input port: " + port) @@ -24,7 +27,7 @@ def __init__(self, usersettings): try: for port in mido.get_input_names(): if "Through" not in port and "RPi" not in port and "RtMidOut" not in port and "USB-USB" not in port: - self.inport = mido.open_input(port) + self.inport = mido.open_input(port, callback=self.msg_callback) self.usersettings.change_setting_value("input_port", port) print("Inport set to " + port) break @@ -66,7 +69,7 @@ def change_port(self, port, portname): destroy_old = None if port == "inport": destory_old = self.inport - self.inport = mido.open_input(portname) + self.inport = mido.open_input(portname, callback=self.msg_callback) self.usersettings.change_setting_value("input_port", portname) elif port == "playport": destory_old = self.playport @@ -84,7 +87,7 @@ def reconnect_ports(self): try: destroy_old = self.inport port = self.usersettings.get_setting_value("input_port") - self.inport = mido.open_input(port) + self.inport = mido.open_input(port, callback=self.msg_callback) if destroy_old is not None: time.sleep(0.002) destroy_old.close() @@ -99,3 +102,6 @@ def reconnect_ports(self): destroy_old.close() except: print("Can't reconnect play port: " + port) + + def msg_callback(self, msg): + self.midi_queue.append((msg, time.time())) diff --git a/visualizer.py b/visualizer.py index 658bcbd..da9073b 100755 --- a/visualizer.py +++ b/visualizer.py @@ -355,18 +355,15 @@ def start_webserver(): ledstrip.set_adjacent_colors(n, Color(int(red), int(green), int(blue)), False, fading) # Prep midi event queue - try: - if len(saving.is_playing_midi) == 0 and learning.is_started_midi is False: - if hasattr(midiports.inport, 'iter_pending') and callable(midiports.inport.iter_pending): - midiports.midipending = midiports.inport.iter_pending() - else: - midiports.midipending = midiports.pending_queue - except Exception as e: - print(f"Unexpected exception occurred: {e}") - traceback.print_exc() + if len(saving.is_playing_midi) == 0 and learning.is_started_midi is False: + midiports.midipending = midiports.midi_queue + else: + midiports.midipending = midiports.midifile_queue # loop through incoming midi messages - for msg in midiports.midipending: + while midiports.midipending: + msg, msg_timestamp = midiports.midipending.popleft() + if int(usersettings.get_setting_value("midi_logging")) == 1: if not msg.is_meta: try: @@ -376,7 +373,6 @@ def start_webserver(): midiports.last_activity = time.time() - # when a note is lifted (off) # midi note off can be triggered 2 ways: note_off or note_on with velocity 0 if (msg.type == "note_off" or (msg.type == "note_on" and msg.velocity == 0)) and ledsettings.mode != "Disabled": @@ -408,7 +404,7 @@ def start_webserver(): ledstrip.set_adjacent_colors(note_position, Color(0, 0, 0), False) if saving.is_recording: - saving.add_track("note_off", msg.note, velocity, midiports.last_activity) + saving.add_track("note_off", msg.note, velocity, msg_timestamp) # when a note is pressed elif msg.type == 'note_on' and msg.velocity > 0 and ledsettings.mode != "Disabled": @@ -464,10 +460,10 @@ def start_webserver(): # Saving if saving.is_recording: if ledsettings.color_mode == "Multicolor": - saving.add_track("note_on", msg.note, velocity, midiports.last_activity, + saving.add_track("note_on", msg.note, velocity, msg_timestamp, wc.rgb_to_hex((red, green, blue))) else: - saving.add_track("note_on", msg.note, velocity, midiports.last_activity) + saving.add_track("note_on", msg.note, velocity, msg_timestamp) # Midi control change event elif msg.type == "control_change": @@ -493,14 +489,12 @@ def start_webserver(): traceback.print_exc() if saving.is_recording: - saving.add_control_change("control_change", 0, control, value, midiports.last_activity) + saving.add_control_change("control_change", 0, control, value, msg_timestamp) color_mode.MidiEvent(msg, None, ledstrip) # Save event-loop update saving.restart_time() - if len(saving.is_playing_midi) > 0: - midiports.pending_queue.remove(msg) # Update ledstrip ledstrip.strip.show() From b33a0db4fd595a6febfff47782ad9078cbc4420e Mon Sep 17 00:00:00 2001 From: stephen322 Date: Sat, 14 Oct 2023 13:26:10 -0400 Subject: [PATCH 4/6] Use rpi-ws281x releaseGIL if available --- lib/ledstrip.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ledstrip.py b/lib/ledstrip.py index 53de530..97a61e1 100644 --- a/lib/ledstrip.py +++ b/lib/ledstrip.py @@ -36,6 +36,8 @@ def __init__(self, usersettings, ledsettings): self.LED_BRIGHTNESS, self.LED_CHANNEL, ws.WS2811_STRIP_GRB) # Intialize the library (must be called once before other functions). self.strip.begin() + if "releaseGIL" in dir(self.strip): + self.strip.releaseGIL() self.change_gamma(self.led_gamma) def change_gamma(self, value): From 7a41a4c1a00eb7e45e465a403eca05d5bd25fbf1 Mon Sep 17 00:00:00 2001 From: stephen322 Date: Sun, 15 Oct 2023 13:19:10 -0400 Subject: [PATCH 5/6] Change midi timestamps and playing/saving timestamps to time.perf_counter() --- lib/functions.py | 20 ++++++++++---------- lib/midiports.py | 2 +- lib/savemidi.py | 4 ++-- visualizer.py | 17 ++++++++--------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/functions.py b/lib/functions.py index caaf4c9..cd6007e 100644 --- a/lib/functions.py +++ b/lib/functions.py @@ -59,7 +59,7 @@ def shift(lst, num_shifts): def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): - midiports.midifile_queue.append((mido.Message('note_on'), time.time())) + midiports.midifile_queue.append((mido.Message('note_on'), time.perf_counter())) if song_path in saving.is_playing_midi.keys(): menu.render_message(song_path, "Already playing", 2000) @@ -81,10 +81,10 @@ def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): for message in mid: if song_path in saving.is_playing_midi.keys(): if not t0: - t0 = time.time() + t0 = time.perf_counter() total_delay += message.time - current_time = (time.time() - t0) + message.time + current_time = (time.perf_counter() - t0) + message.time drift = total_delay - current_time if drift < 0: @@ -94,7 +94,7 @@ def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): if delay < 0: delay = 0 - msg_timestamp = time.time() + delay + msg_timestamp = time.perf_counter() + delay if delay > 0: time.sleep(delay) if not message.is_meta: @@ -106,8 +106,8 @@ def play_midi(song_path, midiports, saving, menu, ledsettings, ledstrip): strip = ledstrip.strip fastColorWipe(strip, True, ledsettings) break - print('play time: {:.2f} s (expected {:.2f})'.format(time.time() - t0, total_delay)) - # print('play time: {:.2f} s (expected {:.2f})'.format(time.time() - t0, length)) + print('play time: {:.2f} s (expected {:.2f})'.format(time.perf_counter() - t0, total_delay)) + # print('play time: {:.2f} s (expected {:.2f})'.format(time.perf_counter() - t0, length)) # saving.is_playing_midi = False except FileNotFoundError: menu.render_message(song_path, "File not found", 2000) @@ -202,14 +202,14 @@ def screensaver(menu, midiports, saving, ledstrip, ledsettings): while True: manage_idle_animation(ledstrip, ledsettings, menu) - if (time.time() - saving.start_time) > 3600 and delay < 0.5 and menu.screensaver_is_running is False: + if (time.perf_counter() - saving.start_time) > 3600 and delay < 0.5 and menu.screensaver_is_running is False: delay = 0.9 interval = 5 / float(delay) cpu_history = [None] * int(interval) cpu_average = 0 i = 0 - if int(menu.screen_off_delay) > 0 and ((time.time() - saving.start_time) > (int(menu.screen_off_delay) * 60)): + if int(menu.screen_off_delay) > 0 and ((time.perf_counter() - saving.start_time) > (int(menu.screen_off_delay) * 60)): menu.screen_status = 0 GPIO.output(24, 0) @@ -277,7 +277,7 @@ def screensaver(menu, midiports, saving, ledstrip, ledsettings): try: if str(midiports.inport.poll()) != "None": menu.screensaver_is_running = False - saving.start_time = time.time() + saving.start_time = time.perf_counter() menu.screen_status = 1 GPIO.output(24, 1) midiports.reconnect_ports() @@ -288,7 +288,7 @@ def screensaver(menu, midiports, saving, ledstrip, ledsettings): pass if GPIO.input(KEY2) == 0: menu.screensaver_is_running = False - saving.start_time = time.time() + saving.start_time = time.perf_counter() menu.screen_status = 1 GPIO.output(24, 1) midiports.reconnect_ports() diff --git a/lib/midiports.py b/lib/midiports.py index a29d347..509d002 100644 --- a/lib/midiports.py +++ b/lib/midiports.py @@ -104,4 +104,4 @@ def reconnect_ports(self): print("Can't reconnect play port: " + port) def msg_callback(self, msg): - self.midi_queue.append((msg, time.time())) + self.midi_queue.append((msg, time.perf_counter())) diff --git a/lib/savemidi.py b/lib/savemidi.py index e639b9a..ba426b2 100644 --- a/lib/savemidi.py +++ b/lib/savemidi.py @@ -13,7 +13,7 @@ def __init__(self): self.menu = None self.is_recording = False self.is_playing_midi = {} - self.start_time = time.time() + self.start_time = time.perf_counter() def add_instance(self, menu): self.menu = menu @@ -75,4 +75,4 @@ def save(self, filename): self.menu.render_message("File saved", filename + ".mid", 1500) def restart_time(self): - self.start_time = time.time() + self.start_time = time.perf_counter() diff --git a/visualizer.py b/visualizer.py index da9073b..b3578ac 100755 --- a/visualizer.py +++ b/visualizer.py @@ -192,9 +192,9 @@ def start_webserver(): manage_hotspot(hotspot, usersettings, midiports, True) # Frame rate counters -event_loop_stamp = time.time() +event_loop_stamp = time.perf_counter() frame_count = 0 -frame_avg_stamp = time.time() +frame_avg_stamp = time.perf_counter() # Main event loop @@ -204,7 +204,7 @@ def start_webserver(): if (time.time() - midiports.last_activity) > (int(menu.screensaver_delay) * 60): screensaver(menu, midiports, saving, ledstrip, ledsettings) try: - elapsed_time = time.time() - saving.start_time + elapsed_time = time.perf_counter() - saving.start_time except Exception as e: # Handle any other unexpected exceptions here print(f"Unexpected exception occurred: {e}") @@ -501,11 +501,12 @@ def start_webserver(): # Frame time calculations - # time taken for the last interation of the main event loop - event_loop_time = time.time() - event_loop_stamp + # time taken for the last iteration of the main event loop + event_loop_time = time.perf_counter() - event_loop_stamp + event_loop_stamp = time.perf_counter() frame_count += 1 - frame_seconds = time.time() - frame_avg_stamp + frame_seconds = time.perf_counter() - frame_avg_stamp # calculate fps average over 2 seconds if frame_seconds >= 2: @@ -513,7 +514,5 @@ def start_webserver(): ledstrip.current_fps = fps # reset counters - frame_avg_stamp = time.time() + frame_avg_stamp = time.perf_counter() frame_count = 0 - - event_loop_stamp = time.time() From b2b9656cd0a67453213514fd0458e0454f894d8c Mon Sep 17 00:00:00 2001 From: stephen322 Date: Sun, 15 Oct 2023 14:37:42 -0400 Subject: [PATCH 6/6] Pass midi timestamp to color_mode --- lib/color_mode.py | 16 ++++++++-------- visualizer.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/color_mode.py b/lib/color_mode.py index c33be8d..c1c1a7b 100644 --- a/lib/color_mode.py +++ b/lib/color_mode.py @@ -40,7 +40,7 @@ def LoadSettings(self, ledsettings): """Called whenever settings change""" pass - def NoteOn(self, midi_event, midi_state, note_position): + def NoteOn(self, midi_event, midi_time, midi_state, note_position): """Primary high-level function for ColorMode Called on midi note-on @@ -74,7 +74,7 @@ def LoadSettings(self, ledsettings): self.green = ledsettings.get_color("Green") self.blue = ledsettings.get_color("Blue") - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): return (self.red, self.green, self.blue) @@ -85,7 +85,7 @@ def LoadSettings(self, ledsettings): self.multicolor_index = 0 self.multicolor_iteration = ledsettings.multicolor_iteration - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): chosen_color = self.get_random_multicolor_in_range(midi_event.note) return chosen_color @@ -141,7 +141,7 @@ def LoadSettings(self, ledsettings): self.timeshift = int(ledsettings.rainbow_timeshift) self.timeshift_start = time.time() - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): shift = (time.time() - self.timeshift_start) * self.timeshift return self.calculate_rainbow_colors(note_position, shift) @@ -165,7 +165,7 @@ def LoadSettings(self, ledsettings): self.speed_period_in_seconds = ledsettings.speed_period_in_seconds self.speed_max_notes = ledsettings.speed_max_notes - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): current_time = time.time() self.notes_in_last_period.append(current_time) return self.speed_get_colors() @@ -204,7 +204,7 @@ def LoadSettings(self, ledsettings): "green": int(ledsettings.usersettings.get_setting_value("gradient_end_green")), "blue": int(ledsettings.usersettings.get_setting_value("gradient_end_blue"))} - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): return self.gradient_get_colors(note_position) def gradient_get_colors(self, position): @@ -224,7 +224,7 @@ def LoadSettings(self, ledsettings): self.key_in_scale = ledsettings.key_in_scale self.key_not_in_scale = ledsettings.key_not_in_scale - def NoteOn(self, midi_event: mido.Message, midi_state, note_position): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): scale_colors = get_scale_color(self.scale_key, midi_event.note, self.key_in_scale, self.key_not_in_scale) return scale_colors @@ -235,7 +235,7 @@ def LoadSettings(self, ledsettings): self.scale = int(ledsettings.velocityrainbow_scale) self.curve = int(ledsettings.velocityrainbow_curve) - def NoteOn(self, midi_event: mido.Message, midi_state, note_position=None): + def NoteOn(self, midi_event: mido.Message, midi_time, midi_state, note_position): x = int(((255 * powercurve(midi_event.velocity / 127, self.curve / 100) * (self.scale / 100) % 256) + self.offset) % 256) x2 = colorsys.hsv_to_rgb(x / 255, 1, (midi_event.velocity / 127) * 0.3 + 0.7) diff --git a/visualizer.py b/visualizer.py index b3578ac..7331187 100755 --- a/visualizer.py +++ b/visualizer.py @@ -413,7 +413,7 @@ def start_webserver(): if note_position >= ledstrip.led_number or note_position < 0: continue - color = color_mode.NoteOn(msg, None, note_position) + color = color_mode.NoteOn(msg, msg_timestamp, None, note_position) if color is not None: red, green, blue = color else: