27
27
import threading
28
28
import math
29
29
from pathlib import Path
30
- use_rtmidi = "rtmidi" in sys .argv # use rtmidi instead of jack audio
30
+
31
+ use_rtmidi = "rtmidi" in sys .argv # use this for native USB MIDI devices like Teensy
32
+ use_serial = "serial" in sys .argv # use this for direct ESP32 connection via serial
31
33
no_gui = "no_gui" in sys .argv # no GUI but blocking (just settings management)
32
34
non_block = "non_block" in sys .argv # no GUI and non-blocking (just settings management)
33
35
use_lcd = "lcd" in sys .argv # LCD GUI mode on Raspberry Pi
34
36
use_webui = "webui" in sys .argv # web UI GUI mode on Raspberry Pi
35
37
use_ncurses = not no_gui and not non_block and not use_lcd and not use_webui # normal console GUI mode (default)
38
+ use_jack = not use_rtmidi and not use_serial
36
39
if use_rtmidi :
37
40
import rtmidi
38
- from rtmidi .midiutil import open_midiinput
39
- from rtmidi .midiutil import open_midioutput
41
+ elif use_serial :
42
+ import serial
43
+ import rtmidi # serial needs rtmidi out port
40
44
else :
41
45
import jack
42
46
if use_lcd :
91
95
kit_vol_str = ""
92
96
93
97
# initialize jack audio for MIDI
94
- if not use_rtmidi :
98
+ if use_jack :
95
99
client = jack .Client ("EdrumulusGUI" )
96
100
input_port = client .midi_inports .register ("MIDI_in" )
97
101
output_port = client .midi_outports .register ("MIDI_out" )
@@ -134,9 +138,9 @@ def process_user_input(ch):
134
138
send_value_to_edrumulus (cmd_val [sel_cmd ], database [sel_cmd ])
135
139
elif ch == "a" or ch == "A" : # enable/disable auto pad selection
136
140
auto_pad_sel = ch == "a" # capital "A" disables auto pad selection
137
- elif (ch == "k" or ch == "K" ) and not use_rtmidi : # kit selection (only for jack audio mode)
141
+ elif (ch == "k" or ch == "K" ) and use_jack : # kit selection (only for jack audio mode)
138
142
ecasound_switch_chains (ch == "k" )
139
- elif (ch == "v" or ch == "V" ) and not use_rtmidi : # kit volume (only for jack audio mode)
143
+ elif (ch == "v" or ch == "V" ) and use_jack : # kit volume (only for jack audio mode)
140
144
ecasound_kit_volume (ch == "v" )
141
145
142
146
def get_linear_pad_type_index (d ):
@@ -559,7 +563,7 @@ def act_on_midi_in(status, key, value):
559
563
################################################################################
560
564
# MIDI handling (via jack audio) ###############################################
561
565
################################################################################
562
- if not use_rtmidi :
566
+ if use_jack :
563
567
def send_value_to_edrumulus (command , value ):
564
568
global midi_send_cmd , midi_send_val
565
569
(midi_send_cmd , midi_send_val ) = (command , value );
@@ -600,6 +604,34 @@ def __call__(self, event, data=None):
600
604
act_on_midi_in (event [0 ][0 ], event [0 ][1 ], event [0 ][2 ])
601
605
602
606
607
+ ################################################################################
608
+ # MIDI handling (via serial) ###################################################
609
+ ################################################################################
610
+ if use_serial :
611
+ serial_message = []
612
+ def send_value_to_edrumulus (command , value ):
613
+ global midi_send_cmd , midi_send_val
614
+ (midi_send_cmd , midi_send_val ) = (command , value );
615
+ ser .write (bytearray ([185 , midi_send_cmd , midi_send_val ]))
616
+ midi_previous_send_cmd = midi_send_cmd # store previous value
617
+ midi_send_cmd = - 1 # invalidate current command to prepare for next command
618
+
619
+ def receive_from_serial ():
620
+ global serial_message
621
+ while ser .isOpen ():
622
+ try :
623
+ data = ser .read ()
624
+ if (data [0 ] & 0x80 ) != 0 :
625
+ serial_message = [data [0 ]] # status byte is first on message
626
+ else :
627
+ serial_message .append (data [0 ])
628
+ if len (serial_message ) == 3 : # we only support three bytes commands
629
+ act_on_midi_in (serial_message [0 ], serial_message [1 ], serial_message [2 ])
630
+ midiout .send_message (serial_message )
631
+ except :
632
+ pass
633
+
634
+
603
635
################################################################################
604
636
# Main function ################################################################
605
637
################################################################################
@@ -620,11 +652,20 @@ def __call__(self, event, data=None):
620
652
try :
621
653
in_name = "EdrumulusIn" if [s for s in rtmidi .MidiIn ().get_ports () if "EdrumulusIn" in s ] else "Edrumulus"
622
654
out_name = "EdrumulusOut" if [s for s in rtmidi .MidiOut ().get_ports () if "EdrumulusOut" in s ] else "Edrumulus"
623
- midiin , port_name_in = open_midiinput ([s for s in rtmidi .MidiIn ().get_ports () if in_name in s ][0 ], client_name = "EdrumulusGUI" )
624
- midiout , port_name_out = open_midioutput ([s for s in rtmidi .MidiOut ().get_ports () if out_name in s ][0 ], client_name = "EdrumulusGUI" )
655
+ midiin , port_name_in = rtmidi . open_midiinput ([s for s in rtmidi .MidiIn ().get_ports () if in_name in s ][0 ], client_name = "EdrumulusGUI" )
656
+ midiout , port_name_out = rtmidi . open_midioutput ([s for s in rtmidi .MidiOut ().get_ports () if out_name in s ][0 ], client_name = "EdrumulusGUI" )
625
657
midiin .set_callback (MidiInputHandler (port_name_in ))
626
658
except :
627
659
raise Exception ("No native Edrumulus USB device (e.g., Teensy) nor loopMIDI driver found." )
660
+ elif use_serial :
661
+ try :
662
+ midiout = rtmidi .MidiOut () # somehow we need to call this twice: once with error and once with success
663
+ except :
664
+ midiout = rtmidi .MidiOut ()
665
+ midiout .open_virtual_port ("EdrumulusOut" )
666
+ # TODO do not use fix values here
667
+ ser = serial .Serial ("/dev/ttyUSB0" , 38400 )
668
+ threading .Thread (target = receive_from_serial ).start ()
628
669
else : # initialize jack midi
629
670
client .activate ()
630
671
try :
@@ -647,7 +688,7 @@ def __call__(self, event, data=None):
647
688
do_update_display = True
648
689
649
690
# it takes time for ecasound to start up -> we need a timer thread for socket connection
650
- if not use_rtmidi : # ecasound is only supported for jack audio mode
691
+ if use_jack : # ecasound is only supported for jack audio mode
651
692
threading .Timer (0.0 , ecasound_connection ).start ()
652
693
653
694
# main loop
@@ -676,6 +717,9 @@ def __call__(self, event, data=None):
676
717
if use_rtmidi :
677
718
midiin .delete ()
678
719
midiout .delete ()
720
+ elif use_serial :
721
+ ser .close ()
722
+ midiout .delete ()
679
723
else :
680
724
client .deactivate ()
681
725
client .close ()
0 commit comments