Giter Site home page Giter Site logo

mido's Introduction

Mido - MIDI Objects for Python

MIT License PyPi version Python version Downloads Test status Docs status REUSE status OpenSSF Best Practices

Mido is a library for working with MIDI messages and ports:

>>> import mido
>>> msg = mido.Message('note_on', note=60)
>>> msg.type
'note_on'
>>> msg.note
60
>>> msg.bytes()
[144, 60, 64]
>>> msg.copy(channel=2)
Message('note_on', channel=2, note=60, velocity=64, time=0)
port = mido.open_output('Port Name')
port.send(msg)
with mido.open_input() as inport:
    for msg in inport:
        print(msg)
mid = mido.MidiFile('song.mid')
for msg in mid.play():
    port.send(msg)

Full documentation at https://mido.readthedocs.io/

Main Features

  • convenient message objects.
  • supports RtMidi, PortMidi and Pygame. New backends are easy to write.
  • full support for all 18 messages defined by the MIDI standard.
  • standard port API allows all kinds of input and output ports to be used interchangeably. New port types can be written by subclassing and overriding a few methods.
  • includes a reusable MIDI stream parser.
  • full support for MIDI files (read, write, create and play) with complete access to every message in the file, including all common meta messages.
  • can read and write SYX files (binary and plain text).
  • implements (somewhat experimental) MIDI over TCP/IP with socket ports. This allows for example wireless MIDI between two computers.
  • includes programs for playing MIDI files, listing ports and serving and forwarding ports over a network.

Status

1.3 is the fourth stable release.

This project uses Semantic Versioning.

Requirements

Mido requires Python 3.7 or higher.

Installing

python3 -m pip install mido

Or, alternatively, if you want to use ports with the default backend:

python3 -m pip install mido[ports-rtmidi]

See docs/backends/ for other backends.

Source Code

https://github.com/mido/mido/

License

Mido is released under the terms of the MIT license.

Questions and suggestions

For questions and proposals which may not fit into issues or pull requests, we recommend to ask and discuss in the Discussions section.

mido's People

Contributors

adarob avatar akx avatar almostimplemented avatar bast avatar belm0 avatar bozakov avatar carlthome avatar endolith avatar gulaki avatar kyleclaassen avatar lacacks avatar langyinan avatar nomadbyte avatar olemb avatar omit66 avatar ptone avatar rbinkys avatar rdoursenaud avatar rec avatar richard-vogl avatar rmccampbell avatar shabble avatar slegroux avatar sonovice avatar theotherdays avatar tomerv avatar trmanderson avatar twangist avatar tweakoz avatar twobraids avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mido's Issues

Messages are unhashable

This means they can't meaningfully be used as keys in dicts, put in sets etc.

I'm building a Markov Model for generating drum midi and being able to hash Messages would make my life 10X easier. I'm happy to put code it up and submit the pull request I just wanted to ask if:

a) This fits in with your plans for Mido?
b) You have enough time to merge the pull request?
c) There are any special requirements for contributing not already mentioned?

MIDI to array problem

How do you get the length of a melody same as endtime including the rest to avoid broken looping for interval mode? myMidi.length won't do it.
Here's my code for MIDI to array conversion:

import mido
filename = 'yourMidi.mid'
t = ['note_off','note_on']
velocity = False
interval = True
time = 0
stack = []
print('//[note'+(',vel'if velocity else'')+',start,end]')
array_name = "melody"
s = 'var '+array_name+'=['
endtime = 0
myMidi = mido.MidiFile(filename)
midiStack = [myMidi.tracks[1][1]]
for i, track in enumerate(myMidi.tracks):
    for message in track[2:][:-1]:
        midiStack.append(message)
if interval:
    for message in midiStack:
        time += message.time
        if(not t.index(message.type)):
            endtime = max(endtime,time)
    time = 0
    for message in midiStack:
        time += message.time
        if(t.index(message.type)): #Note on
            stack.append('['+str(message.note)+(','+str(message.velocity)if velocity else'')+','+str(time/float(endtime))+',')
        else: #Note off
            s += stack.pop(0)+str(time/float(endtime))+'],'
    print(s[:-1]+'];')
else:
    for message in midiStack:
        time += message.time
        if(t.index(message.type)): #Note on
            stack.append('['+str(message.note)+(','+str(message.velocity)if velocity else'')+','+str(time)+',')
        else: #Note off
            s += stack.pop(0)+str(time)+'],'
            endtime = max(endtime,time)
    print(s[:-1]+'];')
    print('var melodyduration='+str(endtime)+';')

Cannot import library

I've installed midio (using sudo pip install midio), but whenever I try and do anything I get:

