Skip to content

Commit

Permalink
Merge pull request #3 from giosad/release/1.01
Browse files Browse the repository at this point in the history
Release/1.01
  • Loading branch information
giosad authored Aug 10, 2018
2 parents 0d780ff + f727a09 commit 983e172
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 49 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# [midi-double-trigger-filter](https://github.com/giosad/midi-double-trigger-filter)
Processes MIDI events from a controller to filter note-on events caused by unintended double triggering.

Confirmed to work on Win10 with MPD218.
Confirmed to work with MPD218 in Win10 and macOs.

## Screenshot
[![midi-note-double-trigger-filter.png](https://s33.postimg.cc/p3emgfmnz/midi-note-double-trigger-filter.png)](https://postimg.cc/image/yny93bbzv/)
## Requirements
For MIDI filtering you need :
- Virtual midi device
Expand Down
93 changes: 51 additions & 42 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env python3

# Copyright (c) 2018 Gennadi Iosad.
# All Rights Reserved.
# You may use, distribute and modify this code under the
Expand All @@ -22,17 +24,17 @@ def __init__(self, root, midi_filter, config):
self.config = config

# vars
self.iportname = tk.StringVar(window)
self.oportname = tk.StringVar(window)
self.status = tk.StringVar(window)
self.autostart = tk.IntVar(window)
self.iportname = tk.StringVar(self.root)
self.oportname = tk.StringVar(self.root)
self.status = tk.StringVar(self.root)
self.autostart = tk.IntVar(self.root)

self.filter1_enabled = tk.IntVar(window)
self.min_delay = tk.StringVar(window)
self.min_velocity = tk.StringVar(window)
self.filter1_enabled = tk.IntVar(self.root)
self.min_delay = tk.StringVar(self.root)
self.min_velocity = tk.StringVar(self.root)

self.notes_on_events_passed = tk.IntVar(window)
self.notes_on_events_skipped = tk.IntVar(window)
self.notes_on_events_passed = tk.IntVar(self.root)
self.notes_on_events_skipped = tk.IntVar(self.root)

self.setup_devices_frame()
self.setup_filter_frame()
Expand All @@ -42,13 +44,14 @@ def __init__(self, root, midi_filter, config):
self.rescan()
self.load_config()


def stats_updated_cb():
def update_stats():
self.notes_on_events_passed.set(self.midi_filter.notes_on_events_passed)
self.notes_on_events_skipped.set(self.midi_filter.notes_on_events_skipped)
self.midi_filter.stats_updated_cb = stats_updated_cb
stats_updated_cb()

REFRESH_GUI_EVENT = '<<RefreshGUI>>'
self.root.bind(REFRESH_GUI_EVENT, lambda event: update_stats())
self.midi_filter.stats_updated_cb = lambda: self.root.event_generate(REFRESH_GUI_EVENT, when="tail")
self.midi_filter.stats_updated_cb()

def set_min_velocity(*args):
try:
Expand All @@ -58,7 +61,6 @@ def set_min_velocity(*args):
self.midi_filter.min_velocity = v
self.min_velocity.trace('w', set_min_velocity)


def set_min_delay(*args):
try:
v = float(self.min_delay.get())
Expand All @@ -67,13 +69,14 @@ def set_min_delay(*args):
self.midi_filter.min_delay = v
self.min_delay.trace('w', set_min_delay)


def filter1_enabled(*args):
self.midi_filter.enabled = self.filter1_enabled.get()
self.filter1_enabled.trace('w', filter1_enabled)

if self.autostart.get():
self.start()
else:
self.update_status()


def load_config(self):
Expand Down Expand Up @@ -113,7 +116,10 @@ def update_option_menu(self, menu, choices, tkvar):


def start(self):
self.midi_filter.start(self.iportname.get(), self.oportname.get())
try:
self.midi_filter.start(self.iportname.get(), self.oportname.get())
except OverflowError as e:
debug_log('Exception in midi_filter:', e)
self.update_status()


Expand Down Expand Up @@ -207,43 +213,46 @@ def setup_stats_frame(self):


def setup_operations_frame(self):
operation_frame = tk.Frame(window)
operation_frame = tk.Frame(self.root)
operation_frame.pack()

start_btn = ttk.Button(operation_frame, textvariable = self.status, command = lambda:self.toggle_start_stop())
start_btn.pack(pady=5, ipady=2)
start_btn.pack(pady=5, ipady=5)

autostart_chkbtn = ttk.Checkbutton(window, text='Autostart', variable = self.autostart)
autostart_chkbtn = ttk.Checkbutton(operation_frame, text='Autostart', variable = self.autostart)
autostart_chkbtn.pack(pady=10)


def main():
# Config.
config_dir = appdirs.user_config_dir('midi-note-double-trigger-filter', '')
config_path = os.path.join(config_dir, 'midi-note-double-trigger-filter.cfg')
debug_log('Config at:', config_path)
config = configparser.ConfigParser()
config.read(config_path)
if 'general' not in config: config.add_section('general')
if 'filter1' not in config: config.add_section('filter1')

# Model and view
window = tk.Tk()
window.title("MIDI Note Double Trigger Filter")

# Config.
config_dir = appdirs.user_config_dir('midi-note-double-trigger-filter', '')
config_path = os.path.join(config_dir, 'midi-note-double-trigger-filter.cfg')
xprint('Config at:', config_path)
config = configparser.ConfigParser()
config.read(config_path)
if 'general' not in config: config.add_section('general')
if 'filter1' not in config: config.add_section('filter1')
midi_filter = MIDIFilter()
view = DoubleTriggerFilterView(window, midi_filter, config)

# Model and view
window = tk.Tk()
window.title("MIDI Note Double Trigger Filter")
window.update()
window.minsize(window.winfo_width(), window.winfo_height())
window.mainloop()

midi_filter = MIDIFilter()
view = DoubleTriggerFilterView(window, midi_filter, config)
midi_filter.stats_updated_cb = None
view.update_config()

window.update()
window.minsize(window.winfo_width(), window.winfo_height())
window.mainloop()
# Save config to file
if not os.path.exists(config_dir):
os.makedirs(config_dir)
config.write(open(config_path, 'w'))

midi_filter.stats_updated_cb = None
view.update_config()
debug_log('EXIT')

# Save config to file
if not os.path.exists(config_dir):
os.makedirs(config_dir)
config.write(open(config_path, 'w'))

xprint('EXIT')
main()
12 changes: 6 additions & 6 deletions midi_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import sys
import time

def xprint(*args, **kwargs):
def debug_log(*args, **kwargs):
t = time.time()
timestamp = time.strftime('%H:%M:%S', time.localtime(t)) + '.{:03}'.format(int(t * 1000) % 1000)
print(timestamp, *args, **kwargs)
Expand Down Expand Up @@ -98,20 +98,20 @@ def handle_in(msg, useData):
else:
self.notes_on_events_skipped += 1
self.stats_updated()
xprint('Skipping note_on of note {}, delta {:.3f}, velocity={}'.format(msg[1], delta, msg[2]))
debug_log('Skipping note_on of note {}, delta {:.3f}, velocity={}'.format(msg[1], delta, msg[2]))

self._oport.open_port(self._port_index_by_name(self._oport, oportname))
if not self._oport.is_port_open():
xprint('Output MIDI device is not found')
debug_log('Output MIDI device is not found')
return

self._iport.set_callback(handle_in)
self._iport.open_port(self._port_index_by_name(self._iport, iportname))
if not self._iport.is_port_open():
xprint('Input MIDI device is not found')
debug_log('Input MIDI device is not found')
return

xprint('Ports open')
debug_log('Ports open')
self._is_running = True


Expand All @@ -126,4 +126,4 @@ def stop(self):
self._oport.close_port()
self._oport = None

xprint('MIDI ports closed')
debug_log('MIDI ports closed')

0 comments on commit 983e172

Please sign in to comment.