Issue with more than 1 midi device

A
AlexM posted Sep 23 '16, 15:26:

Hey all

I've noticed when using 2 midi devices (eg Korg MicroKey + nanoKontrol2, or a Novation LaunchKey which is recognised as 2 devices), I get this error after every few notes played:

MidiInAlsa::alsaMidiHandler: unknown MIDI input error!

I found that Joseph has had this issue over a year ago: https://github.com/superquadratic/rtmidi-python/issues/18 -- any leads here? It would be great to utilise 2 midi devices so that I can assign pots and faders to various parameters (I'm tinkering with Erik's SamplerBox2 which utilises freeverb and some tone controls)

Cheers!

A
AlexM posted Sep 26 '16, 09:30:

SOLVED! Or so I hope...

Had a bit of a look around for a different MIDI module and came across RTMIDI2 which specifically says can open multiple ports at once https://pypi.python.org/pypi/rtmidi2

Installed, imported, and replaced the Midi Devices Detection / Main Loop section with the following:

midi_in = rtmidi2.MidiInMulti().open_ports("*")
midi_in.callback = MidiCallback

No more errors, ghost notes or strange behaviours.

H
HansEhv posted Sep 26 '16, 21:43:

Hello Alex,
Thanks for sharing this!
But how does your main loop now look like?

The original:
---snip---
while True:
for port in midi_in[0].ports:
if port not in previous and 'Midi Through' not in port:
midi_in.append(rtmidi.MidiIn())
midi_in[-1].callback = MidiCallback
midi_in[-1].open_port(port)
print 'Opened MIDI: '+ port
previous = midi_in[0].ports
time.sleep(2)
---snip---

This one relies on the individual ports, how does your version test and loop?

H
HansEhv posted Sep 26 '16, 21:45:

..and now with dashes showing the indent :-)

while True:

  • for port in midi_in[0].ports:
    -- if port not in previous and 'Midi Through' not in port:
    -- midi_in.append(rtmidi.MidiIn())
    -- midi_in[-1].callback = MidiCallback
    -- midi_in[-1].open_port(port)
    -- print 'Opened MIDI: '+ port
  • previous = midi_in[0].ports
  • time.sleep(2)
A
AlexM posted Sep 27 '16, 09:39:

I actually just replaced the whole loop/section with those 2 lines. What would you suggest?

H
HansEhv posted Sep 27 '16, 12:12:

I thought of having the 'while true:' infinite loop with :
-These 2 statements
-The sleep delay. This to give more room for the other processes. It could even be longer as you don't plug/replug your midi interfaces that often.

H
HansEhv posted Sep 27 '16, 12:19:

Sorry, forgot a question: how do you now see the opened port(s)?

A
AlexM posted Sep 27 '16, 16:08:

Hey Hans,

I added these lines below (I'm hoping BB code works here otherwise I'll need to post again!)

This will also close all ports when a device change is detected and attempt to reopen whatever is now connected. (although when disconnecting my nanoKontrol, RPi wigs out with "usb 1-1.3: urb status -32" errors)

[code]
stopit = False
midi_in = rtmidi2.MidiInMulti()
curr_ports = []
prev_ports = []
first_loop = True
while True:
if stopit:
break
curr_ports = rtmidi2.get_in_ports()
if (len(prev_ports) != len(curr_ports)):
midi_in.close_ports()
prev_ports = []
for port in curr_ports:
if port not in prev_ports and 'Midi Through' not in port and (len(prev_ports) != len(curr_ports)):
midi_in.open_ports(port)
midi_in.callback = MidiCallback
if first_loop:
print 'Opened MIDI port: ' + port
else:
print 'Reopening MIDI port: ' + port
prev_ports = curr_ports
first_loop = False
time.sleep(2)
[/code]

A
AlexM posted Sep 27 '16, 16:10:

Ah damn - does anyone know how to format code in this forum? :(

R
remi posted Sep 27 '16, 17:35:

If i'm not wrong this should works like github
https://help.github.com/articles/creating-and-highlighting-code-blocks/

Or just past your code in here : https://gist.github.com/ (you don't need an account)

Test

stopit = False
midi_in = rtmidi2.MidiInMulti()
curr_ports = []
prev_ports = []
first_loop = True
while True:
    if stopit:
        break
    curr_ports = rtmidi2.get_in_ports()
    if (len(prev_ports) != len(curr_ports)):
        midi_in.close_ports()
        prev_ports = []
        for port in curr_ports:
            if port not in prev_ports and 'Midi Through' not in port and (len(prev_ports) != len(curr_ports)):
                midi_in.open_ports(port)
                midi_in.callback = MidiCallback
                if first_loop:
                    print 'Opened MIDI port: ' + port
                else:
                    print 'Reopening MIDI port: ' + port
                    prev_ports = curr_ports
                    first_loop = False
                    time.sleep(2)
A
AlexM posted Sep 27 '16, 17:45:

Perfect!! Thanks remi!

H
HansEhv posted Sep 27 '16, 23:40:

Many thanks guys, this is very useful.

K
Kevin Chau posted Nov 7 '16, 23:29:

Installing rtmidi2 also solved ghost notes and bad midi input for the mpkmini mk2 that i am using. Thanks for the solution

A
AlexM posted Nov 8 '16, 06:57:

Good to know!

There's still a bug that causes SamplerBox to crash when connecting/disconnecting midi devices. I have a few ideas on the cause(s) which I'll test in time. But for the time being this solution seems to be working well for the most part!

D
David Dawkins posted Nov 29 '23, 22:39:

If anyone else finds this thread useful (as I did), then I think this was the intended indentation for AlexM's code:

stopit = False
midi_in = rtmidi2.MidiInMulti()
curr_ports = []
prev_ports = []
first_loop = True
while True:
    if stopit:
        break
    curr_ports = rtmidi2.get_in_ports()
    if (len(prev_ports) != len(curr_ports)):
        midi_in.close_ports()
        prev_ports = []
    for port in curr_ports:
        if port not in prev_ports and 'Midi Through' not in port and (len(prev_ports) != len(curr_ports)):
            midi_in.open_ports(port)
            midi_in.callback = MidiCallback
            if first_loop:
                print ('Opened MIDI port: ' + port)
            else:
                print ('Reopening MIDI port: ' + port)
    prev_ports = curr_ports
    first_loop = False
    time.sleep(2)
...

  (not published)
  I want to post as guest
 

Post