Python 3.5.1 (default, Mar  3 2016, 09:29:07) 
[GCC 5.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
i>>> import midio
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'midio'
>>> 

Any help?

[question] .send() not passing message to the system?

I am trying to send note information to the system midi port, in order to have it synthesised in real-time by garageband.

I can receive keyboard input fine, using .recieve() or .poll() etc., but when I send note events to the same port the system does not seem to detect them?

I have tried using both.open_ioport() and .open_output().

I am on Mac OS X 10.11, using the rtmidi backend and Python 3.6.

midi channel mismatch

First off thanks for creating mido.
I'm very much a newbie in terms of controlling midi in python. I've encountered a little problem assigning midi channel for output when testing mido.

my set up is:
mac os x, python3.4, using the rtmidi backend
I'm attempting to send midi data via a midiman midsport 2x2 usb interface to an external sound module (Roland JV-2080)

Using this test code:

import mido

mido.set_backend('mido.backends.rtmidi')
outport = mido.open_output('MIDISPORT 2x2 Port A')
msg = mido.Message('note_on', note=60, velocity=120)
msg.channel = 10
outport.send(msg)

My problem is: the sound module receives the midi message on channel 11 not channel 10?

ImportError: No module named mido.backends.portmidi

I am using mido in a program which I am now trying to bundle into an executable using pyinstaller. When I run the resulting executable file, I get the following error output:

Traceback (most recent call last):
  File "<string>", line 44, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller-2.1.1dev_-py2.7.egg/PyInstaller/load/pyi_importers.py", line 270, in load_module
    exec(bytecode, module.__dict__)
  File "/home/eric/Documents/School/Independent/py/build/gui-edit/out00-PYZ.pyz/mido", line 117,   in <module>
  File "/home/eric/Documents/School/Independent/py/build/gui-edit/out00-PYZ.pyz/mido", line 110, in set_backend
  File "/usr/local/lib/python2.7/dist-packages/mido/backends/__init__.py", line 52, in __init__
    find_dotted_module(self.name)
  File "/usr/local/lib/python2.7/dist-packages/mido/backends/__init__.py", line 22, in find_dotted_module
    raise ImportError('No module named {}'.format(name))
ImportError: No module named mido.backends.portmidi

Running the script.py file works perfectly with mido and no errors arise regarding importing the backend. I have tried editing my pyinstaller script.spec file to include all the relevant mido directories in the 'hiddenimports'. Any ideas why this error would pop up here?

I am running LinuxMint 17.

receive() in IOPort not working

Hi!

I'm having some troubles when invoking receive() from a IOPort. Here is what I've tried.

This code never receives anything.

#!/usr/bin/env python3
import mido
mido.set_backend('mido.backends.rtmidi')
ports = mido.get_input_names()
p = mido.open_ioport(ports[0])
p.receive()

This code works and ends when a note is received.

#!/usr/bin/env python3
import mido
mido.set_backend('mido.backends.rtmidi')
ports = mido.get_input_names()
p = mido.open_input(ports[0])
p.receive()

Am I doing something wrong?
Thanks in advance.

rtmidi backend

I'm getting this on a fresh pip install:

'Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/mido/backends/rtmidi.py", line 9,
in
import rtmidi
ImportError: No module named rtmidi

This is in the import of the module where it tries a recursive import of itself. I think that's been prevented in Python 2.76 and Python 3.4. I couldn't get it to work in either version.
I used to do things like this, myself, but I think it needs to change.

My best,

Eirikur

python-rtmidi installation instructions are out-of-date

The installation instructions for python-rtmidi aren't accurate (any more):

https://github.com/olemb/mido/blob/master/docs/installing.rst#installing

I released python-rtmidi 1.0.0 a while ago. Using pip install --pre shouldn't be necessary anymore.

Also, python-rtmidi comes with it's own copy of the RtMidi source code and compiles it statically into the _rtmidi extension module. So librtmidi-dev shouldn't be a dependency and to my knowledge never was.

can't import bpm2tempo

I want to write a midi file at a user defined tempo. Following the advice on the docs, I tried to use bpm2tempo (see this and this), but when trying to import bpm2tempo I get the following:

In [29]: from mido import bpm2tempo
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-29-1daa72472ee2> in <module>()
----> 1 from mido import bpm2tempo

ImportError: cannot import name bpm2tempo

I checked the source code installed via pip in my machine (v. 1.1.12) and I can't find the bpm2tempo function.

Reading docs/changes.rst I see that bpm2tempo() and tempo2bpm() were added in v. 1.1.11. Maybe there's a merge problem in 1.1.12 which dropped that?

Setting callback after initialization does not work when kwarg was not set

The following example does not work:

def print_message(message):
    print(message)

port = mido.open_input('Launchpad Mini')
port.callback = print_message

setting callback to anything besides None and substituting the callback afterwards, fixes the problem

def print_message(message):
    print(message)

port = mido.open_input('Launchpad Mini', callback=lambda x: x)
port.callback = print_message

even using

port = mido.open_input('Launchpad Mini', callback=1)

while technically incorrect, fixes the problem.

"IOError: no default port found" when running bin/mido-play

Hi! Apologies for such a n00b question, but I'm having trouble getting past this obstacle.

I've brew installed portmidi. I've also confirmed that pygame is able to play a midi file using its mixer module.

However, running the given mido-play example produces the error message in the subject of this issue. Do you know what step I'm missing? The stack trace is reproduced below:

Traceback (most recent call last):
  File "./bin/mido-play", line 92, in <module>
    main()
  File "./bin/mido-play", line 74, in main
    with mido.open_output(args.output_port) as output:
  File "/usr/local/lib/python2.7/site-packages/mido/backends/backend.py", line 111, in open_output
    return self.module.Output(name, **self._add_api(kwargs))
  File "/usr/local/lib/python2.7/site-packages/mido/ports.py", line 263, in __init__
    BasePort.__init__(self, name, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/mido/ports.py", line 53, in __init__
    self._open(**kwargs)
  File "/usr/local/lib/python2.7/site-packages/mido/backends/portmidi.py", line 116, in _open
    device = _get_default_device(opening_input)
  File "/usr/local/lib/python2.7/site-packages/mido/backends/portmidi.py", line 67, in _get_default_device
    raise IOError('no default port found')
IOError: no default port found

client name?

If I do aplaymidi -l it lists a "client name" is there any way to get this info from mido ?

aplaymidi -l
 Port    Client name                      Port name
 14:0    Midi Through                     Midi Through Port-0
 20:0    APC MINI                         APC MINI MIDI 1
128:0    TiMidity                         TiMidity port 0
128:1    TiMidity                         TiMidity port 1
128:2    TiMidity                         TiMidity port 2
128:3    TiMidity                         TiMidity port 3

output from get_ioport_names

>>> mido.get_ioport_names()
[u'APC MINI MIDI 1', u'Midi Through Port-0']

OSError: dlopen(libportmidi.dylib, 6): image not found

After upgrading from Yosemite to OS X El Capitan 10.11.4 I get the following error. My code worked perfectly just before the upgrade.

Traceback (most recent call last): File "[REDACTED].py", line 6, in <module> inport = mido.open_input('[REDACTED]') File "/Library/Python/2.7/site-packages/mido/backends/backend.py", line 112, in open_input return self.module.Input(name, **self._add_api(kwargs)) File "/Library/Python/2.7/site-packages/mido/backends/backend.py", line 63, in module self.load() File "/Library/Python/2.7/site-packages/mido/backends/backend.py", line 79, in load self._module = _import_module(self.name) File "/Library/Python/2.7/site-packages/mido/backends/backend.py", line 25, in _import_module return importlib.import_module(module, package) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module __import__(name) File "/Library/Python/2.7/site-packages/mido/backends/portmidi.py", line 15, in <module> from . import portmidi_init as pm File "/Library/Python/2.7/site-packages/mido/backends/portmidi_init.py", line 20, in <module> lib = CDLL(dll_name) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 365, in __init__ self._handle = _dlopen(self._name, mode) OSError: dlopen(libportmidi.dylib, 6): image not found

Easier to read screenshot:
https://imgur.com/bf3rbOd

OSError: libportmidi.so: cannot open shared object file: No such file or directory

Hi,
I am trying to run the example but getting OSError after the following statement.

output = mido.open_output()

gives this error.

Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/mido/backends/backend.py", line 133, in open_output return self.module.Output(name, **self._add_api(kwargs)) File "/usr/local/lib/python2.7/dist-packages/mido/backends/backend.py", line 63, in module self.load() File "/usr/local/lib/python2.7/dist-packages/mido/backends/backend.py", line 79, in load self._module = _import_module(self.name) File "/usr/local/lib/python2.7/dist-packages/mido/backends/backend.py", line 25, in _import_module return importlib.import_module(module, package) File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module __import__(name) File "/usr/local/lib/python2.7/dist-packages/mido/backends/portmidi.py", line 15, in <module> from . import portmidi_init as pm File "/usr/local/lib/python2.7/dist-packages/mido/backends/portmidi_init.py", line 20, in <module> lib = CDLL(dll_name) File "/usr/lib/python2.7/ctypes/__init__.py", line 365, in __init__ self._handle = _dlopen(self._name, mode) OSError: libportmidi.so: cannot open shared object file: No such file or directory

AttributeError: 'SocketPort' object has no attribute '_lock'

Hello, I receive an error when trying to connect to a tcp socketport.

gld_address = ("192.168.2.49", 51325)
gld_connection = SocketPort(*gld_address)

Traceback (most recent call last):
  File "__init__.py", line 20, in <module>
    for message in gld_connection:
  File "/usr/lib/python3.6/site-packages/mido/ports.py", line 238, in __iter__
    yield self.receive()
  File "/usr/lib/python3.6/site-packages/mido/ports.py", line 187, in receive
    with self._lock:
AttributeError: 'SocketPort' object has no attribute '_lock'
Exception ignored in: <bound method BasePort.__del__ of <open I/O '192.168.2.4951325' (SocketPort)>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/mido/ports.py", line 81, in __del__
  File "/usr/lib/python3.6/site-packages/mido/ports.py", line 69, in close
AttributeError: 'SocketPort' object has no attribute '_lock'

I can work around the error by modifying the program as follows:

gld_connection = SocketPort(*gld_address)
gld_connection.__dict__['_lock'] = threading.RLock() ## sick hack

I believe that the problem is that SocketPort does not call its super's init method.

PortMidi backend 100% CPU consumption

I'm currently using mido for handle midi-input, on Linux (ALSA),
using the portmidi backend the cpu, after mido.open_input(name), is used at 100% (one core) , using the callback doesn't change.

With rtmidi no problems.

Add ALSA RawMidi backend

@dagargo Here's a new issue to follow up on our discussion on pull request #60.

We can use ctypes or CFFI to call functions in the rawmidi C API. The PortMidi backend uses ctypes. I find CFFI easier to use (especially if you need to use structs) but it adds a dependency.

I suggest we start with a simple prototype that opens an output device and allows you to send messages. If this works we can look at reception.

It looks like the input device needs to be opened in blocking or nonblocking mode which doesn't fit the Mido API very well. If RawMidi supports callbacks we can use the queue trick from the RtMidi backend.

I think we should call the module mido.backends.alsa_rawmidi.

Some documentation on RawMidi:

Where is Channel 10?

I recently started using your library to learn more about the MIDI spec in hopes of building music data visualization tools. As I understand it, MIDI channel 10 is reserved for percussion instruments. I've opened multiple MIDI files with mido and have yet to see any activity in channel 10. Am I missing something obvious or does mido not support the percussion channel?

IOError('data byte must be in range 0..127') with Lakh MIDI file

I can open this attached MIDI file in timidity and Ardour without issue, but mido is unable to parse it. What's special about it?

E.g.

from mido import MidiFile
MidiFile('0b0812979e33c132046d24575ff810cf.mid')

results in

---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-2-51ef249dd91a> in <module>()
----> 1 MidiFile('0b0812979e33c132046d24575ff810cf.mid')

/home/carl/anaconda3/lib/python3.5/site-packages/mido/midifiles.py in __init__(self, filename, file, type, ticks_per_beat, charset)
    229         elif self.filename is not None:
    230             with io.open(filename, 'rb') as file:
--> 231                 self._load(file)
    232 
    233     def add_track(self, name=None):

/home/carl/anaconda3/lib/python3.5/site-packages/mido/midifiles.py in _load(self, file)
    266 
    267             for i in range(number_of_tracks):
--> 268                 self.tracks.append(self._read_track())
    269                 # Todo: used to ignore EOFError. I hope things still work.
    270 

/home/carl/anaconda3/lib/python3.5/site-packages/mido/midifiles.py in _read_track(self)
    351                 message = self._read_sysex()
    352             else:
--> 353                 message = self._read_message(status_byte)
    354 
    355             message.time = delta

/home/carl/anaconda3/lib/python3.5/site-packages/mido/midifiles.py in _read_message(self, status_byte)
    286         for byte in data_bytes:
    287             if byte > 127:
--> 288                 raise IOError('data byte must be in range 0..127')
    289         return build_message(spec, [status_byte] + data_bytes)
    290 

OSError: data byte must be in range 0..127
pip show mido

---
Metadata-Version: 2.0
Name: mido
Version: 1.1.17
Summary: MIDI Objects for Python
Home-page: https://mido.readthedocs.io/
Author: Ole Martin Bjorndalen
Author-email: [email protected]
Installer: pip
License: MIT
Location: /home/carl/anaconda3/lib/python3.5/site-packages
Requires: 
Classifiers:
  Development Status :: 5 - Production/Stable
  Intended Audience :: Developers
  Natural Language :: English
  License :: OSI Approved :: MIT License
  Programming Language :: Python
  Programming Language :: Python :: 2.7
  Programming Language :: Python :: 3.2

osx ML, python 3, problems installing via pip

sudo /opt/local/Library/Frameworks/Python.framework/Versions/3.3/bin/pip install mido
Downloading/unpacking mido
Downloading mido-1.1.1.tar.gz (40kB): 40kB downloaded
Running setup.py egg_info for package mido
Traceback (most recent call last):
File "", line 16, in
File "/private/tmp/pip_build_root/mido/setup.py", line 27, in
long_description=open('README.rst').read(),
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4182: ordinal not in range(128)
Complete output from command python setup.py egg_info:
Traceback (most recent call last):

File "", line 16, in

File "/private/tmp/pip_build_root/mido/setup.py", line 27, in

long_description=open('README.rst').read(),

File "/opt/local/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/encodings/ascii.py", line 26, in decode

return codecs.ascii_decode(input, self.errors)[0]

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4182: ordinal not in range(128)


Cleaning up...
Command python setup.py egg_info failed with error code 1 in /private/tmp/pip_build_root/mido

mido.read_sysx_file() cannot read plain text hex

>>> m = mido.read_syx_file('test.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mido/syx.py", line 42, in read_syx_file
    data = bytearray.fromhex(data.decode('latin1'))
ValueError: non-hexadecimal number found in fromhex() arg at position 20
>>> 
[1]+  Stopped                 python
$ cat test.txt
F0 00 01 5D 02 00 F7

mido and python-midi parse some MIDI files differently

Hi, I recently discovered this - I have found a few files where the package python-midi parses a MIDI file differently than mido. Here's a simple demonstration of that:

>>> for t in mido.MidiFile('diff_mid1.mid').tracks:
...     print len(t)
...
4
1
1
7
342
1523
484
1660
682
3550
1094
1466
54

>>> for t in midi.read_midifile('diff_mid1.mid'):
...     print len(t)
...
6
7
342
1523
484
1660
682
3550
1094
1466
54
720
56

Not sure if you have any ideas as to why this is the case. It seems pretty rare (found two files out of 1000 where this is true). Here are the two example files:
http://colinraffel.com/temp/diff_mid1.mid
http://colinraffel.com/temp/diff_mid2.mid

WindowsError: [Error 126] The specified module could not be found

Trying to play a midi file yields this result:

Traceback (most recent call last):
File "C:\Python27\Lib\mido-master\examples\midifiles\play_midi_file.py", line 19, in
with mido.open_output(port_name) as output:
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\backend.py", line 133, in open_output
return self.module.Output(name, **self.add_api(kwargs))
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\backend.py", line 63, in module
self.load()
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\backend.py", line 79, in load
self.module = import_module(self.name)
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\backend.py", line 25, in import_module
return importlib.import_module(module, package)
File "C:\Python27\lib\importlib__init
.py", line 37, in import_module
import(name)
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\portmidi.py", line 16, in
from . import portmidi_init as pm
File "C:\Python27\lib\site-packages\mido-1.1.13-py2.7.egg\mido\backends\portmidi_init.py", line 20, in
lib = CDLL(dll_name)
File "C:\Python27\lib\ctypes__init
.py", line 365, in init
self._handle = _dlopen(self._name, mode)
WindowsError: [Error 126] The specified module could not be found

What am I doing wrong? Is the .dll in the wrong location?

Two identically named MIDI devices - can't open both.

Hi - I'm trying to write a script using two Korg NanoPAD2 midi controllers. Both of the controllers show up in Mido (portmidi, linux) with the same name - "nanoPAD2 MIDI 1". I can't open both as ports in Mido using the port name. The first device mounts, but when I try to open the second, i get a port is already open error.

Is there any way to mount based on anything other than the device name? Could I use the alsa port number somehow? Is there any other way to invoke open_input() other than with the text string device name?

here's the output of pmidi -l from the command line, showing the port numbers and device names.
28:0 nanoPAD2 nanoPAD2 MIDI 1
36:0 nanoPAD2 nanoPAD2 MIDI 1

....RT-midi names them like this: 'nanoPAD2 28:0', 'nanoPAD2 36:0' - it works. Would be nice if Portmidi could work too though.

Rename Message to MidiMessage

Just a question, but could it be possible to rename Message to MidiMessage in order to avoid possible namespace collisions and in order to make it more consistent with the other classes in Mido.

Basically:

from mido import MidiFile, MidiTrack, Message as MidiMessage

vs.

from mido import MidiFile, MidiTrack, MidiMessage

Documentation Error 1.1.14

The docs say:

MIDI Files
MidiFile objects can be used to read, write and play back MIDI files. (Writing is not yet implemented.)

But i reality writing files seems to work okay using the example.

BaseOutput.send is not thread-safe

It appears that send (at least for the PortMidi backend) is not thread-safe. I'd like to add a lock on the send method for BaseOutput. If this sounds reasonable, let me know and I will submit a PR.

PortMidi: `Bad pointer' error when closing port with pygame backend on Windows

I'm using mido with the pygame backend on Windows 7 and Python 2.7.

When running this:

import mido
import time

mido.set_backend('mido.backends.pygame')

output = mido.open_output()
output.send(mido.Message('note_on', note=64, velocity=60))
time.sleep(3)
output.close()

The following error is printed to stderr in the last line:

Exception Exception: "PortMidi: `Bad pointer'" in <pypm.Output object at 0x025FF0B0> ignored

This error is mentioned as a known bug, but only under Ubuntu. This happens to me on Windows.

Apart from this everything seems to work, but I'm developing a console app so this is problematic. Is there a way for me to fix this? Or should I just use RtMidi as the backend instead?

Thank you

note on message time

OK so the documentation says:

The time attribute is used in several different ways:
--- inside a track, it is delta time in ticks

so when I say this :

        for message in self.midiFile:
                if message.type == 'note_on':
                    if message.velocity > 0:
                        print('Note:' + str(message.note) + ' velocity:' + str(message.velocity) + ' at time:' + str(message.time))

I'm assuming I am seeing at time: "some number of ticks".

but instead I see this:

Note:36 velocity:118 at time:0
Note:42 velocity:95 at time:0
Note:36 velocity:113 at time:0.2583334625
Note:42 velocity:81 at time:0.0111111166667
Note:38 velocity:116 at time:0.247222345833
Note:42 velocity:86 at time:0.00555555833333
Note:42 velocity:56 at time:0.083333375
Note:42 velocity:73 at time:0.0944444916667

so this doesnt look much like a number of ticks to me - or if it is this is a very short midi file, and

self.midiFile.length

tells me the file is 10.436,,, seconds long so...
... clearly I dont understand what the time I am seeing in the output really is...

Can anyone help?

Bug in merge_tracks (with simple fix)

There's a bug in "merge tracks" ... the relative times should restart on each track. Trivial to fix.

def merge_tracksFIXED(tracks):
"""Returns a MidiTrack object with all messages from all tracks.
The messages are returned in playback order with delta times
as if they were all in one track.
"""
now = 0 #TODO: REMOVE THIS
messages = MidiTrack()
for track in tracks:
now = 0 #TODO: ADD THIS
for message in track:
now += message.time
if message.type not in ('track_name', 'end_of_track'):
messages.append(message.copy(time=now))
if message.type == 'end_of_track':
break

messages.sort(key=lambda x: x.time)
messages.append(MetaMessage('end_of_track', time=now))

# Convert absolute time back to delta time.
last_time = 0
for message in messages:
    message.time -= last_time
    last_time += message.time

return messages

Support RIFF MIDI file variant

Another file I tried to load but failed is attached. The file plays correctly on winamp and isn't a sysx file (I checked). This isn't critical to me, as I am working on a large dataset of midi files, but obviously it would be ideal if mido could handle any midi type that common media players can handle.
no_hero.zip

installation problem on windows

i currently do a midi controller with kivy and i need a midi library which give the midi channel number for input message.

thanks for your work

*** Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit (AMD64)] on win32. ***

import mido
Traceback (most recent call last):
File "", line 301, in runcode
File "", line 1, in
File "C:\Python33\lib\site-packages\mido-1.1.5-py3.3.egg\mido__init__.py", line 79, in
ImportError: cannot import name ports

Error while installing with pip on OSX 10.6.8

Here's the output of Terminal when installing with pip on OSX 10.6.8:

MacBook-Pro:~ patrick$ pip install mido
Downloading/unpacking mido
Downloading mido-1.1.3.tar.gz (40kB): 40kB downloaded
Running setup.py egg_info for package mido
Traceback (most recent call last):
File "", line 16, in
File "/private/var/folders/Sl/Sl8Rt9ndGJmyCKh889EQQU+++TI/-Tmp-/pip_build_patrick/mido/setup.py", line 4, in
import mido
File "mido/init.py", line 78, in
from .backends import Backend
File "mido/backends/init.py", line 5, in
from .. import ports
File "mido/ports.py", line 16, in
from .parser import Parser
File "mido/parser.py", line 17, in
from .messages import Message, build_message, get_spec
File "mido/messages.py", line 47
self.settable_attributes = set(self.arguments) | {'time'}
^
SyntaxError: invalid syntax
Complete output from command python setup.py egg_info:
Traceback (most recent call last):

File "", line 16, in

File "/private/var/folders/Sl/Sl8Rt9ndGJmyCKh889EQQU+++TI/-Tmp-/pip_build_patrick/mido/setup.py", line 4, in

import mido

File "mido/init.py", line 78, in

from .backends import Backend

File "mido/backends/init.py", line 5, in

from .. import ports

File "mido/ports.py", line 16, in

from .parser import Parser

File "mido/parser.py", line 17, in

from .messages import Message, build_message, get_spec

File "mido/messages.py", line 47

self.settable_attributes = set(self.arguments) | {'time'}

                                                        ^

SyntaxError: invalid syntax


Cleaning up...
Command python setup.py egg_info failed with error code 1 in /private/var/folders/Sl/Sl8Rt9ndGJmyCKh889EQQU+++TI/-Tmp-/pip_build_patrick/mido
Storing complete log in /Users/patrick/Library/Logs/pip.log
MacBook-Pro:~ patrick$

Index Error when trying to open a valid midi file

I attempted to open the attached file using mido.MidiFile, and got an IndexError.
The midi seems valid because winamp plays it without issue, but when I try to load it with mido I get an IndexError in one of the internal decode functions.

(BTW - what a great library!)

daughter.zip

IOPort.receive() does not return

Around commit 1306d31, the overwriting of Input._receive() was replaced by the overwriting of Input.receive() in the rtmidi module.
As there is no custom IOPort in rtmidi, the calls to the method IOPort.receive() do not work. However, Input.receive() works as expected.

This can be fixed in appending this code to the rtmidi module.

from mido.ports import IOPort as CommonIOPort

class IOPort(CommonIOPort):

    def __init__(self, name, **kwargs):
        self.input = Input(name, **kwargs)
        self.output = Output(name, **kwargs)
        super(IOPort, self).__init__(self.input, self.output)

    def receive(self, block=True):
        return self.input.receive()

But since you are doing some changes to the internal API used by the backends in the mentioned methods I am not sure if adding this is a good idea.

OSError: [WinError 126] The specified module could not be found

Hi,
I'm trying to open a virtual output port but this error is raised when i try to do so. From the installation guide i've understand that i need portmidi.dll, but there's no download link, and google doesn't know the answer either.

Do i need to install portmidi (if i could avoid it that would be amazing, the VStudio solution is broken) or do i only need one dll ?

What do I need to do ?

Question On Sending Midi Messages

I've been using mido to send messages in real time with keyboard inputs. I am able to hear the notes being played out of my speakers but I am having no luck with external software like Cubase and Midi-OX recognizing the output messages. Here is an example of how I send a message:
outport.send(mido.Message('note_on', note=60+octave, velocity=80))

Any help is greatly appreciated and sorry for my lack of knowledge on this stuff but I am still rather novice.

Can only receive 1000 messages before input hangs

So I have modified the example examples/ports/input_filter.py to filter for clock signals, however they seem to stop coming in after 1000 messages;

#!/usr/bin/env python
"""
Receive messages on the input port and print messages with a specific
channel (defaults to 0).
Usage:
    python example_input_filter.py portname [CHANNEL] [...]
"""

from __future__ import print_function
import sys
import mido

def accept_notes(port):
    """Only let clock messages through."""
    for message in port:
        if message.type == 'clock':
            yield message


if len(sys.argv) > 1:
    portname = sys.argv[1]
else:
    portname = None   # Use default port

try:
    with mido.open_input(portname) as port:
        print('Using {}'.format(port))

        print("Ignoring everything but 'clock'.")
        print('Waiting for notes...')

        counter = 0

        for message in accept_notes(port):
            counter += 1
            print('Received {} ({})'.format(message, counter))
except KeyboardInterrupt:
    pass

And here is the output from running that:

Received clock time=0 (1)
Received clock time=0 (2)
Received clock time=0 (3)
Received clock time=0 (4)
...
Received clock time=0 (999)
Received clock time=0 (1000)

The program then hangs on line 15 (for message in port:) forever.

I believe it's because of this line (mido/backends/portmidi.py:131), as the buffer size is set to 1000. After reading the documentation for Pm_OpenInput, I'm not entirely sure why it's stopping at 1000.

The way I understand it is that the buffer fills up to a maximum of bufferSize events, while Pm_Read removes events from the buffer. This leads me to wonder why it's stopping as in theory the for loop should be emptying the buffer and allowing new messages to arrive.

Note that the clock messages are coming in extremely fast, although I'm not entirely sure how fast.

Another interesting thing I've noticed is that the 1000 limit seems to only apply to the clock type message, as if I turn off the "clock filter" in that code, I get this at the start too:

Received sysex data=(126,127,6,1) time=0 (1)
Received sysex data=(126,0,6,1) time=0 (2)
Received sysex data=(0,32,127,3,1) time=0 (3)
Received start time=0 (4)

Which leads to me receiving 1003 notes instead of just 1000. What is going on?

rtmidi backend with JACK fails to open outputs

when using python 3.5 / mido 1.2.4 from ipython shell, attempting to open a JACK-backed output port fails with OSError: unknown port 'jack_mixer:midi in'. Opening alsa (or default with no args given) ports does succeed.

Jack is configured with 'alsa seq' midi backend, and import rtmidi; rtmidi.get_compiled_api() returns [2,3], corresponding to both ALSA and JACK API support.

STR:

  • $ export MIDO_BACKEND=mido.backends.rtmidi/UNIX_JACK (per docs)
  • $ ipython
  • > import mido; print(mido.backend); print(mido.get_output_names()); mido.open_output('jack_mixer:midi in')

gives:

<backend mido.backends.rtmidi/UNIX_JACK (loaded)>
['jack_mixer:midi in', 'midi-monitor:input', 'system:midi_playback_1']
OSError: unknown port 'jack_mixer:midi in'

A bit of poking suggests that in backends/rtmidi.py:Output._open, the initial rtmidi.MidiOut call needs the appropriate rtapi= kwarg similar to how get_devices does.

A trivial patch which (I think) solves my problem here is:

--- rtmidi.py	2017-04-26 21:25:35.976253379 +0100
+++ rtmidi.py.mine	2017-04-26 21:25:03.787777692 +0100
@@ -222,7 +222,8 @@
         self.closed = True
         self._send_lock = threading.RLock()

-        self._rt = rtmidi.MidiOut(name=client_name)
+        rtapi = _get_api_id(api)
+        self._rt = rtmidi.MidiOut(name=client_name, rtapi=rtapi)

         self.api = _api_to_name[self._rt.get_current_api()]
         self._device_type = 'RtMidi/{}'.format(self.api)

but not sure if this is the right way to go about it, and there are probably other places (like Input) that'll need similar.

If this looks plausible, I can submit a merge request if desired?

[question] About playing sequence of notes and multiple threads

Hello

I've been having a lot of fun exploring Mido, and was thinking to use it as the foundation of an API for real time musical livecoding.

Here's where I got to:

from __future__ import print_function
import sys
import time
import random
import mido
from mido import Message
from threading import Thread

mido.set_backend('mido.backends.rtmidi')
threads = []

notes = [60, 62, 64, 60]

def playnote(note_or_notes, vel, dur, ch=0):
    """abstraction for playing a note"""
    def _play(note_or_notes, vel, dur, ch=0):
        with mido.open_output(None, autoreset=True) as port:
            if type(note_or_notes) != type([]):
                note_or_notes = [note_or_notes]
            for note in note_or_notes:
                on = Message('note_on', channel=ch, note=note, velocity=vel)
                port.send(on)
            time.sleep(1 * dur)
            for note in note_or_notes:
                off = Message('note_off', channel=ch, note=note, velocity=vel)
                port.send(off)
    t = Thread(target=_play, args=(note_or_notes, vel, dur, ch))
    threads.append(t)
    t.daemon = True
    t.start()

for n in notes:
    playnote([n, n+12], 120, 1, 0)
    print("Now I have %d threads.." % len(threads))
    time.sleep(1)

print("Exiting - with %d threads.." % len(threads))

So I was wondering

a) are threads the right way to go about playing multiple notes simultaneously (so that each note is independently defined)? PS I guess ThreadPools could be used to reuse old threads..

b) is there a standard 'MIDI' way of playing a chord? Eg above I try to do that by grouping all on and off messages. Does that guarantee that notes are played at the same time?

