Skip to content
Realtime MIDI I/O for python.
Branch: master
Clone or download
Latest commit 994d876 Jun 10, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
cpp_src prevent buffer overflow crash on certain getMidiNoteName numbers (issue Aug 15, 2018
rtmidi Moved cpp to cpp_src file, fixed manifest.in. Went through and cleane… Jun 13, 2017
tests fixed channel bug for noteOn on linux Jan 6, 2018
.gitignore added .gitignore Jun 9, 2019
CHANGELOG.txt prevent buffer overflow crash on certain getMidiNoteName numbers (issue Aug 15, 2018
DOC.txt Added doc file Jan 6, 2018
MANIFEST.in
Makefile fixed channel bug for noteOn on linux Jan 6, 2018
README.md Moved cpp to cpp_src file, fixed manifest.in. Went through and cleane… Jun 13, 2017
pkechomidi.py Moved cpp to cpp_src file, fixed manifest.in. Went through and cleane… Jun 13, 2017
setup.py prevent buffer overflow crash on certain getMidiNoteName numbers (issue Aug 15, 2018
setup_pkechomidi.py Moved cpp to cpp_src file, fixed manifest.in. Went through and cleane… Jun 13, 2017

README.md

pyrtmidi

Realtime MIDI I/O for Python on Windows, OS X, and Linux. Includes comprehensive MidiMessage class, support for virtual ports on OS X and Linux, and multi-threaded lister utility classes.

Pyrtmidi provides MIDI I/O for PKMidiCron.

Installation

Install using:

pip install rtmidi

Usage

pyrtmidi is a Python interface to RtMidi. It provides real-time midi input and output.

import rtmidi

midiin = rtmidi.RtMidiIn()

def print_message(midi):
    if midi.isNoteOn():
        print('ON: ', midi.getMidiNoteName(midi.getNoteNumber()), midi.getVelocity())
    elif midi.isNoteOff():
        print('OFF:', midi.getMidiNoteName(midi.getNoteNumber()))
    elif midi.isController():
        print('CONTROLLER', midi.getControllerNumber(), midi.getControllerValue())

ports = range(midiin.getPortCount())
if ports:
    for i in ports:
        print(midiin.getPortName(i))
    print("Opening port 0!") 
    midiin.openPort(0)
    while True:
        m = midiin.getMessage(250) # some timeout in ms
        if m:
            print_message(m)
else:
    print('NO MIDI INPUT PORTS!')

The API is copied near verbatim from the C++ code. Refer to the RtMidi tutorial, and take into account the following caveats:

RtMidiIn

getMessage(timeout_ms=None)

  • The message argument has been replaced with an optional millisecond timeout value.
  • The function will return a MidiMessage object, or None if no message is available.

setCallback

  • This function works just as described in the above docs, and takes a python callable object.
  • This method is most useful with a queue.Queue object to communicate between threads.

MidiMessage

This class has been taken from the juce library, and includes an excellent comprehensive set of midi functions. please check here for available methods.

Recipes

The following implements a QObject wrapper for rtmidi.RtMidiIn that emits a 'message()' signal. The essential code is follows:

class MidiInput(QThread):
    def __init__(self, devid, parent=None):
        QThread.__init__(self, parent)
        self.device = rtmidi.RtMidiIn()
        self.device.openPort(devid)
        self.running = False

    def run(self):
        self.running = True
        while self.running:
            msg = self.device.getMessage(250)
            if msg:
                self.msg = msg
                self.emit(SIGNAL('message(PyObject *)'), self.msg)
                self.emit(SIGNAL('message()')

midi = MidiInput(1)
def slotMessage(msg):
   print msg
QObject.connect(midi, SIGNAL('message(PyObject *)'), slotMessage)

The following implements a midi echo for all ports.

import sys
import rtmidi
import threading

def print_message(midi, port):
    if midi.isNoteOn():
        print '%s: ON: ' % port, midi.getMidiNoteName(midi.getNoteNumber()), midi.getVelocity()
    elif midi.isNoteOff():
        print '%s: OFF:' % port, midi.getMidiNoteName(midi.getNoteNumber())
    elif midi.isController():
        print '%s: CONTROLLER' % port, midi.getControllerNumber(), midi.getControllerValue()

class Collector(threading.Thread):
    def __init__(self, device, port):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.port = port
        self.portName = device.getPortName(port)
        self.device = device
        self.quit = False

    def run(self):
        self.device.openPort(self.port)
        self.device.ignoreTypes(True, False, True)
        while True:
            if self.quit:
                return
            msg = self.device.getMessage()
            if msg:
                print_message(msg, self.portName)


dev = rtmidi.RtMidiIn()
collectors = []
for i in range(dev.getPortCount()):
    device = rtmidi.RtMidiIn()
    print 'OPENING',dev.getPortName(i)
    collector = Collector(device, i)
    collector.start()
    collectors.append(collector)


print 'HIT ENTER TO EXIT'
sys.stdin.read(1)
for c in collectors:
    c.quit = True

Common Problems

This is a commonly reported build error on linux, although I it works for me using python2.7 on ubuntu.

:~/devel/pkaudio/pyrtmidi/tests$ python test_rtmidi.py 
Traceback (most recent call last):
File "test_rtmidi.py", line 29, in 
import rtmidi
ImportError: /usr/local/lib/python2.6/dist-packages/rtmidi.so: undefined symbol: _ZN11MidiMessageaSERKS_
You can’t perform that action at this time.