# mididings - Units Reference

Units 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.
- 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.

Discard all events except note-on, note-off and control changes:
Filter(NOTE|CTRL)

#### PortFilter(port, ...)

Filters by port(s).

#### ChannelFilter(channel, ...)

Filters by channel(s).

#### KeyFilter(note_range)
KeyFilter(lower, upper)
KeyFilter(lower=...)
KeyFilter(upper=...)
KeyFilter(notes=[...])

Filters by note or note-range.

#### VelocityFilter(value)
VelocityFilter(lower=...)
VelocityFilter(upper=...)
VelocityFilter(lower, upper)

Filters by note-on velocity.

#### CtrlFilter(ctrl, ...)

Filters by CC number(s).

#### CtrlValueFilter(value)
CtrlValueFilter(lower=...)
CtrlValueFilter(upper=...)
CtrlValueFilter(lower, upper)

Filters by CC value.

#### ProgramFilter(program, ...)

Filters by PC number(s).

#### SysExFilter(sysex)

Filters by sysex data, specified as a string or as a sequence of integers. If sysex doesn't end with F7, partial matches that start with the given data bytes are accepted.

Filter out SysEx events for Roland devices with device ID 0x10:
SysExFilter('\xf0\x41\x10')

#### SysExFilter(manufacturer=...)

Filters by sysex manufacturer id, which can be a string or a sequence of integers, with a length of one or three bytes.

Filter out SysEx events for Yamaha devices:
SysExFilter(manufacturer=0x43)

## Splits

#### PortSplit({port: patch, ...})
PortSplit({(port, ...): patch, ...})

Splits by port.

#### ChannelSplit({channel: patch, ...})
ChannelSplit({(channel, ...): patch, ...})

Splits by channel.

#### KeySplit(note, patch_lower, patch_upper)
KeySplit({(lower, upper): patch, ...})
KeySplit({note_range: patch, ...})

Splits by note. Non-note events are sent to all patches.

#### VelocitySplit(threshold, patch_lower, patch_upper)
VelocitySplit({(lower, upper): patch, ...})

Splits by velocity. Non-note events are sent to all patches.

#### CtrlSplit({ctrl: patch, ...})
CtrlSplit({(ctrl, ...): patch, ...})

Splits by controller number. Non-controller events are left unchanged, but not sent to any of the patches.

#### CtrlValueSplit(threshold, patch_lower, patch_upper)
CtrlValueSplit({value: patch, ...})
CtrlValueSplit({(lower, upper): patch, ...})

Splits by controller value. Non-controller events are left unchanged, but not sent to any of the patches.

#### ProgramSplit({program: patch, ...})
ProgramSplit({(program, ...): patch, ...})

Splits by program number. Non-program-change events are left unchanged, but not sent to any of the patches.

#### SysExSplit({sysex: patch, ...})
SysExSplit(manufacturers={manufacturer: patch, ...})

Splits by sysex data or manufacturer id.

## Modifiers

#### Port(port)

Changes port.

#### Channel(channel)

Changes channel.

#### Transpose(offset)

Transposes all note events by the given number of semitones.

#### Key(note)

Changes note-events to a fixed note number.

#### Velocity(offset)
Velocity(multiply=...)
Velocity(fixed=...)
Velocity(curve=...)
Velocity(gamma=...)
Velocity(multiply, offset)

Changes velocity by adding an offset, multiplying with a factor, setting it to a fixed value, or applying a velocity-curve.
gamma uses a simple power function, where values greater than 1 increase velocity, while values between 0 and 1 decrease it. curve uses a somewhat smoother exponential function, where positive values increase velocity, while negative values decrease it.
Within mididings, velocity values may be (temporarily) greater than 127 or less than 1. When sending events through a MIDI output port, or by using the Sanitize() unit, velocities greater than 127 will automatically be reduced to 127, and events with a velocity less than 1 will be removed.

Increase velocity of note-on events, making the keyboard feel softer:
Velocity(curve=1.0)

#### VelocitySlope(notes, offset)
VelocitySlope(notes, multiply=...)
VelocitySlope(notes, fixed=...)
VelocitySlope(notes, curve=...)
VelocitySlope(notes, gamma=...)
VelocitySlope(notes, multiply, offset)

Changes velocity, applying a linear slope between different notes. This can be thought of as a Velocity() unit with different parameters for different notes, and is useful for example to fade-in a sound over a region of the keyboard.
Both parameters must be sequences of the same length, where one velocity value corresponds to each note.

Apply a velocity slope as seen in the graphic above:
VelocitySlope(notes=('b1','g2','g#3','d4'), offset=(-64, 32, 32, 0))

#### VelocityLimit(min, max)
VelocityLimit(min)
VelocityLimit(max=...)

Confines velocity to values between min and max.

