mididings - Documentation
Table of Contents
Basics
mididings configuration files are just Python scripts, although mididings uses some of Python's features in ways
for which they weren't intended ;)
Basically, the MIDI processing setup is defined in Python, while the actual event processing is done entirely
in C++. It is however possible to explicitly call back into Python, if necessary.
Functions
config(**kwargs)
Changes global mididings settings. This should be called only once, before constructing any processing units.
Possible keyword arguments are:
- backend: MIDI backend to be used:
- 'alsa': Use the ALSA sequencer (this is the default).
- 'jack': Use JACK MIDI. All MIDI events are buffered and processed outside the JACK process callback,
and will thus be delayed by (at least) one period.
- 'jack-rt': MIDI events are processed directly in the JACK process callback. It's not safe to run Python
code in a realtime context, so it's recommended to avoid Call(), which might cause xruns (or worse).
All other units should be safe to use.
- client_name: MIDI client name to be used.
- in_ports/out_ports: Integers indicating the number of input/output ports to create (named in_n
or out_n), or lists of port names, in which case the list's length determines the number of ports.
- data_offset: 1 (default) or 0. Determines whether program, port and channel numbers will be
in the range 1-128 or 0-127.
- octave_offset: Default is 2, meaning that "Middle C" is designated as C3.
- start_delay: The number of seconds before sending any MIDI events (i.e. switching to the first patch).
A small value like 0.5 can be used to give tools like qjackctl's patchbay time to connect the ports.
A value of 0 instructs mididings to wait for the user to press enter. Default is None.
- remove_duplicates: Whether, when two or more units connected in parallel yield identical MIDI events,
the duplicates should be discarded (default is True).
run(patch)
Starts the actual MIDI processing. This is usually the last function called by a mididings script.
run_patches(patches, control=None, pre=None, post=None)
Starts the actual MIDI processing, using multiple patches.
- patches: A dictionary with program numbers as keys, and patches as values.
Values can also be tuples with two items, the first being an init-patch that's executed once every time the
patch is selected, and the second being the actual patch that processes incoming events.
- control: The "control" patch, which is always active, and runs in parallel to the current patch.
- pre/post: Allows processing to take place before/after every patch. Does not affect
the control patch.
switch_patch(number)
Switches to another patch. This function is similar to the PatchSwitch() object, but can be called from Python.
Data Types
MidiEvent
Used in conjunction with the Call(), CallAsync() and CallThread() units.
A MidiEvent object has the following attributes:
- type_: The event type, one of the constants described below.
- port_: The event port.
- channel_: The event channel.
- data1, data2: Data bytes, meaning depends on event type.
There are also aliases for these attributes, some of which are only defined for certain types of events:
- port: Event port. Unlike port_, this value is affected by the data_offset setting.
- channel: Event channel. Unlike channel_, this value is affected by the data_offset setting.
- note: Note number, alias for data1.
- velocity: Note velocity, alias for data2.
- param: Controller number, alias for data1.
- value: Controller parameter, alias for data2.
- program: Program number, alias for data2. Unlike data2, this value is affected by the data_offset setting.
Constants
Event Types
Every event has one of these types: NOTEON, NOTEOFF, CTRL, PITCHBEND, PROGRAM.
When building filters, event types can be combined using the bitwise or operator.
Also defined are NOTE (= NOTEON | NOTEOFF), NONE, ANY.
Event Attributes
These constants are used to refer to an event's data attributes:
EVENT_PORT, EVENT_CHANNEL, EVENT_DATA1, EVENT_DATA2, EVENT_NOTE,
EVENT_VELOCITY, EVENT_PARAM, EVENT_VALUE, EVENT_PROGRAM.
Making Connections
A >> B
Connects two units in series. Incoming MIDI events will be processed by unit A first, then by unit B.
If the event is filtered out by unit A, it is not processed any further, and unit B will not be called.
[ A, B, ... ]
Connects two or more units in parallel. All units will be called with identical copies of incoming MIDI
events. The output will be the sum of all the units' outputs.
Fork([ A, B, ... ], types=ANY, remove_duplicates=None)
Same as the above, with some additional features:
- types: Pass something other than ANY to process only certain types of events, and leave
other events unchanged.
- remove_duplicates: True or False overrides the global remove_duplicates setting (see config()).
Using Fork() explicitly (instead of just a list) is also useful in situations where both sides of operator >>
would otherwise be lists, which Python does not allow.
{ T1: A, T2: B, ... }
Splits by event type.
Equivalent to [ Filter(T1) >> A, Filter(T2) >> B, ... ].
Split({ T1: A, T2: B, ... })
Same as the above. Like Fork(), this can be useful to make operator >> work.
~F
Inverts the filter F. Note that for filters which only affect certain kinds of events,
other events will remain unaffected when the filter is inverted.
F % A
Runs only those events through A which match filter F, but keeps those which don't.
Equivalent to [ F >> A, ~F ].
Units
These are the basic building blocks from which you can build your patches.
- Filters: These units filter by some property of the MIDI event. If the event matches, it's passed
unmodified, otherwise it's discarded.
Filters have no effect on different event types (e.g. a note event going through a CtrlFilter).
- Splits: Basically just combinations of multiple filters of the same kind.
- Modifiers: These units change some property of the MIDI event.
- Generators: Converters from one event type to another.
- Function Calls: These units allow calling back into Python code.
- Miscellaneous: Anything that doesn't fit into any of the other categories :)
Filters
Filter(type, ...)
Filters by one or more event types.
PortFilter(port, ...)
ChannelFilter(channel, ...)
Filters by event port or channel.
KeyFilter(key)
KeyFilter(lower, upper)
KeyFilter(range)
Filters by key or key-range. Keys can be MIDI note numbers or note names (e.g. 'g#3').
Ranges can be 2-tuples of note numbers, or note names (e.g. 'g#3:c6').
VelocityFilter(min, max)
Filters by note velocity.
CtrlFilter(ctrl, ...)
Filters by CC number.
CtrlValueFilter(value)
CtrlValueFilter(min, max)
Filters by CC value.
ProgFilter(program, ...)
Filters by PC number.
Splits
PortSplit({port: units, ...})
PortSplit({(port, ...): units, ...})
ChannelSplit({channel: units, ...})
ChannelSplit({(channel, ...): units, ...})
Splits by port or channel.
KeySplit(key, units_lower, units_upper)
KeySplit({(lower, upper): units, ...})
KeySplit({range: units, ...})
Splits by key. Non-note events are sent to all units.
VelocitySplit(threshold, units_lower, units_upper)
VelocitySplit({(min, max): units, ...})
Splits by velocity. Non-note events are sent to all units.
CtrlSplit({ctrl: units, ...})
CtrlSplit({(ctrl, ...): units, ...})
Splits by controller number.
Non-controller events are left unchanged, but not sent to any of the units.
CtrlValueSplit({value, units, ...})
CtrlValueSplit({(min, max): units, ...})
Splits by controller value.
Non-controller events are left unchanged, but not sent to any of the units.
ProgSplit({program: units, ...})
ProgSplit({(program, ...): units, ...})
Splits by program number.
Non-program-change events are left unchanged, but not sent to any of the units.
Modifiers
Port(port)
Channel(channel)
Changes port or channel.
Transpose(offset)
Transposes all note events.
Velocity(offset)
VelocityMultiply(mult)
VelocityFixed(value)
Changes velocity by adding an offset, multiplying with a factor, or setting it to a fixed value.
VelocityCurve(gamma)
Applies a "gamma"-curve to all velocity values.
VelocityGradient(note_lower, note_upper, value_lower, value_upper)
VelocityGradientMultiply(note_lower, note_upper, value_lower, value_upper)
VelocityGradientFixed(note_lower, note_upper, value_lower, value_upper)
Changes velocity, using a gradient from lower to upper.
This can be used for example to fade-in a sound over a region of the keyboard.
CtrlMap(ctrl_in, ctrl_out)
Maps one controller to another (i.e. changes the CC number).
CtrlRange(ctrl, out_min, out_max, in_min=0, in_max=127)
Maps controller range in to out.
An input value of in_min or less results in an output value of out_min.
Likewise, an in value of in_max or greater results in an output value of out_max.
Generators
CtrlChange(ctrl, value)
CtrlChange(port, channel, ctrl, value)
ProgChange(program)
ProgChange(port, channel, program)
NoteOn(note, velocity)
NoteOn(port, channel, note, velocity)
NoteOff(note, velocity)
NoteOff(port, channel, note, velocity)
Changes the type of the event.
If port and channel are omitted, the values of the input event are used.
To "reuse" other values from the incoming event, one of the EVENT_* constants can be used in place of any parameter.
Function Calls
Call(function)
Calls a Python function. This will stall any other MIDI processing until the function returns.
- function: A function (or any other callable object) that will be called with a MidiEvent
object as its only argument.
Possible return values are:
- A single MidiEvent object: output one event and continue processing it.
- A list of MidiEvent objects: output multiple events.
- An empty list or None: discard current event.
CallAsync(function)
Schedules a Python function for execution, and continues MIDI processing immediately.
- function: The function to be called. Unlike Call(), this will run the function in another thread.
Its return value will be ignored.
CallThread(function)
Like CallAsync(), but runs the function in its own thread.
System(cmd)
Runs an arbitrary shell command, without waiting for the command to complete.
- cmd: The command as a string, or a Python function taking a single MidiEvent parameter and returning a string.
Miscellaneous
Pass()
Does nothing.
Discard()
Discards the current event.
PatchSwitch()
PatchSwitch(number)
Switches to another patch.
number should be a patch number, or one of the EVENT_* constants.
Without parameters, the program number of the incoming event (should be a program change) will be used.
InitAction(action)
Executes action when switching to the patch containing this unit (essentially adding it to the init-patch,
see run_patches() for more information).
Output(port, channel, program=None)
Based on InitAction(), this sends a program change when the patch is selected,
and routes all incoming events to the specified port/channel.
Print(name=None, types=ANY, portnames=Print.PORTNAMES_NONE)
Prints event data.
- name: A string to be printed before each event.
- types: Restricts printing to certain event types, using a combination of the event type constants described above.
- portnames: Pass Print.PORTNAMES_IN or Print.PORTNAMES_OUT to print input or output portnames,
rather than just numbers.
PrintString(string)
Prints a fixed string.
Sanitize()
Makes sure the event is a valid MIDI message. Events with invalid port, channel, controller, program or note number are
discarded, note velocity and controller values are confined to the range 0-127.
Additional Units and Functions
These units are defined in the mididings.extra module, and offer some more advanced/specific functionality,
based on the more basic mididings units.
Some of these are implemented in Python using Call(), and thus not safe to use with the jack-rt backend.
Harmonize(tonic, scale, interval, non_harmonic='below')
A diatonic harmonizer.
- tonic: The tonic of the scale.
- scale: One of:
'major', 'minor', 'minor_harmonic', 'ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', 'aeolian', 'locrian'.
- interval: The number of steps to transpose the notes by, or one of these interval names:
'unison', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'octave',
'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth'.
It's also possible to pass a list of intervals, to create multiple harmonized voices.
- non_harmonic: What to do with out-of-scale notes:
- 'skip': Ignore note.
- 'same': Output note as is, without transposing it.
- 'below'/'above': Transpose by the same interval as the next on-scale note below/above.
SuppressPC()
Filters out program changes if the same program had previously been selected on the same port/channel.
PedalToNoteoff(ctrl=64)
Converts sustain pedal CCs to note-off events (delaying note-offs until the pedal is released).
BlackKeys()
WhiteKeys()
Filters notes by key color.
SendOSC(target, path, ...)
Defined in mididings.extra.osc. Requires pyliblo.
Sends an OSC message. Parameters are the same as for liblo.send().
Additionally, rather than a concrete value, each data argument can be a Python function instead.
The function should take a single MidiEvent parameter, and return the value to be sent.
SendDBUS(service, path, interface, method, ...)
Defined in mididings.extra.dbus. Requires dbus-python.
Sends a DBUS message. Rather than a concrete value, each data argument can be a Python function instead.
The function should take a single MidiEvent parameter, and return the value to be sent.
run_patches_memorize(memo_file, patches, control=None, pre=None, post=None)
Like run_patches(), but saves the selected patch number to a file, and restores it the next time it's called.
memo_file is the path of the file to be used to store the patch number.
Examples
- transpose.py - probably the most simple example that actually does something useful ;)
- connections.py - how to connect units in series or in parallel,
and how to split by event type or channel
- filters.py - how to use filters
- print.py - printing MIDI events to stdout
- output.py - uses the Output() unit to simplify MIDI routing and sending program changes
- call.py - shows how to process MIDI events in Python
- harmonizer.py - example usage of the diatonic harmonizer
- aeolus.py - Aeolus
stop control using one controller per stop
- klick.py - uses SendOSC() to start/stop klick,
or change its tempo