(work in progress)
I’ve always thought it would be cool to be able to compose music in code. There are some languages out there that do this, but I was more interested in direct midi programming than in a DSL for composing music. Enter mido
.
mido is a midi library for Python that wraps python-rtmidi in a friendlier API. It can do a lot of things, but I was primarily interested in sending notes to a synth in Bitwig Studio. But playing notes was more a side effect of wanting to explore some ideas around an API for composing music.
I started by defining a Note class.
Python
import mido
class Note:
# http://bradthemad.org/guitar/tempo_explanation.php
LENGTHS = {
'w': 240,
'h': 120,
'q': 60,
'e': 30,
's': 15,
't': 7.5,
'dq': 90,
'de': 45,
'ds': 22.5,
'tq': 40,
'te': 20,
'ts': 10
}
# what is the equivalent of '1' numeric duration value
DURATION_MULTIPLIER = LENGTHS['q']
def __init__(self, value:int, duration, multiplier=1, velocity:int=64):
self.value = value
self.duration = duration
self.multiplier = multiplier
self.velocity = velocity
# Converts a note length value like dotted eighth to a value in seconds based on default or provided bpm tempo.
# Length abbrs: w, h, q, e, s, t, dq, de, ds, tq, te, ts (whole/half/quarter/eight/sixteenth/32nd, dotted/triplet)
def seconds(self, tempo:int):
if type(self.duration) == str:
if self.duration in Note.LENGTHS:
len = Note.LENGTHS[self.duration]
return len * self.multiplier / tempo
else:
return 0
else:
return self.duration * Note.DURATION_MULTIPLIER / tempo
# Returns mido "note_on" message
def get_on(self):
print(f"On {self.value} {self.duration}")
return mido.Message('note_on', note=self.value, velocity=self.velocity)
# Returns mido "note_off" message
def get_off(self):
print(f"Off {self.value} {self.duration}")
return mido.Message('note_off', note=self.value)