.....
            for note in note_or_notes:
                on = Message('note_on', channel=ch, note=note, velocity=vel)
                port.send(on)
            time.sleep(1 * dur)
            for note in note_or_notes:
                off = Message('note_off', channel=ch, note=note, velocity=vel)
                port.send(off) 
......

Thanks in advance for the help - and keep up the good work :-)

Wrong bpm2tempo and tempo2bpm?

The current implementation is

def bpm2tempo(bpm):
    """Convert beats per minute to MIDI file tempo.

    Returns microseconds per beat as an integer."""
    #120 => 500000
    #60 => 1000000
    return int(bpm * (250000.0 / 60))

but this is what I get:

>>> from mido import bpm2tempo, tempo2bpm
>>> bpm2tempo(120), bpm2tempo(60)  # should return (500000, 1000000) according to my knowledge and the docstrings!
(500000, 250000)
>>> round(tempo2bpm(500000), 1), round(tempo2bpm(1000000), 1)  # should return (120.0, 60.0) according to my knowledge and the docstrings!
(120.0, 240.0)

I think the implementations should be:

def bpm2tempo(bpm):
    """Convert beats per minute to MIDI file tempo.

    Returns microseconds per beat as an integer."""
    #120 => 500000
    #60 => 1000000
    return int(1000000 * 60.0 / bpm)

