jvconnected.interfaces.midi

jvconnected.interfaces.midi.midi_io

class jvconnected.interfaces.midi.midi_io.MidiIO(*args, **kwargs)[source]

Bases: jvconnected.interfaces.base.Interface

Midi interface handler

Properties
inport_names: List[str] Property(List[str])

list of input port names to use (as str)

outport_names: List[str] Property(List[str])

list of output port names to use (as str)

inports: Dict[str, InputPort] Property(Dict[str, InputPort])

Mapping of InputPort instances stored with the names as keys

outports: Dict[str, OutputPort] Property(Dict[str, OutputPort])

Mapping of OutputPort instances stored with the names as keys

mapped_devices: Dict[str, MappedDevice] Property(Dict[str, MappedDevice])

Mapping of MappedDevice instances stored with the device id as keys

Events
port_state(io_type: jvconnected.utils.IOType, name: str, state: bool)

Fired when a port is added or removed using one of add_input(), add_output(), remove_input(), remove_output().

Parameters
  • io_type (jvconnected.utils.IOType) – The type of port (input or output)

  • name (str) – The port name

  • state (bool) – True if the port was added, False if it was removed

classmethod get_available_inputs() List[str][source]

Get all detected input port names

classmethod get_available_outputs() List[str][source]

Get all detected output port names

async set_engine(engine: jvconnected.engine.Engine)[source]

Attach the interface to a running instance of jvconnected.engine.Engine

This will be called automatically by the engine if the class is in the jvconnected.interfaces.registry.

If the engine is running, the interface will start (using the open() method). Otherwise it will automatically start when the engine does.

automap_engine_devices(*args, **kwargs)[source]

Map the engine’s devices by index

async open()[source]

Open any configured input and output ports and begin communication

async close()[source]

Stop communication and close all input and output ports

async open_ports()[source]

Open any configured input and output ports. (Called by open())

async close_ports()[source]

Close all running input and output ports (Called by close())

async add_input(name: str)[source]

Add an input port

The port name will be added to inport_names and stored in the config.

If MidiIO is running, an instance of InputPort will be created and added to inports.

Parameters

name (str) – The port name (as it appears in get_available_inputs())

async add_output(name: str)[source]

Add an output port

The port name will be added to outport_names and stored in the config.

If MidiIO is running, an instance of OutputPort will be created and added to outports.

Parameters

name (str) – The port name (as it appears in get_available_outputs())

async remove_input(name: str)[source]

Remove an input port from inports and inport_names

If the port exists in inports, it will be closed and removed.

Parameters

name (str) – The port name

async remove_output(name: str)[source]

Remove an output port from outports and outport_names

If the port exists in outports, it will be closed and removed.

Parameters

name (str) – The port name

async send_message(msg: mido.messages.messages.BaseMessage)[source]

Send a message to all output ports in outports

Parameters

msg – The Message to send

map_device(midi_channel: int, device: jvconnected.device.Device)[source]

Connect a jvconnected.device.Device to a mapped_device.MappedDevice

unmap_device(midi_channel: int)[source]

Unmap a device

update_config(*args, **kwargs)[source]

Update the config with current state

jvconnected.interfaces.midi.aioport

class jvconnected.interfaces.midi.aioport.BasePort(*args, **kwargs)[source]

Bases: pydispatch.dispatch.Dispatcher

Async wrapper for mido.ports

Parameters

name (str) – The port name

Properties
name: str Property(str)

The port name

running: bool Property(bool)

Current run state

Attributes

stopped (asyncio.Event)

EXECUTOR: ClassVar[concurrent.futures.ThreadPoolExecutor] = None

A concurrent.futures.ThreadPoolExecutor to use in the run_in_executor() method for all instances of all BasePort subclasses

static get_executor() concurrent.futures.ThreadPoolExecutor[source]

Get or create the EXECUTOR instance to use in the run_in_executor() method

async run_in_executor(fn: Callable) Any[source]

Call the given function in the EXECUTOR instance using asyncio.loop.run_in_executor() and return the result

This method is used to create and manipulate all mido ports to avoid blocking, threaded operations

async open() bool[source]

Open the midi port

Returns

True if the port was successfully opened

Return type

bool

async close()[source]

Close the midi port

