Skip to content

External C API

MidiInfoObject.aux2 exposes its loaded MIDI analysis to external plugins through a stable C ABI. Other plugins can read BPM, time signature, bars, note spans, channel colors, shared playback time, and more.

Zel9278/midi-info-api

Public C ABI header for the AviUtl2 MIDI Info plugin. Pull in this one file to use it from an external plugin.

MITgithub.com
  • Public header: MidiInfoAPI.h (maintained in the repo above; pulled in here as a submodule, external/midi-info-api. Consumers only need to copy this one file)
  • Entry point: MidiInfo_GetAPI (exported by MidiInfoObject.aux2)
  • Function list: Function reference
  • Working example: Sample plugin

Design

  • A POD-only function table (no STL across the boundary). Compiler/language independent and safe.
  • Analysis handles hold a shared_ptr internally, so returned array pointers stay valid until release.
  • MidiInfoNoteSpan is binary-compatible with the internal representation, so spans are returned by pointer without copying.
  • Forward compatible: the table is append-only; breaking changes bump MIDIINFO_API_VERSION. struct_size / version are included too.

Getting started

1. Obtain the API

MidiInfoObject.aux2 is resident in the same process, so resolve the table via GetModuleHandle + GetProcAddress.

c
#include "MidiInfoAPI.h"

HMODULE h = GetModuleHandleW(L"MidiInfoObject.aux2");
if (!h) return; // the host plugin is not installed

MidiInfo_GetAPI_Fn getapi =
    (MidiInfo_GetAPI_Fn)GetProcAddress(h, MIDIINFO_GETAPI_SYMBOL);

const MidiInfoAPI* api = getapi ? getapi(MIDIINFO_API_VERSION) : NULL;
if (!api) return; // no compatible version

When getapi returns NULL

If your requested requested_version is newer than what the host provides, MidiInfo_GetAPI returns NULL (e.g. an old host with a new request).

2. Acquire an analysis and use it

c
// path = NULL -> the "shared MIDI" (what MIDI Source loaded)
MidiInfoAnalysis* an = api->acquire(NULL);   // or api->acquire(L"C:/song.mid")

if (api->is_ok(an)) {
    double t   = 1.5;                          // seconds
    double bpm = api->bpm_at(an, t);
    uint8_t num = 4, den = 4;
    api->signature_at(an, t, &num, &den);
    uint32_t notes = api->count_at(an, t, 0); // cumulative notes up to now

    const MidiInfoNoteSpan* spans;
    int n = api->note_spans(an, 60, &spans);  // spans for C4 (=60)
    for (int i = 0; i < n; ++i) {
        // spans[i].start / .end (seconds), .channel, .track, .color
    }
}

api->release(an);   // always release acquired handles

3. Sync to playback

Like the built-in objects, you can sync to MIDI Source's shared playback time.

c
double t = api->get_shared_time();   // NaN if unavailable
if (t != t) {                        // NaN check
    t = /* fall back to your own object time */ 0.0;
}

Lifetime & thread safety

  • Always release handles obtained from acquire / acquire_wait; this drops the internal shared_ptr.
  • Array pointers returned by note_spans are valid until that handle is released.
  • Until is_ok is true (i.e. background analysis finishes), a not-yet-loaded handle may be returned. When you must have data (e.g. encoding), use acquire_wait.
  • Analysis data is immutable after creation, so reads are thread-safe. acquire / release are internally locked.

Distributing

  • To embed in your own plugin, just copy the single file MidiInfoAPI.h.
  • No linking required (resolved at runtime via GetProcAddress).