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 byMidiInfoObject.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_ptrinternally, so returned array pointers stay valid untilrelease. MidiInfoNoteSpanis 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/versionare 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 versionWhen 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 handles3. 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
releasehandles obtained fromacquire/acquire_wait; this drops the internalshared_ptr. - Array pointers returned by
note_spansare valid until that handle is released. - Until
is_okis true (i.e. background analysis finishes), a not-yet-loaded handle may be returned. When you must have data (e.g. encoding), useacquire_wait. - Analysis data is immutable after creation, so reads are thread-safe.
acquire/releaseare internally locked.
Distributing
- To embed in your own plugin, just copy the single file
MidiInfoAPI.h. - No linking required (resolved at runtime via
GetProcAddress).