MIDI I/O

Supported bindings: ossia, vst, vst3, clap

Some media systems may have a concept of MIDI input / output. Note that currently this is only implemented for DAW-ish bindings: ossia, VST3, CLAP... Max and Pd do not support it yet (but if there is a standard for passing MIDI messages between objects there I'd love to hear about it !).

There are a few ways to specify MIDI ports.

Here is how one specifies unsafe MIDI ports:

struct
{
  static consteval auto name() { return "MIDI"; }
  struct
  {
    uint8_t bytes[3]{};
    int timestamp{}; // relative to the beginning of the tick
  }* midi_messages{};
  std::size_t size{};
} midi_port;

Or, more clearly:

// the name does not matter
struct midi_message {
  uint8_t bytes[3]{};
  int timestamp{}; // relative to the beginning of the tick
};

struct
{
  static consteval auto name() { return "MIDI"; }
  midi_message* midi_messages{};
  std::size_t size{};
} midi_port;

Here, Avendish bindings will allocate a large enough buffer to store MIDI messages ; this is mainly to enable writing dynamic-allocation-free backends where such a buffer may be allocated statically.

It is also possible to do this if you don't expect to run your code on Arduinos:

struct
{
  // Using a non-fixed size type here will enable MIDI messages > 3 bytes, if for instance your 
  // processor expects to handle SYSEX messages.
  struct msg {
    std::vector<uint8_t> bytes;
    int64_t timestamp{};
  };

  std::vector<msg> midi_messages;
} midi_port;

Helpers

The library provides helper types which are a good compromise between these two solutions, as they are based on boost::container::small_vector: for small numbers of MIDI messages, there will be no memory allocation, but pathological cases (an host sending a thousand MIDI messages in a single tick) can still be handled without loosing messages.

The type is very simple:

halp::midi_bus<"In"> midi;