Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::format::au Namespace Reference

Apple-only: the whole header is gated on APPLE so it stays an empty no-op on the Linux header-hygiene check. More...

Classes

class  FactoryPresetTable
 The host-facing factory-preset table for one plug-in instance. More...
class  PulpAUEffect
struct  PulpEditorContext
class  OfflineRenderProperty
 Host offline-render intent for an AU v2 instance. More...
struct  MidiOutputPacketBuilder
class  RenderContextObserverProperty
 kAudioUnitProperty_RenderContextObserver, the v2 form of AUv3's renderContextObserver. More...
class  ScopedHostParamWrite
 RAII marker for the host-write window. Scoped to the calling thread. More...
class  ParameterDisplayNamePublisher
 Coalesces StateStore presentation-name changes and republishes only the affected stable parameter IDs from the host's main thread. More...
class  MidiOutputCallbackPublisher
 Publishes the host's kAudioUnitProperty_MIDIOutputCallback pair from the main thread to the render thread. More...
class  PulpAUInstrument
class  PulpAUMidiProcessor
 AU v2 adapter for a Pulp Processor whose descriptor declares PluginCategory::MidiEffect — an AU MIDI processor, component type aumi (kAudioUnitType_MIDIProcessor). More...

Typedefs

using CocoaViewInfoFiller = bool (*)(void*)
 Cross-TU Cocoa-view hook.

Functions

std::filesystem::path factory_presets_dir_for_binary (const std::filesystem::path &binary)
 Map a plug-in binary's path to the folder holding its factory presets.
std::filesystem::path loaded_bundle_factory_presets_dir ()
 factory_presets_dir_for_binary applied to the image this code is linked into.
UInt32 build_channel_info (const PluginDescriptor &desc, AUChannelInfo *out) noexcept
 Maximum number of AUChannelInfo pairs build_channel_info can produce.
bool effect_has_sidechain_element (const PluginDescriptor &desc) noexcept
 True when an AU v2 unit built from desc exposes a second input element for side-chain audio: the descriptor declares a main input bus plus a second input bus with at least one channel.
UInt32 effect_input_element_count (const PluginDescriptor &desc) noexcept
 Number of AU input elements an AU v2 effect built from desc exposes: 2 with a side-chain bus (main + side chain), otherwise 1.
UInt32 instrument_input_element_count (const PluginDescriptor &desc) noexcept
 Number of AU input elements an AU v2 INSTRUMENT built from desc exposes: 0 without a main input bus (the classic synth), 1 with a main input, 2 with a main input and a side chain.
UInt32 sidechain_element_default_channels (const PluginDescriptor &desc) noexcept
 Default channel count of the side-chain input element, clamped into the adapter's per-bus ceiling.
std::size_t build_input_bus_infos (const PluginDescriptor &desc, ProcessBusBufferInfo *out, std::size_t cap) noexcept
 Fill ProcessBusBufferInfo for an AU v2 EFFECT's input buses: the main input (index 0, role Main) plus — when the descriptor declares a second input bus — a Sidechain bus (index 1, role Sidechain).
UInt32 resolve_sidechain_channels (const AudioBufferList *list, UInt32 expected_channels, UInt32 frame_offset, UInt32 frames, const float **out, std::size_t cap) noexcept
 Resolve the per-channel read pointers of a pulled side-chain buffer list for one render slice.
bool fill_cocoa_view_info (void *outData)
 Fills an AudioUnitCocoaViewInfo with the Pulp Cocoa view factory's bundle URL + class name.
ContractEditorSession * contract_view_session (void *ns_view)
 The session behind an AU v2 contract view (the NSView the contract view factory returned), or null for any other view or once it is invalidated, so an in-process host (automation, tests) can reach the editor and its EditorAutomation.
midi::MidiEvent decode_midi_event (uint8_t inStatus, uint8_t inChannel, uint8_t inData1, uint8_t inData2) noexcept
 Decode a short MIDI status byte and two data bytes into a midi::MidiEvent.
