MIDI Interface

class shc.interfaces.midi.MidiInterface(input_port_name: Optional[str] = None, output_port_name: Optional[str] = None, send_channel: int = 0, receive_channel: Union[None, int, Iterable[int]] = None)

An SHC interface for connecting with MIDI devices.

This interface is primarily designed to control SHC applications with MIDI DAW controllers such as the Behringer X-Touch, Icon QCon, DJ Techtools Midi Fighter or similar, which provide (motorized) faders, rotary encoders and/or push buttons. These interfaces typically send MIDI Note on/off and control change messages when the user uses the controls. In return, the controller’s hardware feedback (motor faders, LEDs) can be updated by sending the corresponding MIDI events to the controller.

Thus, the MidiInterface allows to create the following types of Connectable objects:

  • note_on_off(): bool-type for sending/receiving Note on/off events for a specific note number (for push buttons)

  • note_velocity(): range-type (RangeUint8) for sending/receiving Note on/off events with a value encoded in the velocity parameter of a specific note number

  • control_change(): range-type (RangeUint8) for sending/receiving Control Change events with a for a specific control.

However, the Interface features might also be suited to control any MIDI gear, which reacts to these MIDI events.

The outbound MIDI channel number can be set globally for all Connectables of the interface (send_channel). Inbound MIDI events can be filtered for a specific MIDI channel or a list of channels (receive_channel).

The interface can be used in a bidirectional mode, input-only mode (no output port; values written to the Connectable objects are dropped) or output-only mode (no input port).

Parameters:
  • input_port_name – Name of the inbound MIDI port. If not specified, the interface works in output-only mode. Use mido.get_input_names() to get a list of output port names.

  • output_port_name – Name of the outbound MIDI port. If not specified, the interface works in input-only mode. Use mido.get_output_names() to get a list of output port names.

  • send_channel – MIDI channel number [0-15] for all outbound MIDI messages. Defaults to 0.

  • receive_channel – If specified, it allows to filter the incomming MIDI events by MIDI channel. Either a single channel number [0-15] or a list of channel numbers which should be processed. Other than the specified MIDI channel(s) are ignored.

control_change(control_channel: int) ControlChangeVariable

Create a Connectable object for this MIDI interface which handles Control Change events.

The logics are pretty simple: The value of an incoming MIDI control change event for the given control number is published as a shc.datatypes.RangeUInt8 value. New values from SHC are sent out as control change MIDI events. The 7-bit MIDI values are converted to a RangeUInt8 by multiplying with 2 and adding 1 to all values >127. This way, the MIDI value 127 is mapped to RangeUInt8(255).

Parameters:

control_channel – The MIDI control number (0-127)

Returns:

The Connectable object with RangeUInt8 type to interact with the specified MIDI control channel

note_on_off(note: int, emulate_toggle: bool = False, off_output_velocity: int = 0, on_output_velocity: int = 127) NoteOnOffVariable

Create a Connectable object for this MIDI interface which handles Note on/off events as boolean values.

The returned object is Writable and Subscribable. It will publish a True value when a Note on event for the specified Note is received and a False for each Note off event. Note on events with velolicty=0 are handled like Note off events. The same mapping is applied for outgoing messages: True → Note on False → Note off. The velocity values for outgoing events can be configured via off_output_velocity and on_output_velocity.

The emulate_toggle parameter can be used to select a different operation mode, which is designed to turn a hardware controller’s “flash” buttons (press sends Note on, release send note off) into toggle buttons. In this mode, an internal boolean state is maintained, which is toggled upon every incoming Note on events. Incoming Note off events are ignored. The state can be updated from within SHC by writing a bool value to the object. Outbound MIDI events are created, when the state is updated from within SHC (as in the normal operation mode) and as a response to incoming MIDI event, to make sure the hardware controller’s button LEDs are always in the right state.

The following table shows a comparison of the two operation modes:

incoming MIDI event sequence

emulate_toggle=False

emulate_toggle=True

Note on

True published

True published, Note on sent back

Note off

False published

True published, Note on sent back

Note on

True published

False published, Note off sent back

Note off

False published

False published, Note off sent back

Warning

For every note number, either note_on_off() or note_velocity() can be used, but not both.

Parameters:
  • note – The MIDI note number to listen to/send events to [0 (C-2) - 127 (G9)].

  • emulate_toggle – If True, emulate a toggle button (see above).

  • off_output_velocity – The MIDI velocity of outbound Note on events. Defaults to 0.

  • on_output_velocity – The MIDI velocity of outbound Note on events. Defaults to 127.

Returns:

The Connectible object with the given specification

note_velocity(note: int) NoteVelocityVariable

Create a Connectable object for this MIDI interface which handles Note on/off events as range values using their velocity value.

For each incoming Note on/off event for the specified note number the velocity value is published as a shc.datatypes.RangeUInt8. The 7-bit MIDI values are converted to a RangeUInt8 by multiplying with 2 and adding 1 to all values >127. This way, the MIDI value 127 is mapped to RangeUInt8(255). When a new value is received from SHC (i.e. written to the object), an outbound Note on/off event is created, with a note velocity corresponding to the value. If the value is 0, a Note off event is created, otherwise a Note on event.

Warning

For every note number, either note_on_off() or note_velocity() can be used, but not both.

Parameters:

note – The MIDI control number (0-127)

Returns:

The Connectable object with RangeUInt8 type to interact with the specified MIDI note.

async start() None

This coroutine is called once on each interface when the SHC application is started via main().

It may be used to initialize network connections and start background Tasks for message handling and event generation. The start coroutines of all interfaces are started in parallel. Timers and Variable’s are only initialized when all start coroutines have returned successfully.

The method should await the completion of the interface startup, i.e. only return when the interface is fully functional. In case of an error, this method may raise and exception or call interface_failure() to terminate the SHC application.

async stop() None

This coroutine is called once on each interface to shut down the SHC application.

This may happen when a SIGTERM (or similar) is received or when a critical error in an interface is reported (via interface_failure() or an exception raised by an interface’s start() method). Thus, the stop method may even be called while start() is still running. It shall be able to handle that situation and stop the half-started interface.

In any case, the stop method shall cause the termination of all pending background task of the interface within a few seconds and only return when all tasks have terminated.