5

I have a physical MIDI keyboard that also features some control keys, such as "play" and "stop". When pressed, they send the MIDI codes 115 and 116 respectively over the MIDI bus. Is it possible to hook up these commands to the usual media controls (play and pause) of Linux, so that when I press "play", the playback starts?

Is it furthermore possible to hook up other MIDI keys (e.g., up/down) to their respective keyboard counterparts (e.g., arrow up/down)?

7
  • Possible? Yes. Easy? No, you'll need to write custom software that listens for events on that MIDI bus, and turns them into keyboard events. At least I am not aware of anything ready-made for this. Commented Apr 23, 2022 at 9:28
  • I just googled again and found a software for Windows that maps MIDI signals to keyboard strokes. Probably have to write something by myself though. Commented Apr 23, 2022 at 12:29
  • Look up uinput, and read up on the ALSA MIDI interface. You don't have to do this in C, e.g. Python has libraries for both. Commented Apr 23, 2022 at 14:00
  • Ah, I see you already did :-) Commented Apr 23, 2022 at 14:00
  • Yes, just finished. Was easier than expected, although I'm not entirely happy with it yet. I'd prefer a non-root user solution. Commented Apr 23, 2022 at 14:01

1 Answer 1

2

In the comments, dirkt suggested to write a custom program. So, I wrote a short working proof of concept script in Python that reads inputs from a MIDI controller and then simulates the required key press. I tested it on Ubuntu 20.04. Unfortunately, it requires superuser privileges to run, otherwise /dev/uinput cannot be opened for writing.

import mido
from evdev import uinput, ecodes as e


def press_playpause(): 
    """Simulate pressing the "play" key"""
    with uinput.UInput() as ui: 
      ui.write(e.EV_KEY, e.KEY_PLAY, 1)
      ui.syn() 


def clear_event_queue(inport):
    """Recent events are stacked up in the event queue 
    and read when opening the port. Avoid processing these
    by clearing the queue.
    """
    while inport.receive(block=False) is not None:
        pass


device_name = mido.get_input_names()[0]  # you may change this line
print("Device name:", device_name)

MIDI_CODE_PLAY = 115
MIDI_VALUE_ON = 127

with mido.open_input(name=device_name) as inport: 
    clear_event_queue(inport)
    print("Waiting for MIDI events...")
    for msg in inport:
        print(msg)
        if (hasattr(msg, "value") 
                and msg.value == MIDI_VALUE_ON
                and hasattr(msg, "control")
                and msg.control == MIDI_CODE_PLAY):
            press_playpause()

Requirements:

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.