midi_input_stream

Overview

The midi_input_stream class facilitates MIDI communication and data transmission of MIDI messages between a MIDI device and an application.

midi_input_stream dispatches MIDI messages to a MIDI processor: a user-defined construct that follows a specific C++ concept for receiving and interpreting MIDI messages. The MIDI processor acts as an intermediary between MIDI devices and the application. Its purpose is to receive incoming MIDI messages, analyze their content, and extract relevant information. This may include extracting note data, control change values, program change commands, or any other MIDI message content that is of interest to the user. See MIDI Processor

Include

#include <q_io/midi_stream.hpp>

Declaration

class midi_input_stream : non_copyable
{
public:
                        midi_input_stream();
                        midi_input_stream(midi_device const& device);
                        ~midi_input_stream();

   bool                 is_valid() const;

                        template <typename Processor>
                        requires concepts::midi_1_0::Processor<P>
   void                 process(Processor&& proc);

   static void          set_default_device(int id);
};

Expressions

Notation

ms

Object of type midi_input_stream.

md

Object of type midi_device.

id

A unique MIDI device ID (integer).

proc

Object that conforms to the MIDI Processor concept.

Constructors

Expression Semantics

midi_input_stream()

Construct a default midi_input_stream. See set_default_device below.

midi_input_stream(md)

Construct a midi_input_stream using the the midi_device, md.

Take note that midi_input_stream is non-copyable.

Default MIDI device

Expression Semantics

set_default_device(id)

Set the default midi_device used by the default constructor above to the midi_device with the given ID. Once set, the default midi_input_stream constructor will use this midi_device.

Accessor

Expression Semantics Return Type

ms.is_valid()

Check if the midi_input_stream is valid. Do this before any operation on the midi_input_stream. Any operation on an invalid stream is undefined behavior.

bool

Process MIDI

Expression Semantics

ms.process(proc)

Process incoming MIDI messages, given a user provided MIDI processor proc.

Call this function in a loop while to process incoming MIDI messages. This function blocks. It is advisable to place this processing loop in a separate thread.

Example

Monitor incoming MIDI messages:

q::midi_input_stream stream;              (1)
if (stream.is_valid())                    (2)
{
   while (true)                           (3)
      stream.process(midi_processor{});   (4)
}
1 Instantiate a default MIDI stream.
2 Check if the MIDI stream is valid.
3 Infinite loop, processing incoming MIDI messages from the stream.
4 midi_processor is a user defined struct implemented below.
struct midi_processor : midi::processor
{
   using midi::processor::operator();

   void operator()(midi::note_on msg, std::size_t time)
   {
      std::cout
         << "Note On  {"
         << "Channel: "    << int(msg.channel())
         << ", Key: "      << int(msg.key())
         << ", Velocity: " << int(msg.velocity())
         << '}'            << std::endl;
   }

   void operator()(midi::note_off msg, std::size_t time)
   {
      std::cout
         << "Note Off {"
         << "Channel: "    << int(msg.channel())
         << ", Key: "      << int(msg.key())
         << ", Velocity: " << int(msg.velocity())
         << '}'            << std::endl;
   }

   void operator()(midi::poly_aftertouch msg, std::size_t time)
   {
      std::cout
         << "Polyphonic Aftertouch {"
         << "Channel: "    << int(msg.channel())
         << ", Key: "      << int(msg.key())
         << ", Pressure: " << int(msg.pressure())
         << '}'            << std::endl;
   }

   void operator()(midi::control_change msg, std::size_t time)
   {
      std::cout
         << "Control Change {"
         << "Channel: "       << int(msg.channel())
         << ", Controller: "  << int(msg.controller())
         << ", Value: "       << int(msg.value())
         << '}'               << std::endl;
   }

   void operator()(midi::program_change msg, std::size_t time)
   {
      std::cout
         << "Program Change {"
         << "Channel: "    << int(msg.channel())
         << ", Preset: "   << int(msg.preset())
         << '}'            << std::endl;
   }

   void operator()(midi::channel_aftertouch msg, std::size_t time)
   {
      std::cout
         << "Channel Aftertouch {"
         << "Channel: "    << int(msg.channel())
         << ", Pressure: " << int(msg.pressure())
         << '}'            << std::endl;
   }

   void operator()(midi::pitch_bend msg, std::size_t time)
   {
      std::cout
         << "Pitch Bend             {"
         << "Channel: "    << int(msg.channel())
         << ", Value: "    << int(msg.value())
         << '}'            << std::endl;
   }
};