Connects 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.
Connects an arbitrary number of units in series.
Connects units in parallel. Both units will be called with identical copies of incoming MIDI events. The output will be the sum of all the units' outputs.
Connects an arbitrary number of units in parallel. With Fork() it's also possible to disable the automatic removal of identical MIDI events by setting remove_duplicates to False.
Applies A to a duplicate of each event and leaves the original unchanged. Equivalent to [ Pass(), A ].
Splits by event type. Equivalent to [ Filter(T1) >> A, Filter(T2) >> B, ... ].
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. For example, an inverted KeyFilter will match a different note range, but neither the original nor the inverted filter will have any effect on control or program changes.
Inverts the filter F. Unlike ~F, this matches exactly the events that F doesn't.
Applies A only to events which match filter F, but keeps events which don't. Equivalent to [ F >> A, -F ].
Applies A only to events which match selector S. Selectors can be built by combining multiple filters using the operators & (AND) and | (OR).
Many mididings units accept notes and/or note ranges as parameters. Notes can be specified either as a MIDI note number or by their name, consisting of one letter, optionally 'b' or '#', and an octave number. Examples of valid note names are 'c3', 'g#4', 'eb2'.
Note ranges can be specified either as a 2-tuple of note numbers, e.g. (48, 60), or as two note names
separated by a colon, e.g. 'g#3:c6'. Like all ranges in Python, note ranges are semi-open (do not include
their upper limit), so 'g#3:c6' matches notes from 'g#3' up to 'b5', but not 'c6'!
It's also possible to leave out either the upper or the lower limit, for example 'c4:' matches all notes above
(and including) C4, while ':a2' matches all note up to (but not including) A2.
Internally, ports are always referred to by their number. When an event is received on the second input port,
and is not explicitly routed to another port, it will be sent to the second output port.
If you named your input and output ports using the in_ports and out_ports parameters to config(), you can also refer
to them by their names in all units that accept ports as parameters.
To avoid ambiguities, port names should be unique (with the JACK backend they must be).
A couple of things you might need to know...
Many function and unit names in mididings are overloaded to have somewhat different meanings depending on the number and/or names of their parameters. For example, KeyFilter(note) filters a single note, while KeyFilter(lower, upper) filters a range of notes.
When multiple versions of a unit accept the same number of parameters, it's necessary to explicitly name the parameters of the version you'd like to use. Cases where parameter names are required are indicated in the documentation as "param=...". It's usually possible to name parameters like this regardless of whether it's actually necessary.
Everything in mididings is a Python object, and can be assigned to variables, returned from functions, etc.
def add_interval(n): return Pass() // Transpose(n) route = Channel(2) mypatch = add_interval(7) >> route run(mypatch)
In Python, line breaks delimit statements, and indentation delimits blocks. However, as a rule of thumb, both are irrelevant as long as at least one parenthesis or bracket is still open. Many mididings patches consist of lists and dictionaries, so line breaks and indentation are usually not an issue.
Sometimes it makes sense to put a patch in parentheses to allow it to span multiple lines:
mypatch = ( Transpose(12) >> Velocity(curve=1.0) >> Filter(~PROGRAM) )
Overloading operators in Python does not change their precedence. This is a list of all operators relevant to mididings, in order of their precedence (highest to lowest):
[A, B, ...] (...) |
Connection in parallel, using a list Binding (parentheses) |
~F | Filter inversion |
-F +F |
"True" filter inversion Apply to duplicate |
A // B S % A |
Connection in parallel Selector |
A >> B | Connection in series |
F & G | Selector AND |
F | G | Selector OR |
In short, just remember that...
Also note that operators can't be overloaded if both sides are builtin Python types like lists or dictionaries. In some cases it may be necessary to wrap those in Fork() or Split().