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 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. 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 controllers or program changes.
Negates the filter F. Unlike ~F, this matches exactly the events that F doesn't.
Every filter can act as a selector. In addition, it's possible to combine multiple filters into more complex selectors:
Builds a selector for events that match all of the given filters or selectors.
Builds a selector for events that match at least one of the given filters or selectors.
Applies A only to events which match selector S, but keeps events which don't.
If S is a single filter, this is equivalent to [ S >> A, -S ].
Note that operator % has higher precedence than & and |, so the selector will usually have to
be written in parentheses.
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, ...] |
Binding (parentheses) Connection in parallel (list) |
~F -F +F |
Filter inversion Filter negation Apply to duplicate |
A // B S % A |
Connection in parallel Selector "then" |
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().