libremidi Documentation

repository·master·Indexed 20 days ago

https://github.com/celtera/libremidi

A high-performance, cross-platform C++20 library for real-time MIDI 1 and MIDI 2 and MIDI file I/O. It supports Windows, macOS, Linux, Android, iOS, and WebMIDI (Emscripten), providing robust support for Universal MIDI Packet (UMP) and various backends including ALSA, JACK, PipeWire, WinMM, UWP, WinMIDI, and CoreMIDI. The library supports C++20 modules, header-only mode, and zero-allocation MIDI messages via the LIBREMIDI_SLIM_MESSAGE macro.

Tokens
12.6K
Snippets
38
Records
56
Agent score
72%

What's inside libremidi

  1. Overview of libremidi capabilities

    master

    libremidi is a cross-platform C++20 MIDI library designed for both file-based and real-time MIDI I/O. It supports MIDI 2.0 on specific modern platforms and provides several advanced features for high-performance and real-time applications:

    • Real-time I/O Support:
      • macOS: version 11 or newer.
      • Linux: Kernel 6.5 or newer.
      • Windows: Windows 11 Insiders builds or Windows 10 with Windows MIDI Services installed.
    • Device Management: Uses libremidi::observer for device enumeration and hotplug support across all backends. Ports are identified by handles rather than numbers to ensure stability during unplugging/replugging.
    • High Performance & Real-time Safety:
      • Reduced memory allocations and virtual function calls.
      • Support for fixed message sizes using boost::static_vector for hard real-time requirements.
      • Support for boost::small_vector for optimized general use.
    • Precision Timing: Uses integer timestamps (defaulting to nanoseconds) to avoid floating-point precision issues. Supports multiple timestamping methods including relative, absolute monotonic clock, sample-based, or custom methods.
    • Modern C++ Integration: Utilizes C++20 features like std::span, std::function, and standard threading primitives (std::thread, std::jthread).
    • Extensive Backend Support: Includes ALSA RawMidi, PipeWire, Windows UWP, WebMIDI (via Emscripten), JACK, Computer keyboard input, and Network I/O.
  2. Overview of libremidi

    master
    libremidi is a cross-platform C++20 library designed for real-time and MIDI file input and output. It provides comprehensive support for both MIDI 1 and MIDI 2 protocols across various desktop platforms (Windows, macOS, Linux) and mobile/web environments (Android, iOS, Emscripten).
  3. Share a single backend context across multiple MIDI objects

    master

    By default, each libremidi object creates its own backend context (e.g., a JACK client, a PipeWire main loop, or a CoreMIDI MIDIClientRef). To share a single context across multiple objects, you must pass a configuration derived from an existing object or a specific backend configuration. This is useful for ensuring multiple MIDI inputs/outputs or observers operate within the same backend environment.

    #include <libremidi/configurations.hpp>
    
    // Example: Using a specific backend configuration
    libremidi::midi_in in{
        libremidi::input_configuration{.on_message = ...}
      , libremidi::alsa_seq::input_configuration{
          .client_name = "my client"
      } 
    };
  4. Handle errors in the MIDI file API using exceptions

    master
    Unlike the real-time API, the MIDI file API uses standard C++ exceptions for error handling. This is due to the non-real-time nature of file operations. When performing operations with the MIDI file API, wrap calls in try-catch blocks to handle potential failures.
  5. Default keyboard mapping for MIDI

    master

    The keyboard backend uses a specific default mapping for keys.

    • Notes: The middle row (C, D, E, F, G, A, B, C, D, E, F, G) maps to musical notes.
    • Velocity Steps: Keys V0 through V12 set the velocity in steps of approximately 10 (ranging from 0 to 127).
    • Octave Control: O- and O+ keys increase or decrease the octave.
    • Velocity Fine-tuning: V- and V+ keys increase or decrease the velocity by 10.
  6. Getting started with libremidi

    master
    To begin using libremidi, you need to compile the library and integrate it into your project. The library supports both header-only usage and CMake integration. Once set up, you can perform basic MIDI operations such as enumerating ports, handling MIDI 1 and MIDI 2 input/output, and working with MIDI files.
  7. Perform basic MIDI operations

    master

    The core functionality of libremidi involves:

    • Enumerating ports: Discover available MIDI ports on your system.
    • MIDI 1 I/O: Handle standard MIDI 1 messages for both input and output.
    • MIDI 2 I/O: Handle MIDI 2 messages for both input and output.
    • MIDI file support: Read and process MIDI files.
  8. Use asynchronous runtimes for non-blocking MIDI input

    master

    To maintain imperative coding styles while benefiting from non-blocking MIDI processing, it is recommended to use an asynchronous runtime.

    A modern implementation pattern using C++20 coroutines with Boost.Cobalt is provided in the coroutines.cpp example in the repository.

  9. Send MIDI 1 messages to a device

    master

    To send MIDI 1 messages using libremidi, you must first instantiate a libremidi::midi_out object and open a MIDI port. You can open a port by retrieving a port handle (e.g., using libremidi::midi1::out_default_port()) and passing it to midi.open_port(). Once a port is open, you can transmit messages using several different methods depending on your data format.

    // Create the midi object
    libremidi::midi_out midi;
    
    // Open a given midi port
    if(auto port = libremidi::midi1::out_default_port())
      midi.open_port(*port);
    
    // Send a message
    midi.send_message(144, 110, 40);
  10. Add libremidi to a CMake project via add_subdirectory

    master

    If you have added libremidi to your project as a git submodule (e.g., in 3rdparty/libremidi), you can integrate it using add_subdirectory. Ensure you link your target against the libremidi target using target_link_libraries.

    project(my_app)
    
    # example of folder structure
    add_subdirectory(3rdparty/libremidi)
    
    add_executable(my_app src/main.cpp)
    
    target_link_libraries(my_app PRIVATE libremidi)