Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
au_v2_midi_effect_entry.hpp
Go to the documentation of this file.
1#pragma once
2
3// AU v2 MIDI-effect entry point generator
4// For MIDI processors that receive MIDI and produce MIDI with no audio path
5// (`aumi`, kAudioUnitType_MIDIProcessor) — transposers, arpeggiators, chord
6// generators, note filters, humanizers.
7//
8// Usage (in one .cpp file per AU MIDI-effect plugin):
9// #include "my_midi_effect.hpp"
10// #include <pulp/format/au_v2_midi_effect_entry.hpp>
11// PULP_AU_MIDI_EFFECT(MyMidiEffectAU, my_namespace::create_my_midi_effect)
12//
13// Three surfaces must agree or the component is invalid:
14// 1. `descriptor().category == PluginCategory::MidiEffect`
15// 2. the `aumi` component type — `pulp_add_plugin(CATEGORY MidiEffect)`
16// resolves it, or a hand-written Info.plist.au declares it
17// 3. `PULP_AU_MIDI_EFFECT` here
18//
19// The factory is the load-bearing half of (3): a factory only dispatches the
20// selectors its lookup table carries, so registering through the plain
21// `ausdk::AUBaseFactory` makes every host `MusicDeviceMIDIEvent` call return
22// -4 (unimpErr) even though the adapter class implements `HandleMIDIEvent`.
23// `AUMIDIEffectFactory`'s `AUMIDILookup` carries MIDIEvent + SysEx, which is
24// exactly a MIDI processor's selector set (StartNote / StopNote belong to an
25// instrument, not to an `aumi`).
26
27// Apple-only: wraps AudioUnitSDK. No-op on non-Apple so the header stays
28// self-contained on the Linux header-hygiene check.
29#if defined(__APPLE__)
30
33#include <AudioUnitSDK/AUPlugInDispatch.h>
34#include <AudioUnitSDK/ComponentBase.h>
35
36// Generate an AU v2 MIDI-effect entry point.
37// ClassName determines the factory function name: ClassNameFactory, which must
38// match the `factoryFunction` in the bundle's Info.plist (CMake derives it as
39// `<cmake-target>AUFactory`).
40#define PULP_AU_MIDI_EFFECT(ClassName, factory_fn) \
41 PULP_REGISTER_PLUGIN(factory_fn) \
42 class ClassName : public pulp::format::au::PulpAUMidiProcessor { \
43 public: \
44 explicit ClassName(AudioComponentInstance ci) \
45 : PulpAUMidiProcessor(ci) {} \
46 }; \
47 AUSDK_COMPONENT_ENTRY(ausdk::AUMIDIEffectFactory, ClassName)
48
49// ── Multi-plugin bundle variant ──────────────────────────────────────────
50// One binary hosts many MIDI processors (`aumi`). Binds each component to its
51// own factory lexically (via the factory-taking PulpAUMidiProcessor ctor), so
52// processor construction never consults the legacy global slot, and registers a
53// KEYED entry (which never touches that global). Expand once per component; N
54// per binary is legal. The trailing arg is a PluginRegistration braced-init
55// carrying id + AU codes (WITHOUT `.factory` — it is bound from factory_fn and
56// force-assigned, so a stray `.factory` would be ignored); it is variadic so
57// its internal commas survive the preprocessor.
58#define PULP_AU_BUNDLE_MIDI_EFFECT(ClassName, factory_fn, ...) \
59 namespace { \
60 struct ClassName##_Registrar { \
61 ClassName##_Registrar() { \
62 ::pulp::format::PluginRegistration reg __VA_ARGS__; \
63 reg.factory = factory_fn; \
64 ::pulp::format::register_plugin(reg); \
65 } \
66 } ClassName##_registrar_; \
67 } \
68 class ClassName : public pulp::format::au::PulpAUMidiProcessor { \
69 public: \
70 explicit ClassName(AudioComponentInstance ci) \
71 : PulpAUMidiProcessor(ci, factory_fn) {} \
72 }; \
73 AUSDK_COMPONENT_ENTRY(ausdk::AUMIDIEffectFactory, ClassName)
74
75#endif // defined(__APPLE__)