class jvconnected.interfaces.midi.aioport.InputPort(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.aioport.BasePort

Async wrapper around mido.ports.BaseInput

Attributes

queue (asyncio.Queue) – Message queue for the port

async receive(timeout: Optional[numbers.Number] = None) Optional[mido.messages.messages.Message][source]

Wait for an incoming message

Parameters

timeout (float, optional) – Time to wait for a message. if None, wait until an item is available

Returns

An instance of mido.Message. If timeout was provided and no message was retrieved, None will be returned.

async queue_get(timeout: Optional[numbers.Number] = None) Any[source]

Convenience method for get() on the queue

Parameters

timeout (float, optional) – Time to wait for an item on the queue. if None, wait until an item is available

task_done()[source]

Convenience method for queue task_done()

class jvconnected.interfaces.midi.aioport.OutputPort(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.aioport.BasePort

Async wrapper around mido.ports.BaseOutput

Attributes

queue (queue.Queue) – Message queue for the port. Since the output port operates in a separate thread, this is a thread-based queue (not async)

async open() bool[source]

Open the midi port

Returns

True if the port was successfully opened

Return type

bool

async send(msg: mido.messages.messages.Message)[source]

Send a message

The message will be placed on the queue and sent from a separate thread

Parameters

msg – The mido.Message to send

class jvconnected.interfaces.midi.aioport.IOPort(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.aioport.BasePort

jvconnected.interfaces.midi.mapper

class jvconnected.interfaces.midi.mapper.Map(name: str = '', group_name: str = '', full_name: str = '', index: int = - 1)[source]

Bases: object

class jvconnected.interfaces.midi.mapper.ControllerMap(name: str = '', group_name: str = '', full_name: str = '', index: int = - 1, controller: int = 0)[source]

Bases: jvconnected.interfaces.midi.mapper.Map

class jvconnected.interfaces.midi.mapper.NoteMap(name: str = '', group_name: str = '', full_name: str = '', index: int = - 1, note: int = 0)[source]

Bases: jvconnected.interfaces.midi.mapper.Map

class jvconnected.interfaces.midi.mapper.AdjustControllerMap(name: str = '', group_name: str = '', full_name: str = '', index: int = - 1, controller: int = 0)[source]

Bases: jvconnected.interfaces.midi.mapper.Map

class jvconnected.interfaces.midi.mapper.MidiMapper(maps: Optional[Sequence[Union[jvconnected.interfaces.midi.mapper.Map, Dict]]] = None)[source]

Bases: object

Container for MIDI mapping definitions

create_map(map_type: str, full_name: str, **kwargs) jvconnected.interfaces.midi.mapper.Map[source]

Create a Map with the given arguments and add it

Parameters
  • map_type (str) – The map type to add

  • full_name (str) –

jvconnected.interfaces.midi.mapped_device

class jvconnected.interfaces.midi.mapped_device.MappedDevice(*args, **kwargs)[source]

Bases: pydispatch.dispatch.Dispatcher

Manages midi input and output for a single Device

Parameters
  • midi_io – The parent MidiIO instance

  • midi_channel (int) – Midi channel to use (0 to 15)

  • device – The Device instance

Attributes
async handle_incoming_message(msg: mido.messages.messages.BaseMessage)[source]

Dispatch an incoming message to all MappedParameter instances

The MappedParameter.handle_incoming_message() method is called for each parameter instance in mapped_params

async send_all_parameters()[source]

Send values for all mapped parameters (full refresh)

async send_message(msg: mido.messages.messages.Message)[source]

Send the given message with midi_io

class jvconnected.interfaces.midi.mapped_device.MappedParameter(*args, **kwargs)[source]

Bases: pydispatch.dispatch.Dispatcher

Handles midi input and output for a single parameter within a jvconnected.device.ParameterGroup

Attributes
  • mapped_device (MappedDevice) – The parent MappedDevice instance

  • param_group (ParameterGroupSpec) – The ParameterGroupSpec definition that describes the parameter

  • param_name (str) – The parameter name within the param_group

  • name (str) – Unique name of the parameter as defined by jvconnected.interfaces.paramspec.ParameterSpec.full_name

  • param_spec – The ParameterSpec instance within the param_group

  • channel (int) – The midi channel to use, typically gathered from mapped_device

  • value_min (int) – Minimum value for the parameter as it exists in the jvconnected.device.ParameterGroup

  • value_max (int) – Maximum value for the parameter as it exists in the jvconnected.device.ParameterGroup

property value_range Number   [read-only]

Total range of values calculated as value_max - value_min

async handle_incoming_message(msg: mido.messages.messages.BaseMessage)[source]

Process an incoming message

If the message is valid for this object, the appropriate setter methods will by called on the param_spec

message_valid(msg: mido.messages.messages.BaseMessage) bool[source]

Check the incoming message parameters to determine whether it should be handled by this object

scale_to_midi(value: Union[numbers.Number, bool]) int[source]

Scale the given value to a range of 0 to 127

If the given value is bool, this will return 127 for True and 0 for False.

Otherwise the result will be \(((value - vmin) / vrange * 127\)

scale_from_midi(value: int) int[source]

Scale a value from \([0,1,..,127]\) to the range expected by the parameter. This results in \((value / 127) * vrange + vmin\)

get_message_type(value: Union[numbers.Number, bool]) str[source]

Get the mido.Message type argument for an outgoing mido.Message with the given value.

Typically one of ['control_change', 'note_on', 'note_off', 'pitchwheel']

get_message_kwargs(value: Union[numbers.Number, bool]) Dict[source]

Get keyword arguments to build an outgoing mido.Message with the given value

build_message(value: Union[numbers.Number, bool]) mido.messages.messages.Message[source]

Create a mido.Message to send for the given parameter value

Uses get_message_type() and get_message_kwargs() for message arguments

get_current_value() Any[source]

Get the current device value

class jvconnected.interfaces.midi.mapped_device.MappedController(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.mapped_device.MappedParameter

MappedParameter subclass that uses midi control-change messages

Attributes

controller (int) – The controller number

message_valid(msg: mido.messages.messages.BaseMessage) bool[source]

Check the incoming message parameters to determine whether it should be handled by this object

get_message_type(value: Union[numbers.Number, bool]) str[source]

Get the mido.Message type argument for an outgoing mido.Message with the given value.

Typically one of ['control_change', 'note_on', 'note_off', 'pitchwheel']

get_message_kwargs(value: Union[numbers.Number, bool]) Dict[source]

Get keyword arguments to build an outgoing mido.Message with the given value

class jvconnected.interfaces.midi.mapped_device.MappedNoteParam(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.mapped_device.MappedParameter

MappedParameter subclass that uses midi note messages

Intended for boolean values. Sends a note_on message with velocity of 127 for True and 0 for False.

Incoming note_on messages with velocity < 0 are treated as True, velocity == 0 and note_off messages are considered False.

Attributes

note (int) – The midi note number

message_valid(msg: mido.messages.messages.BaseMessage) bool[source]

Check the incoming message parameters to determine whether it should be handled by this object

get_message_type(value: Union[numbers.Number, bool]) str[source]

Get the mido.Message type argument for an outgoing mido.Message with the given value.

Typically one of ['control_change', 'note_on', 'note_off', 'pitchwheel']

get_message_kwargs(value: Union[numbers.Number, bool]) Dict[source]

Get keyword arguments to build an outgoing mido.Message with the given value

class jvconnected.interfaces.midi.mapped_device.AdjustController(*args, **kwargs)[source]

Bases: jvconnected.interfaces.midi.mapped_device.MappedController

A MappedController that sends outgoing messages like MappedController, but incoming messages will either increment (>=64) or decrement (<64) the value.

The use case for this would be for parameters that lack a direct setter method, but instead rely on adjustment methods.

An example would be the gain attribute of jvconnected.device.ExposureParams where the value can only be changed using the increase_gain() and decrease_gain() methods.

message_valid(msg: mido.messages.messages.BaseMessage) bool[source]

Check the incoming message parameters to determine whether it should be handled by this object

get_message_type(value: Union[numbers.Number, bool]) str[source]

Get the mido.Message type argument for an outgoing mido.Message with the given value.

Typically one of ['control_change', 'note_on', 'note_off', 'pitchwheel']

get_message_kwargs(value: Union[numbers.Number, bool]) Dict[source]

Get keyword arguments to build an outgoing mido.Message with the given value

jvconnected.interfaces.midi.bcf

class jvconnected.interfaces.midi.bcf.BCLBlock(revision: str = 'F1', text_lines: Sequence[str] = <factory>)[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.BCLBlock

jvconnected.interfaces.midi.bcf_sysex

exception jvconnected.interfaces.midi.bcf_sysex.ResponseError(error_code: int)[source]

Bases: Exception

class jvconnected.interfaces.midi.bcf_sysex.BCLSyxBase(manufacturer: Sequence[ByteString] = (0, 32, 50), device_id: Sequence[ByteString] = (127,), model: Sequence[ByteString] = (20,), command: Sequence[ByteString] = (32,), message_index: int = 0)[source]

Bases: object

property index_msb typing.Sequence[typing.ByteString]   [read-only]

Bits 7-13 of message_index

property index_lsb typing.Sequence[typing.ByteString]   [read-only]

Bits 0-6 of message_index

class jvconnected.interfaces.midi.bcf_sysex.BCLSysex(manufacturer: Sequence[ByteString] = (0, 32, 50), device_id: Sequence[ByteString] = (127,), model: Sequence[ByteString] = (20,), command: Sequence[ByteString] = (32,), message_index: int = 0, bcl_text: str = '')[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.BCLSyxBase

class jvconnected.interfaces.midi.bcf_sysex.BCLReply(manufacturer: Sequence[ByteString] = (0, 32, 50), device_id: Sequence[ByteString] = (127,), model: Sequence[ByteString] = (20,), command: Sequence[ByteString] = (32,), message_index: int = 0, error_code: Sequence[ByteString] = (0,))[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.BCLSyxBase

class jvconnected.interfaces.midi.bcf_sysex.BCLBlock(revision: str = 'F1', text_lines: Sequence[str] = <factory>)[source]

Bases: object

class jvconnected.interfaces.midi.bcf_sysex.ControlBase(message_type: str = 'control_change', channel: int = 0, number: int = 0, mode: str = '', value_min: int = 0, value_max: int = 127, value_default: Union[int, NoneType] = None, show_value: bool = True)[source]

Bases: object

message_type: str = 'control_change'

Midi message type for the encoder

Choices

['note', 'aftertouch', 'control_change', 'program_change', 'pitch_bend']
channel: int = 0

Midi channel (zero-indexed)

number: int = 0

Note or controller number (zero-indexed)

value_min: int = 0

Minimum controller value

value_max: int = 127

Maximum controller value

value_default: Optional[int] = None

Default controller value

show_value: bool = True

Whether the value should be displayed in the 4-digit LED display when adjusted

class jvconnected.interfaces.midi.bcf_sysex.EncoderConf(message_type: str = 'control_change', channel: int = 0, number: int = 0, mode: str = '1dot', value_min: int = 0, value_max: int = 127, value_default: Union[int, NoneType] = None, show_value: bool = True, index: int = 1, encoder_mode: str = 'absolute', resolution: Sequence[int] = (96, 96, 96, 96))[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.ControlBase

index: int = 1

Encoder number starting with 1

mode: str = '1dot'

LED Display mode

Choices

[
    'off', '1dot', '1dot/off', '12dot', '12dot/off', 'bar', 'bar/off',
    'spread', 'pan', 'qual', 'cut', 'damp',
]
encoder_mode: str = 'absolute'

Control mode for the encoder

Choices

[
    'absolute', 'relative-1', 'relative-2', 'relative-3', 'inc/dec',
    'absolute/14', 'relative-1/14', 'relative-2/14', 'relative-3/14',
]
resolution: Sequence[int] = (96, 96, 96, 96)

Steps per revolution at four different rotation speeds

class jvconnected.interfaces.midi.bcf_sysex.FaderConf(message_type: str = 'control_change', channel: int = 0, number: int = 0, mode: str = 'absolute', value_min: int = 0, value_max: int = 127, value_default: Union[int, NoneType] = None, show_value: bool = True, index: int = 1, motor: bool = True, override: str = 'move', keyoverride: str = 'off')[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.ControlBase

index: int = 1

Fader number starting with 1

motor: bool = True

Enable/disable the fader motor

override: str = 'move'

Behavior when motor is False

Choices

['move', 'pickup']
'move'

Immediately send output messages when the fader is moved

'pickup'

Wait for the fader to reach last known value before sending output messages

keyoverride: str = 'off'

Set a button to temporarily disable the fader motor when held

Choices

['off', 1 .. 64]
class jvconnected.interfaces.midi.bcf_sysex.ButtonConf(message_type: str = 'control_change', channel: int = 0, number: int = 0, mode: str = '', value_min: int = 0, value_max: int = 127, value_default: Union[int, NoneType] = None, show_value: bool = True, index: int = 1, button_mode: str = 'toggleon', increment: int = 1)[source]

Bases: jvconnected.interfaces.midi.bcf_sysex.ControlBase

index: int = 1

Button number starting with 1

button_mode: str = 'toggleon'

Choices

['toggleoff', 'toggleon', 'increment']
increment: int = 1

Amount to increment/decrement if button_mode is 'increment'