#### CtrlMap(ctrl_in, ctrl_out)

Maps one controller to another (i.e. changes the CC number).

Convert sustain pedal to sostenuto:
CtrlMap(64, 66)

#### CtrlRange(ctrl, min, max, in_min=0, in_max=127)

Maps controller values from one range of values (default is 0-127) to another.
Any input value less than or equal to in_min results in an output value of min. Likewise, any value of in_max or greater results in an output value of max.

Invert CC #11 (expression):
CtrlRange(11, 127, 0)

#### CtrlCurve(ctrl, gamma)
CtrlCurve(ctrl, curve=...)
CtrlCurve(ctrl, offset=...)
CtrlCurve(ctrl, multiply=...)
CtrlCurve(ctrl, multiply, offset)

Changes controller values by applying a curve, offset or multiplication. See Velocity() for a description of the parameters.

#### PitchbendRange(min, max, in_min=-8192, in_max=8191)

Changes the pitchbend range to values between min and max.

#### PitchbendRange(down, up, range=...)

Changes the pitchbend range to the specified number of semitones.

Bend a full octave down, but only one whole step up, assuming the tone generator is set to a (symmetric) range of 12 semitones:
PitchbendRange(-12, 2, range=12)

## Generators

#### NoteOn(note, velocity)
NoteOn(port, channel, note, velocity)
NoteOff(note, velocity=0)
NoteOff(port, channel, note, velocity=0)
Ctrl(ctrl, value)
Ctrl(port, channel, ctrl, value)
Program(program)
Program(port, channel, program)
Pitchbend(value)
Pitchbend(port, channel, value)
Aftertouch(value)
Aftertouch(port, channel, value)

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.

Convert aftertouch to CC #1 (modulation):
Filter(AFTERTOUCH) % Ctrl(1, EVENT_VALUE)

#### SysEx(sysex)
SysEx(port, sysex)

Creates a new system exclusive event. sysex can be a string or a sequence of integers, and must include the leading F0 and trailing F7 bytes.

Send a SysEx message read from a file:
SysEx(open('example.syx').read())

#### Generator(type, port, channel, data1=0, data2=0)

Generic generator. System common and system realtime events can only be generated this way.

## Function Calls

#### Process(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 MidiEvent objects 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.
  Alternatively, function can be a generator that yields MidiEvent objects.

#### Call(function)

Schedules a Python function for execution, and continues MIDI processing immediately.

- function: The function to be called. Unlike Process(), this will run the function in another thread. Its return value will be ignored.

#### Call(thread=...)

Like Call(), 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.

#### SceneSwitch()
SceneSwitch(number)
SceneSwitch(offset=...)

Switches to another scene. number should be a scene number, or one of the EVENT_* constants. offset can be positive or negative and will be added to the current scene number. Without parameters, the program number of the incoming event (should be a program change) will be used.

#### SubSceneSwitch()
SubSceneSwitch(number)
SubSceneSwitch(offset=..., wrap=True)

Switches between subscenes within a scene group.

#### Init(patch)

Executes patch when switching to the scene containing this unit (essentially adding it to the init-patch, see run() for more information).

#### Output(port, channel, program=None, volume=None, pan=None, expression=None, ctrls={})

Routes incoming events to the specified port/channel. Optionally, when switching to the scene containing this unit, a program change and/or arbitrary control changes can be sent. To send a bank select in addition to the program change, program can be a tuple with two elements, where the first element is the bank number, and the second is the program number.

Route all events to output 'synth', channel 1, and set the volume to 100:
Output('synth', 1, volume=100)

#### OutputTemplate(*args, **kwargs)

Creates an object that when called will behave like Output(), with args and kwargs replacing some of its arguments. This works just like `functools.partial(Output, *args, **kwargs)`, but with the added benefit that an OutputTemplate object also supports operator >> like any unit.

Define an instrument by specifying its output port, channel, program number and transposition, then use the same instrument in two different patches at different volumes:

    synth = Transpose(12) >> OutputTemplate('synth', 1, 42)

    patch1 = synth(64)
    patch2 = synth(127)

This is equivalent to:

    patch1 = Transpose(12) >> Output('synth', 1, 42, 64)
    patch2 = Transpose(12) >> Output('synth', 1, 42, 127)

#### Print(name=None, portnames=None)

Prints event data.

- name: A string to be printed before each event.
- portnames: Pass 'in' or 'out' to print input or output port names, rather than just numbers.

A simple MIDI event monitor:
$ mididings "Print()"

#### Print(string=...)

Prints a string. Instead of a fixed value, string can also be a Python function that takes a single MidiEvent parameter, and returns the string to be sent.

Print a graph of note-on velocities:
Filter(NOTEON) % Print(string=lambda ev: '#'*ev.velocity)

#### 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.