ProcessContext make_render_process_context (double sample_rate, int num_samples, bool offline=false) noexcept
 Build the AU v2 render-path ProcessContext fields that are independent of host callbacks.
void apply_host_callbacks_to_process_context (ProcessContext &ctx, const ausdk::AUBase &unit, detail::PlayheadSnapshot &previous) noexcept
 Populate AU v2 render-context transport metadata from host callbacks and derive per-block playhead change flags.
Float64 tail_samples_to_seconds (int tail_samples, double sample_rate) noexcept
OSStatus fill_parameter_list (const state::StateStore &store, AudioUnitScope scope, AudioUnitParameterID *out_list, UInt32 &out_count)
 GetParameterList: report every global-scope parameter ID.
OSStatus fill_parameter_info (const state::StateStore &store, AudioUnitScope scope, AudioUnitParameterID param_id, AudioUnitParameterInfo &out_info, bool advertise_value_strings)
 GetParameterInfo: name, range, and unit.
OSStatus fill_parameter_clump_property_info (const state::StateStore &store, AudioUnitScope scope, UInt32 &out_size, bool &out_writable)
OSStatus fill_supports_mpe_property_info (bool supports_mpe, AudioUnitScope scope, UInt32 &out_size, bool &out_writable)
 kAudioUnitProperty_SupportsMPE (the v2 bridge of AUv3's supportsMPE).
OSStatus fill_supports_mpe (bool supports_mpe, AudioUnitScope scope, void *out_data)
OSStatus fill_parameter_clump_name (const state::StateStore &store, AudioUnitScope scope, void *out_data)
OSStatus fill_parameter_value_strings (const state::StateStore &store, AudioUnitScope scope, AudioUnitParameterID param_id, CFArrayRef *out_strings)
 GetParameterValueStrings: the enumerated display strings for a DISCRETE parameter.
OSStatus parameter_string_from_value (const state::StateStore &store, void *out_data)
 kAudioUnitProperty_ParameterStringFromValue.
OSStatus parameter_value_from_string (const state::StateStore &store, void *out_data)
 kAudioUnitProperty_ParameterValueFromString — text entry, string → value.
bool host_is_writing_param () noexcept
 True while this thread is inside a host-originated SetParameter.
void wire_host_parameter_bridge (state::StateStore &store, AudioUnit unit, state::ListenerToken &out_listener)
 Wire the editor → host parameter path: gesture begin/end brackets (so a drag records one clean automation pass) and a value-change notification so the host re-reads through GetParameter.
OSStatus save_pulp_state (state::StateStore &store, Processor &processor, CFPropertyListRef *out_data)
 Attach Pulp's serialized state to the AU class-info dictionary the base class produced.
OSStatus restore_pulp_state (state::StateStore &store, Processor &processor, StateRestoreGate &gate, CFPropertyListRef plist)
 Read the pulp-state blob back out of an AU class-info dictionary.
CFArrayRef make_midi_output_names (const char *stream_name)
 Build the one-element CFArrayRef a host reads from kAudioUnitProperty_MIDIOutputCallbackInfo — the names of the plugin's MIDI output streams.
std::size_t instrument_output_element_count (const PluginDescriptor &desc) noexcept
 Number of AU output ELEMENTS (buses) a multi-output instrument advertises: one per declared output bus, floored at 1 and capped at BusBufferSet::kMaxBuses.
std::size_t build_output_bus_infos (const PluginDescriptor &desc, ProcessBusBufferInfo *out, std::size_t cap) noexcept
 Fill one ProcessBusBufferInfo per declared output bus (index 0 = Main, the rest = Aux) from the descriptor.

Variables

constexpr AudioUnitElement kSidechainInputElement = 1
 AU input element that carries the side-chain bus of an AU v2 effect.
constexpr const char * kSidechainElementName = "Side Chain"
 Element name a host shows for the side-chain input.
constexpr std::size_t kMaxChannelInfoPairs = 16
 Upper bound on AUChannelInfo pairs an adapter advertises through SupportedNumChannels.
static constexpr AudioUnitPropertyID kPulpEditorContextProperty = 0x50754564
 Custom AU property ID the Cocoa view factory queries to obtain the host-side Processor + StateStore pointers.
CocoaViewInfoFiller g_cocoa_view_info_filler
constexpr std::size_t kMaxMidiEventsPerBlock = 2048
 RT-safe builder for the MIDIPacketList an AU v2 plugin hands the host via kAudioUnitProperty_MIDIOutputCallback.

Detailed Description

Apple-only: the whole header is gated on APPLE so it stays an empty no-op on the Linux header-hygiene check.

Typedef Documentation

◆ CocoaViewInfoFiller

using pulp::format::au::CocoaViewInfoFiller = bool (*)(void*)

Cross-TU Cocoa-view hook.

The AU adapter classes are compiled into the shared pulp-format library WITHOUT PULP_AU_GUI, while the Cocoa view factory + its AudioUnitCocoaViewInfo filler live in au_v2_cocoa_view.mm, added per-plugin to the *_AU target WITH PULP_AU_GUI. A compile-time #ifdef in the adapters would therefore always be off. Instead, the GUI module registers its filler here at static-init, and the adapters read it (ungated) from GetProperty(kAudioUnitProperty_CocoaUI).

Null when no GUI module is linked (CLAP / Standalone / headless tests) — the adapters then report no Cocoa view and the host uses its generic view. Without this hook the host is NEVER told the plugin has a custom editor.

Function Documentation

◆ apply_host_callbacks_to_process_context()

void pulp::format::au::apply_host_callbacks_to_process_context ( ProcessContext & ctx,
const ausdk::AUBase & unit,
detail::PlayheadSnapshot & previous )
inlinenoexcept

Populate AU v2 render-context transport metadata from host callbacks and derive per-block playhead change flags.

The AU v2 SDK only exposes these callbacks through AUBase during render, but keeping the mapping here lets every adapter share one contract and lets tests install HostCallbackInfo without constructing a full AudioComponentInstance.

◆ build_channel_info()

UInt32 pulp::format::au::build_channel_info ( const PluginDescriptor & desc,
AUChannelInfo * out )
inlinenoexcept

Maximum number of AUChannelInfo pairs build_channel_info can produce.

Pulp's flexible channel contract allows mono / stereo per main bus (validate_channel_layout constrains every count to {1, 2}), so the worst case is a handful of pairs. The bound itself, kMaxChannelInfoPairs, lives in au_v2_common.hpp so the instrument adapter shares it. Derive the AU kAudioUnitProperty_SupportedNumChannels table from a Pulp PluginDescriptor. Surfaces which (input, output) channel-count pairs the plugin handles so hosts and auval can negotiate a layout instead of guessing.

Reports the channel counts the descriptor ACTUALLY declares (clamped into the supported {1, 2} flex range per validate_channel_layout), so asymmetric configs are not hidden from the host:

  • Instrument / generator with NO input bus (0 input channels): report inChannels = 0 paired with each supported output width up to the declared maximum — {0,1} for a mono synth, {0,1} and {0,2} for a stereo synth.
  • Symmetric effect (declared input width == output width): report the matching in == out flex ladder up to that width — {1,1} for mono, {1,1} and {2,2} for stereo. Mono-down flex stays available so a host can run a stereo plugin on a mono track.
  • Asymmetric effect (declared input width != output width, e.g. a mono-in / stereo-out widener): report the single exact declared pair, e.g. {1,2}. Hiding it behind a matched ladder would mis-report the plugin's real capability.

Writes at most kMaxChannelInfoPairs entries into out and returns the count. out must point to storage for at least kMaxChannelInfoPairs entries. Pure / allocation-free so the AU SupportedNumChannels override can fill caller-owned storage.

◆ build_input_bus_infos()

std::size_t pulp::format::au::build_input_bus_infos ( const PluginDescriptor & desc,
ProcessBusBufferInfo * out,
std::size_t cap )
inlinenoexcept

Fill ProcessBusBufferInfo for an AU v2 EFFECT's input buses: the main input (index 0, role Main) plus — when the descriptor declares a second input bus — a Sidechain bus (index 1, role Sidechain).

The side-chain info is emitted INACTIVE. The adapter activates it for a block only after it has pulled audio from the side-chain input element (element 1, see effect_has_sidechain_element); while the host leaves that element unconnected the bus stays inactive and Processor::sidechain_input() returns nullptr, the same "not connected" contract the VST3, CLAP and AU v3 adapters use. The bus->buffer mapping is identical either way.

Pure / allocation-free and unit-testable without an AudioComponentInstance. Names view into desc, which must outlive the filled infos. The adapter sets each view's .active from the live host channel count before process().

◆ build_output_bus_infos()

std::size_t pulp::format::au::build_output_bus_infos ( const PluginDescriptor & desc,
ProcessBusBufferInfo * out,
std::size_t cap )
inlinenoexcept

Fill one ProcessBusBufferInfo per declared output bus (index 0 = Main, the rest = Aux) from the descriptor.

Bus names are string_views INTO desc, so desc must outlive the filled infos (the render path views the adapter's cached descriptor, whose strings live for the plugin's lifetime).

Pure / allocation-free: the render path uses it to tag each per-block output view so a multi-out processor that overrides process(ProcessBuffers&) sees stable bus identity, and it is unit-testable without a live AU host. Writes at most cap entries and returns the count.

◆ contract_view_session()

ContractEditorSession * pulp::format::au::contract_view_session ( void * ns_view)

The session behind an AU v2 contract view (the NSView the contract view factory returned), or null for any other view or once it is invalidated, so an in-process host (automation, tests) can reach the editor and its EditorAutomation.

Defined in au_v2_contract_view.mm. Main thread.

◆ decode_midi_event()

midi::MidiEvent pulp::format::au::decode_midi_event ( uint8_t inStatus,
uint8_t inChannel,
uint8_t inData1,
uint8_t inData2 )
noexcept

Decode a short MIDI status byte and two data bytes into a midi::MidiEvent.

Exposed at namespace scope so the AU-MIDI routing can be unit tested without constructing a real AudioComponentInstance.

Channel voice messages arrive at AUMIDIBase::HandleMIDIEvent already split into inStatus (top nibble, e.g. 0x80, 0xB0) and inChannel (bottom nibble, 0–15). This helper re-combines them into a single status byte so the resulting choc::midi::ShortMessage has a consistent on-the-wire layout regardless of whether the caller already split the channel out.

Parameters
inStatusStatus byte (top nibble, bottom nibble optional).
inChannelMIDI channel (0–15). Ignored for system messages.
inData1Data byte 1 (note number, CC number, etc.).
inData2Data byte 2 (velocity, CC value, etc.).
Returns
MidiEvent with sample_offset == 0 — callers should set the sample offset themselves before enqueuing.

◆ effect_has_sidechain_element()

bool pulp::format::au::effect_has_sidechain_element ( const PluginDescriptor & desc)
inlinenoexcept

True when an AU v2 unit built from desc exposes a second input element for side-chain audio: the descriptor declares a main input bus plus a second input bus with at least one channel.

AU input elements are positional, so a side chain is only reachable behind a main input; the Processor API exposes exactly one side-chain slot (input bus 1), so further input buses are not surfaced. Shared by the effect and the instrument adapter.

◆ effect_input_element_count()

UInt32 pulp::format::au::effect_input_element_count ( const PluginDescriptor & desc)
inlinenoexcept

Number of AU input elements an AU v2 effect built from desc exposes: 2 with a side-chain bus (main + side chain), otherwise 1.

An effect always has a main input element, even for a descriptor that declares none.

◆ factory_presets_dir_for_binary()

std::filesystem::path pulp::format::au::factory_presets_dir_for_binary ( const std::filesystem::path & binary)

Map a plug-in binary's path to the folder holding its factory presets.

Recognises the two Apple bundle shapes a Pulp plug-in is loaded from:

  • Foo.component/Contents/MacOS/Foo → Foo.component/Contents/Resources/Presets
  • Foo.appex/Foo (flat iOS bundle) → Foo.appex/Presets

Returns an empty path for a binary that is not inside a bundle — a unit-test executable, a standalone build — so discovery degrades to "no factory presets" instead of scanning an unrelated directory.

◆ fill_cocoa_view_info()

bool pulp::format::au::fill_cocoa_view_info ( void * outData)

Fills an AudioUnitCocoaViewInfo with the Pulp Cocoa view factory's bundle URL + class name.

Defined in au_v2_cocoa_view.mm (PULP_AU_GUI); installed into g_cocoa_view_info_filler at static-init. Returns false if the factory class isn't available. outData must point to an AudioUnitCocoaViewInfo.

◆ fill_parameter_clump_name()

OSStatus pulp::format::au::fill_parameter_clump_name ( const state::StateStore & store,
AudioUnitScope scope,
void * out_data )

◆ fill_parameter_clump_property_info()

OSStatus pulp::format::au::fill_parameter_clump_property_info ( const state::StateStore & store,
AudioUnitScope scope,
UInt32 & out_size,
bool & out_writable )

◆ fill_parameter_info()

OSStatus pulp::format::au::fill_parameter_info ( const state::StateStore & store,
AudioUnitScope scope,
AudioUnitParameterID param_id,
AudioUnitParameterInfo & out_info,
bool advertise_value_strings )

GetParameterInfo: name, range, and unit.

advertise_value_strings controls kAudioUnitParameterFlag_ValuesHaveStrings for parameters that declare a to_string or explicit value labels. Setting the flag is what makes a host ASK for display text — through GetParameterValueStrings for discrete parameters and kAudioUnitProperty_ParameterStringFromValue / ...ValueFromString for continuous ones. An adapter that does not serve those must pass false, or the host asks a question nothing answers.

◆ fill_parameter_list()

OSStatus pulp::format::au::fill_parameter_list ( const state::StateStore & store,
AudioUnitScope scope,
AudioUnitParameterID * out_list,
UInt32 & out_count )

GetParameterList: report every global-scope parameter ID.

A non-global scope reports zero parameters rather than an error, matching AUBase.

◆ fill_parameter_value_strings()

OSStatus pulp::format::au::fill_parameter_value_strings ( const state::StateStore & store,
AudioUnitScope scope,
AudioUnitParameterID param_id,
CFArrayRef * out_strings )

GetParameterValueStrings: the enumerated display strings for a DISCRETE parameter.

Continuous parameters reach the host through kAudioUnitProperty_ParameterStringFromValue instead and report kAudioUnitErr_InvalidPropertyValue here. A null out_strings is the GetPropertyInfo availability query and returns noErr for a discrete parameter without allocating.

◆ fill_supports_mpe()

OSStatus pulp::format::au::fill_supports_mpe ( bool supports_mpe,
AudioUnitScope scope,
void * out_data )

◆ fill_supports_mpe_property_info()

OSStatus pulp::format::au::fill_supports_mpe_property_info ( bool supports_mpe,
AudioUnitScope scope,
UInt32 & out_size,
bool & out_writable )

kAudioUnitProperty_SupportsMPE (the v2 bridge of AUv3's supportsMPE).

An MPE-aware host reads it to decide whether to route an MPE zone's per-member-channel stream to this unit at all, so a plug-in with MPE handling wired but this property unanswered is simply never offered MPE input. Report kAudioUnitErr_InvalidProperty when the plug-in did not opt in, which is what a host reads as "no" and matches leaving the property unimplemented.

◆ host_is_writing_param()

bool pulp::format::au::host_is_writing_param ( )
noexcept

True while this thread is inside a host-originated SetParameter.

The store's UI-push listener fires inline on the writing thread, so it consults this to skip echoing the host's own write back at it.

◆ instrument_input_element_count()

UInt32 pulp::format::au::instrument_input_element_count ( const PluginDescriptor & desc)
inlinenoexcept

Number of AU input elements an AU v2 INSTRUMENT built from desc exposes: 0 without a main input bus (the classic synth), 1 with a main input, 2 with a main input and a side chain.

MusicDeviceBase pulls no input itself, so the instrument adapter pulls each of these elements by hand in Render().

◆ instrument_output_element_count()

std::size_t pulp::format::au::instrument_output_element_count ( const PluginDescriptor & desc)
inlinenoexcept

Number of AU output ELEMENTS (buses) a multi-output instrument advertises: one per declared output bus, floored at 1 and capped at BusBufferSet::kMaxBuses.

Passed to the MusicDeviceBase base constructor so an AU host (Logic, Live, Cubase) lists each output bus — main plus every aux — and can route them to separate mixer channels.

The cap is load-bearing, not cosmetic: Render() only fills output views up to kMaxOutputBuses (== BusBufferSet::kMaxBuses), so advertising more AU elements than that would materialise output elements the render path never touches — the host would show buses that stay permanently silent. Clamp here so the advertised element count and the routed count agree; the constructor's caller (registry_output_element_count) logs a warning when a descriptor's declared bus count exceeds the cap so the truncation is observable, not silent.

Pure so the multi-output element-count contract is unit-testable without an AudioComponentInstance. Mirrors how VST3 (addAudioOutput per bus) and CLAP (audio-ports per bus) already iterate descriptor().output_buses, and how CLAP caps routed output buses at its own kMaxOutputBuses.

◆ loaded_bundle_factory_presets_dir()

std::filesystem::path pulp::format::au::loaded_bundle_factory_presets_dir ( )

factory_presets_dir_for_binary applied to the image this code is linked into.

Empty when that image is not inside a bundle.

◆ make_midi_output_names()

CFArrayRef pulp::format::au::make_midi_output_names ( const char * stream_name)

Build the one-element CFArrayRef a host reads from kAudioUnitProperty_MIDIOutputCallbackInfo — the names of the plugin's MIDI output streams.

The host owns and releases the array, so it is created with a +1 retain.

◆ make_render_process_context()

ProcessContext pulp::format::au::make_render_process_context ( double sample_rate,
int num_samples,
bool offline = false )
inlinenoexcept

Build the AU v2 render-path ProcessContext fields that are independent of host callbacks.

offline is the host's kAudioUnitProperty_OfflineRender value (see OfflineRenderProperty): a host doing a faster-than-realtime bounce sets it before rendering, and the block is then reported as ProcessMode::Offline + RenderSpeedHint::FasterThanRealtime, the same mapping the AU v3, VST3, and CLAP adapters use.

◆ parameter_string_from_value()

OSStatus pulp::format::au::parameter_string_from_value ( const state::StateStore & store,
void * out_data )

kAudioUnitProperty_ParameterStringFromValue.

The host owns and releases outString, so it is created with a +1 retain; inValue == nullptr means "use the parameter's current value".

◆ parameter_value_from_string()

OSStatus pulp::format::au::parameter_value_from_string ( const state::StateStore & store,
void * out_data )

kAudioUnitProperty_ParameterValueFromString — text entry, string → value.

◆ resolve_sidechain_channels()

UInt32 pulp::format::au::resolve_sidechain_channels ( const AudioBufferList * list,
UInt32 expected_channels,
UInt32 frame_offset,
UInt32 frames,
const float ** out,
std::size_t cap )
inlinenoexcept

Resolve the per-channel read pointers of a pulled side-chain buffer list for one render slice.

frame_offset is the slice start within the pulled block (non-zero only while scheduled parameters split a render into slices) and frames the slice length. Writes up to cap pointers and returns the channel count, or 0 when the list is absent, malformed (wrong shape, null or undersized storage) or wider than cap — a malformed side chain is reported as "not connected" rather than handing the processor bad pointers.

Pure / allocation-free. Expects the non-interleaved Float32 layout the side-chain element's ValidFormat enforces (one channel per buffer).

◆ restore_pulp_state()

OSStatus pulp::format::au::restore_pulp_state ( state::StateStore & store,
Processor & processor,
StateRestoreGate & gate,
CFPropertyListRef plist )

Read the pulp-state blob back out of an AU class-info dictionary.

A dictionary without the key restores nothing and succeeds (an AU preset saved by a different plugin version is not an error).

gate is held across the restore so it cannot run while the audio thread is inside Processor::process(). Hosts set class info on the main thread while the unit is initialized and rendering, and Processor::deserialize_plugin_state() is documented as running with the audio thread stopped.

◆ save_pulp_state()

OSStatus pulp::format::au::save_pulp_state ( state::StateStore & store,
Processor & processor,
CFPropertyListRef * out_data )

Attach Pulp's serialized state to the AU class-info dictionary the base class produced.

Takes ownership semantics identical to AUBase::SaveState: *out_data is replaced with a dictionary carrying the pulp-state blob.

◆ sidechain_element_default_channels()

UInt32 pulp::format::au::sidechain_element_default_channels ( const PluginDescriptor & desc)
inlinenoexcept

Default channel count of the side-chain input element, clamped into the adapter's per-bus ceiling.

0 when the descriptor declares no side chain.

◆ tail_samples_to_seconds()

Float64 pulp::format::au::tail_samples_to_seconds ( int tail_samples,
double sample_rate )
inlinenoexcept

◆ wire_host_parameter_bridge()

void pulp::format::au::wire_host_parameter_bridge ( state::StateStore & store,
AudioUnit unit,
state::ListenerToken & out_listener )

Wire the editor → host parameter path: gesture begin/end brackets (so a drag records one clean automation pass) and a value-change notification so the host re-reads through GetParameter.

All three are plain AUEventListenerNotify calls on the editing thread — never AudioUnitSetParameter on ourselves, and never from the render thread.

unit is captured by value, so the callbacks never dereference the adapter after it is gone. The returned listener token must be held for the adapter's lifetime.

Variable Documentation

◆ g_cocoa_view_info_filler

CocoaViewInfoFiller pulp::format::au::g_cocoa_view_info_filler
extern

◆ kMaxChannelInfoPairs

std::size_t pulp::format::au::kMaxChannelInfoPairs = 16
inlineconstexpr

Upper bound on AUChannelInfo pairs an adapter advertises through SupportedNumChannels.

Descriptor widths are validated into {1, 2}, so a table is a handful of pairs; the constant is a small fixed size so callers back it with instance storage and never allocate.

◆ kMaxMidiEventsPerBlock

std::size_t pulp::format::au::kMaxMidiEventsPerBlock = 2048
inlineconstexpr

RT-safe builder for the MIDIPacketList an AU v2 plugin hands the host via kAudioUnitProperty_MIDIOutputCallback.

Backed by a fixed-size byte buffer so building the list never allocates on the audio thread — the same pre-reserved-storage discipline the MIDI input queues use.

Short channel-voice / system messages (1–3 bytes) and the Processor's output SysEx are merged into a single ascending-sample_offset order before being appended via the CoreMIDI packet-list builders (which write into the caller's buffer). CoreMIDI packet lists are expected time-ordered, so the merge guarantees a SysEx at offset 0 is delivered before a note at offset 64 even though they live in separate sidecars. Each packet carries the Processor's per-event sample_offset, clamped to the current block, as its timestamp — the offset semantics kAudioUnitProperty_MIDIOutputCallback documents.

◆ kPulpEditorContextProperty

AudioUnitPropertyID pulp::format::au::kPulpEditorContextProperty = 0x50754564
staticconstexpr

Custom AU property ID the Cocoa view factory queries to obtain the host-side Processor + StateStore pointers.

Fixes the former "dual-Processor" bug where the Cocoa view created a second Processor instance that silently desynchronized from the host's audio-thread Processor. Property is Global scope, read-only.

◆ kSidechainElementName

const char* pulp::format::au::kSidechainElementName = "Side Chain"
inlineconstexpr

Element name a host shows for the side-chain input.

Logic labels its "Side Chain" pop-up from the presence of this second input element.

◆ kSidechainInputElement

AudioUnitElement pulp::format::au::kSidechainInputElement = 1
inlineconstexpr

AU input element that carries the side-chain bus of an AU v2 effect.