def tempo2bpm(tempo):
    """Convert MIDI file tempo to BPM.

    Returns BPM as an integer or float."""
    #500000 => 120
    #1000000 => 60
    return 1000000 * 60.0 / tempo

Error in creating new MIDI files

I got an error when saving a mid file with

mid.save('myfile.mid')

The error is :


File "/usr/lib/python3.5/site-packages/mido/midifiles.py", line 461, in save
self._save(file)
File "/usr/lib/python3.5/site-packages/mido/midifiles.py", line 487, in _save
bytes += encode_variable_int(message.time)
File "/usr/lib/python3.5/site-packages/mido/midifiles_meta.py", line 104, in encode_variable_int
raise ValueError('variable int must be a positive integer')


I found out that message.time coulde be either an int or a float (http://mido.readthedocs.io/en/latest/messages.html#the-time-attribute) and that in midifiles.py the float possibility is not checked (l.487).

My MIDI file had indeed float time attributs, that's why it didn't work.

Returning from a function when there's no message

Hi,
I have the following function using your library:

def get_input(self):
        for message in self.padinput:
            if message.type == "note_on":
                xy = self.miditoxy(message.note)
                xyv = (message.type, xy[0],xy[1],message.velocity)
                return xyv
            elif message.type == "control_change":
                return (message.type, message.control-104, message.value)

How would I add another if making the function return something else, immediately, if no input comes from the port?

can't find libportmidi.dylib when using MacPorts

I'm working on an app using mido. I work on a Mac, and I currently prefer to use MacPorts as my secondary package manager of choice. I'm also using Python 3.5 right now.

I'm using virtualenv, as I'm working on my app, so mido itself was a pip install to a normal virtualenv-based directory.

I double-checked that libportmidi.dylib was available in my LD_LIBRARY_PATH. It's in /opt/local/lib -- as is normal for a MacPorts install. This is on the LD_LIBRARY_PATH and it should work...

However, I got an error in portmidi_init.py that it couldn't be found.

I also found that the issue was easily fixed by changing:

lib = CDLL(dll_name)

to the following:

lib = CDLL(find_library(dll_name))

Errors in MacOS 10.12

Hi, getting: 'OSError: dlopen(libportmidi.dylib, 6): image not found'
When trying to execute: 'mido.get_input_names()'

Thanks, great library! (regardless of the error)

Segment fault using portmidi with callback

Sometimes when calling .open_input(<port_name>, callback=), excluding the first time, the application crash with segment-fault.

The strange fact is, without the callback all works fine, and when looking/debugging the code the problem seems located in portimidi.Input._check_error, that sometimes raise an OSError (bad pointer).

I've used this code to spot the problem, the segment-fault occur between "START 2" and "END" prints

import mido

backend = mido.Backend('mido.backends.portmidi', load=True)
port = backend.open_input()

def change_port(backend, port):
    port.close()
    return backend.open_input(backend.get_input_names()[0])

def change_port_callback(backend, port):
    port.close()
    return backend.open_input(backend.get_input_names()[0],
                              callback=lambda *a: None)

print('START 1')
port = change_port(backend, port)
port = change_port(backend, port)
port = change_port(backend, port)
port = change_port(backend, port)
print('START 2')
port = change_port_callback(backend, port) # Here
port = change_port_callback(backend, port) # Or here
port = change_port_callback(backend, port) # Or here
port = change_port_callback(backend, port) # Or here
print('END')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.