Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
au_v2_common.hpp
Go to the documentation of this file.
1#pragma once
2
4
5// Pieces of the AU v2 adapter surface that no single adapter owns.
6//
7// Pulp has three AU v2 adapters — the effect (`AUMIDIEffectBase`), the
8// instrument (`MusicDeviceBase`), and the MIDI processor (`MusicDeviceBase`
9// with no audio buses) — and the AudioUnitSDK forces each to derive a
10// different base. Everything here is expressed against `AUBase`, `StateStore`,
11// `Processor`, or plain bytes rather than a specific adapter base, so all
12// three route through one implementation instead of three copies that drift.
13//
14// Apple-only: the whole header is gated on __APPLE__ so it stays an empty
15// no-op on the Linux header-hygiene check.
16#if defined(__APPLE__)
17
18#include <AudioUnitSDK/AUBase.h>
19
20#include <cstddef>
21#include <AudioToolbox/AudioUnitProperties.h>
22
23#include <AudioUnit/AudioUnit.h>
24#include <CoreFoundation/CoreFoundation.h>
25#include <CoreMIDI/MIDIServices.h>
26#include <mach/mach_time.h>
28#include <pulp/format/detail/host_sample_position.hpp>
29
32#include <pulp/format/detail/midi_out_offset.hpp>
33#include <pulp/format/detail/playhead_diff.hpp>
34#include <pulp/midi/buffer.hpp>
35#include <pulp/midi/message.hpp>
37#include <pulp/state/store.hpp>
38
39#include <array>
40#include <atomic>
41#include <cstdint>
42#include <functional>
43#include <limits>
44#include <memory>
45
46namespace pulp::format {
50} // namespace pulp::format
51
52namespace pulp::format::au {
53
58inline constexpr std::size_t kMaxChannelInfoPairs = 16;
59
65static constexpr AudioUnitPropertyID kPulpEditorContextProperty = 0x50754564; // 'PuEd'
66
75
88using CocoaViewInfoFiller = bool (*)(void*);
90
95bool fill_cocoa_view_info(void* outData);
96
102
121 uint8_t inChannel,
122 uint8_t inData1,
123 uint8_t inData2) noexcept;
124
132 int num_samples,
133 bool offline = false) noexcept {
134 ProcessContext ctx;
135 ctx.sample_rate = sample_rate;
136 ctx.num_samples = num_samples;
140 return ctx;
141}
142
162public:
163 OSStatus property_info(AudioUnitScope scope, UInt32& out_size,
164 bool& out_writable) const noexcept {
165 if (scope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
166 out_size = sizeof(UInt32);
167 out_writable = true;
168 return noErr;
169 }
170
171 OSStatus get(AudioUnitScope scope, void* out_data) const noexcept {
172 if (scope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
173 if (!out_data) return kAudioUnitErr_InvalidPropertyValue;
174 *static_cast<UInt32*>(out_data) = offline() ? 1u : 0u;
175 return noErr;
176 }
177
178 OSStatus set(AudioUnitScope scope, const void* in_data,
179 UInt32 in_size) noexcept {
180 if (scope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
181 if (!in_data || in_size < sizeof(UInt32))
182 return kAudioUnitErr_InvalidPropertyValue;
183 offline_.store(*static_cast<const UInt32*>(in_data) != 0,
184 std::memory_order_release);
185 written_since_session_start_.store(true, std::memory_order_release);
186 return noErr;
187 }
188
193 void begin_session() noexcept {
194 if (!written_since_session_start_.exchange(false,
195 std::memory_order_acq_rel))
196 offline_.store(false, std::memory_order_release);
197 }
198
200 bool offline() const noexcept {
201 return offline_.load(std::memory_order_acquire);
202 }
203
204private:
205 std::atomic<bool> offline_{false};
206 std::atomic<bool> written_since_session_start_{false};
207};
208
215 ProcessContext& ctx,
216 const ausdk::AUBase& unit,
217 detail::PlayheadSnapshot& previous) noexcept {
218 Float64 beat = 0.0;
219 Float64 tempo = 0.0;
220 if (unit.CallHostBeatAndTempo(&beat, &tempo) == noErr) {
221 ctx.position_beats = beat;
222 ctx.transport_validity.set(TransportField::BeatPosition);
223 if (tempo > 0.0) {
224 ctx.tempo_bpm = tempo;
225 ctx.transport_validity.set(TransportField::Tempo);
226 }
227 }
228
229 UInt32 delta_samples = 0;
230 Float32 ts_num = 0.0f;
231 UInt32 ts_denom = 0;
232 Float64 current_measure_downbeat = 0.0;
233 if (unit.CallHostMusicalTimeLocation(&delta_samples, &ts_num, &ts_denom,
234 &current_measure_downbeat) == noErr) {
235 if (ts_num > 0.0f && ts_denom > 0) {
236 ctx.time_sig_numerator = static_cast<int>(ts_num);
237 ctx.time_sig_denominator = static_cast<int>(ts_denom);
238 ctx.transport_validity.set(TransportField::TimeSignature);
239 }
240 }
241
242 Boolean is_playing = false;
243 Boolean transport_state_changed = false;
244 Float64 current_sample_in_timeline = 0.0;
245 Boolean is_cycling = false;
246 Float64 cycle_start = 0.0;
247 Float64 cycle_end = 0.0;
248 if (unit.CallHostTransportState(&is_playing, &transport_state_changed,
249 &current_sample_in_timeline, &is_cycling,
250 &cycle_start, &cycle_end) == noErr) {
251 ctx.is_playing = (is_playing != 0);
252 ctx.is_looping = (is_cycling != 0);
253 ctx.transport_validity.set(TransportField::Playing);
254 ctx.transport_validity.set(TransportField::Looping);
255 if (const auto position = detail::host_sample_position(current_sample_in_timeline)) {
256 ctx.position_samples = *position;
257 ctx.transport_validity.set(TransportField::SamplePosition);
258 }
259 if (ctx.is_looping) {
260 ctx.loop_start_beats = cycle_start;
261 ctx.loop_end_beats = cycle_end;
262 ctx.transport_validity.set(TransportField::LoopRange);
263 }
264 }
265
266 static mach_timebase_info_data_t timebase = {0, 0};
267 if (timebase.denom == 0) mach_timebase_info(&timebase);
268 if (timebase.denom != 0) {
269 const uint64_t now = mach_absolute_time();
270 ctx.host_time_ns = static_cast<int64_t>(
271 (now * timebase.numer) / timebase.denom);
272 ctx.transport_validity.set(TransportField::HostTime);
273 }
274
275 detail::derive_bar_from_beats(ctx);
276 if (ctx.has_transport(TransportField::BeatPosition) &&
277 ctx.has_transport(TransportField::TimeSignature)) {
278 ctx.transport_validity.set(TransportField::Bar);
279 }
280 detail::compute_playhead_changes(
281 ctx, previous, detail::TransportDiffMode::FieldValidity);
282}
283
284inline Float64 tail_samples_to_seconds(int tail_samples,
285 double sample_rate) noexcept {
286 if (tail_samples < 0) return std::numeric_limits<Float64>::infinity();
287 if (tail_samples == 0 || sample_rate <= 0.0) return 0.0;
288 return static_cast<Float64>(tail_samples) / sample_rate;
289}
290
304//
305// The per-block MIDI event budget shared by every AU v2 adapter's
306// `kMaxEventsPerBlock` and the output packet builder's `kMaxOutputEvents`.
307// This lives in one place on purpose: if the input bound and the output bound
308// ever drift apart, host-bound MIDI is silently truncated on a dense
309// arp/generator block. Reference this constant, never re-spell the literal.
310inline constexpr std::size_t kMaxMidiEventsPerBlock = 2048;
311
313 // Bound the per-block output by the same event budget the MIDI input path
314 // reserves, so a dense arp/generator block is delivered in full rather than
315 // silently truncated. Short messages are at most 3 wire bytes; the CoreMIDI
316 // packet header + per-packet overhead is small, so a budget of
317 // (events * ~16 bytes) comfortably covers the worst case. SysEx shares the
318 // same buffer and yields to the byte bound. Events past the buffer bound are
319 // dropped (counted in `dropped`) rather than overflowing.
320 static constexpr std::size_t kMaxOutputEvents = kMaxMidiEventsPerBlock;
321 static constexpr std::size_t kBufferBytes = kMaxOutputEvents * 16;
322 alignas(MIDIPacketList) std::array<std::uint8_t, kBufferBytes> storage{};
323
324 // Number of events dropped on the most recent build() because the packet
325 // buffer or the merge index filled. 0 in steady state; a diagnostic the
326 // adapter / tests can read to detect a too-dense block.
327 std::size_t dropped = 0;
328
337 const MIDIPacketList* build(const midi::MidiBuffer& midi_out,
338 std::uint32_t frame_count) noexcept {
339 dropped = 0;
340
341 // Build a merge index over both sources (short events + sysex) so we can
342 // emit in ascending sample_offset order. Each source is referenced by a
343 // tagged index; the index array is fixed-capacity (no allocation).
344 struct Ref {
345 std::int32_t offset;
346 std::uint32_t order; // stable tiebreak: preserves per-source order
347 std::uint32_t index; // index within its source
348 bool is_sysex;
349 };
350 std::array<Ref, kMaxOutputEvents> refs;
351 std::size_t n_refs = 0;
352 std::uint32_t order = 0;
353
354 const auto clamp_offset = [&](std::int32_t off) -> std::int32_t {
355 // Shared cross-format offset contract (see detail/midi_out_offset.hpp
356 // and test_midi_out_offset_parity.cpp): an in-block offset N is
357 // preserved; a stray out-of-block offset is clamped into the block.
358 return detail::au_output_offset(off, frame_count);
359 };
360
361 std::uint32_t ev_index = 0;
362 for (const auto& e : midi_out) {
363 const std::uint32_t len = e.message.length();
364 if (len != 0 && len <= 3) { // short messages only
365 if (n_refs < refs.size()) {
366 refs[n_refs++] = Ref{clamp_offset(e.sample_offset),
367 order++, ev_index, false};
368 } else {
369 ++dropped;
370 }
371 }
372 ++ev_index;
373 }
374 const auto& sysex = midi_out.sysex();
375 for (std::uint32_t i = 0; i < sysex.size(); ++i) {
376 if (sysex[i].data.empty()) continue;
377 if (n_refs < refs.size()) {
378 refs[n_refs++] = Ref{clamp_offset(sysex[i].sample_offset),
379 order++, i, true};
380 } else {
381 ++dropped;
382 }
383 }
384
385 // Stable sort by offset (insertion sort — small n, no allocation, and
386 // stable so same-offset events keep per-source emission order).
387 for (std::size_t i = 1; i < n_refs; ++i) {
388 Ref key = refs[i];
389 std::size_t j = i;
390 while (j > 0 && (refs[j - 1].offset > key.offset ||
391 (refs[j - 1].offset == key.offset &&
392 refs[j - 1].order > key.order))) {
393 refs[j] = refs[j - 1];
394 --j;
395 }
396 refs[j] = key;
397 }
398
399 auto* list = reinterpret_cast<MIDIPacketList*>(storage.data());
400 MIDIPacket* cur = MIDIPacketListInit(list);
401 bool wrote = false;
402
403 for (std::size_t i = 0; i < n_refs; ++i) {
404 const Ref& r = refs[i];
405 const auto ts = static_cast<MIDITimeStamp>(r.offset);
406 MIDIPacket* next = nullptr;
407 if (r.is_sysex) {
408 const auto& sx = sysex[r.index];
409 next = MIDIPacketListAdd(list, kBufferBytes, cur, ts,
410 sx.data.size(), sx.data.data());
411 } else {
412 // Random-access the short event by its buffer index.
413 const midi::MidiEvent& e = midi_out[r.index];
414 const std::uint32_t len = e.message.length();
415 std::uint8_t bytes[3] = {0, 0, 0};
416 const auto* d = e.data();
417 for (std::uint32_t b = 0; b < len; ++b) bytes[b] = d[b];
418 next = MIDIPacketListAdd(list, kBufferBytes, cur, ts, len, bytes);
419 }
420 if (next == nullptr) { // buffer full — drop the rest
421 dropped += (n_refs - i);
422 break;
423 }
424 cur = next;
425 wrote = true;
426 }
427
428 return wrote ? list : nullptr;
429 }
430};
431
432// ── Parameter surface ────────────────────────────────────────────────────
433//
434// The StateStore IS the host's parameter store (see the auv2 skill's
435// "Parameters are single-source-of-truth" section) — these helpers only read
436// and write it, never a parallel AUElement copy.
437
441 AudioUnitScope scope,
442 AudioUnitParameterID* out_list,
443 UInt32& out_count);
444
455 AudioUnitScope scope,
456 AudioUnitParameterID param_id,
457 AudioUnitParameterInfo& out_info,
458 bool advertise_value_strings);
459
461 AudioUnitScope scope,
462 UInt32& out_size,
463 bool& out_writable);
464
472OSStatus fill_supports_mpe_property_info(bool supports_mpe, AudioUnitScope scope, UInt32& out_size,
473 bool& out_writable);
474
475OSStatus fill_supports_mpe(bool supports_mpe, AudioUnitScope scope, void* out_data);
476
493 public:
498
502 void bind(Processor* processor);
503
504 OSStatus property_info(AudioUnitScope scope, AudioUnitElement element, UInt32& out_size,
505 bool& out_writable) const;
506 OSStatus get(AudioUnitScope scope, AudioUnitElement element, void* out_data) const;
507
510 void prepare_for_render() const noexcept;
511
515 void clear_after_render_resources() const noexcept;
516
517 AudioWorkgroupClient* client() const noexcept {
518 return client_;
519 }
520
521 private:
522 AudioWorkgroupClient* client_ = nullptr;
523 void* block_ = nullptr; // AURenderContextObserver, Block_copy-owned
524};
525
527 AudioUnitScope scope,
528 void* out_data);
529
537 AudioUnitScope scope,
538 AudioUnitParameterID param_id,
539 CFArrayRef* out_strings);
540
545 void* out_data);
546
549 void* out_data);
550
551// ── Host ↔ store parameter bridge ────────────────────────────────────────
552
556bool host_is_writing_param() noexcept;
557
566
576void wire_host_parameter_bridge(state::StateStore& store,
577 AudioUnit unit,
578 state::ListenerToken& out_listener);
579
580// ── Host-facing parameter-name publishing ────────────────────────────────
581
590public:
591 using Notify = std::function<void(state::ParamID)>;
592
595
598
601 void start(state::StateStore& store, Notify notify);
602
604 void stop() noexcept;
605
609
610private:
611 struct Impl;
612 std::unique_ptr<Impl> impl_;
613};
614
615// ── State (preset) serialization ─────────────────────────────────────────
616
620OSStatus save_pulp_state(state::StateStore& store,
621 Processor& processor,
622 CFPropertyListRef* out_data);
623
633OSStatus restore_pulp_state(state::StateStore& store,
634 Processor& processor,
635 StateRestoreGate& gate,
636 CFPropertyListRef plist);
637
638// ── MIDI output callback publishing ──────────────────────────────────────
639
651public:
652 struct Pair {
653 AUMIDIOutputCallback callback = nullptr;
654 void* user_data = nullptr;
655 };
656
660 OSStatus publish(const void* in_data, UInt32 in_data_size) noexcept;
661
664 OSStatus reflect(void* out_data) const noexcept;
665
668 const Pair* load() const noexcept {
669 return active_.load(std::memory_order_acquire);
670 }
671
672private:
673 std::array<Pair, 2> slots_{};
674 std::atomic<std::uint8_t> write_slot_{0};
675 std::atomic<const Pair*> active_{nullptr};
676};
677
682CFArrayRef make_midi_output_names(const char* stream_name);
683
684} // namespace pulp::format::au
685
686#endif // defined(__APPLE__)
The factory-preset surface both Audio Unit adapters serve to the host.
Optional capability for processors and graph runtimes which own auxiliary realtime rendering threads.
Definition audio_workgroup_client.hpp:11
Definition contract_editor_session.hpp:92
The contract sessions one adapter instance opened that a host still holds.
Definition contract_editor_session.hpp:73
Definition processor.hpp:174
Definition state_restore_gate.hpp:87
Publishes the host's kAudioUnitProperty_MIDIOutputCallback pair from the main thread to the render th...
Definition au_v2_common.hpp:650
const Pair * load() const noexcept
Acquire-load the published pair, or nullptr when the host has installed none.
Definition au_v2_common.hpp:668
OSStatus publish(const void *in_data, UInt32 in_data_size) noexcept
Publish the pair carried by a kAudioUnitProperty_MIDIOutputCallback SetProperty payload.
OSStatus reflect(void *out_data) const noexcept
Reflect the currently published pair into a AUMIDIOutputCallbackStruct for GetProperty.
Host offline-render intent for an AU v2 instance.
Definition au_v2_common.hpp:161
void begin_session() noexcept
Start a render session (call from Initialize()).
Definition au_v2_common.hpp:193
bool offline() const noexcept
Render-thread read of the latest host value.
Definition au_v2_common.hpp:200
OSStatus set(AudioUnitScope scope, const void *in_data, UInt32 in_size) noexcept
Definition au_v2_common.hpp:178
OSStatus get(AudioUnitScope scope, void *out_data) const noexcept
Definition au_v2_common.hpp:171
OSStatus property_info(AudioUnitScope scope, UInt32 &out_size, bool &out_writable) const noexcept
Definition au_v2_common.hpp:163
void start(state::StateStore &store, Notify notify)
Snapshot the current stable parameter list and begin the paced main-thread poll.
void poll_main_thread()
Drain once on the caller's control/main thread.
ParameterDisplayNamePublisher(const ParameterDisplayNamePublisher &)=delete
ParameterDisplayNamePublisher & operator=(const ParameterDisplayNamePublisher &)=delete
std::function< void(state::ParamID)> Notify
Definition au_v2_common.hpp:591
void stop() noexcept
Stop future polls and retire queued callbacks without touching the host.
void clear_after_render_resources() const noexcept
Off the render thread, when render resources go away (Cleanup): publish removal and wait until every ...
void bind(Processor *processor)
Bind the processor (call once it exists, before the host can query).
AudioWorkgroupClient * client() const noexcept
Definition au_v2_common.hpp:517
void prepare_for_render() const noexcept
Render entry guard: idempotent, realtime safe.
OSStatus property_info(AudioUnitScope scope, AudioUnitElement element, UInt32 &out_size, bool &out_writable) const
RenderContextObserverProperty(const RenderContextObserverProperty &)=delete
OSStatus get(AudioUnitScope scope, AudioUnitElement element, void *out_data) const
RenderContextObserverProperty & operator=(const RenderContextObserverProperty &)=delete
Collection of timestamped MIDI events within a single audio buffer period.
Definition buffer.hpp:31
std::shared_ptr< State > Handle
Definition alive_token.hpp:53
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
Apple-only: the whole header is gated on APPLE so it stays an empty no-op on the Linux header-hygiene...
Definition au_factory_presets.hpp:33
ContractEditorSession * contract_view_session(void *ns_view)
The session behind an AU v2 contract view (the NSView the contract view factory returned),...
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).
bool fill_cocoa_view_info(void *outData)
Fills an AudioUnitCocoaViewInfo with the Pulp Cocoa view factory's bundle URL + class name.
bool(*)(void *) CocoaViewInfoFiller
Cross-TU Cocoa-view hook.
Definition au_v2_common.hpp:88
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.
Definition au_v2_common.hpp:131
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.
OSStatus parameter_value_from_string(const state::StateStore &store, void *out_data)
kAudioUnitProperty_ParameterValueFromString — text entry, string → value.
CocoaViewInfoFiller g_cocoa_view_info_filler
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_clump_property_info(const state::StateStore &store, AudioUnitScope scope, UInt32 &out_size, bool &out_writable)
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 automa...
constexpr std::size_t kMaxMidiEventsPerBlock
RT-safe builder for the MIDIPacketList an AU v2 plugin hands the host via kAudioUnitProperty_MIDIOutp...
Definition au_v2_common.hpp:310
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.
bool host_is_writing_param() noexcept
True while this thread is inside a host-originated SetParameter.
CFArrayRef make_midi_output_names(const char *stream_name)
Build the one-element CFArrayRef a host reads from kAudioUnitProperty_MIDIOutputCallbackInfo — the na...
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.
constexpr std::size_t kMaxChannelInfoPairs
Upper bound on AUChannelInfo pairs an adapter advertises through SupportedNumChannels.
Definition au_v2_common.hpp:58
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)
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 ch...
Definition au_v2_common.hpp:214
static constexpr AudioUnitPropertyID kPulpEditorContextProperty
Custom AU property ID the Cocoa view factory queries to obtain the host-side Processor + StateStore p...
Definition au_v2_common.hpp:65
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.
Float64 tail_samples_to_seconds(int tail_samples, double sample_rate) noexcept
Definition au_v2_common.hpp:284
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 parameter_string_from_value(const state::StateStore &store, void *out_data)
kAudioUnitProperty_ParameterStringFromValue.
What the product grants a device: the quota table indexed by capability tier and live thermal state.
Definition aax_editor.hpp:31
@ FasterThanRealtime
Definition process_context.hpp:43
@ Realtime
Definition process_context.hpp:42
@ Offline
Definition process_block.hpp:31
@ Realtime
Definition process_block.hpp:30
@ BeatPosition
Definition transport_fields.hpp:14
@ HostTime
Definition transport_fields.hpp:19
@ LoopRange
Definition transport_fields.hpp:17
@ Looping
Definition transport_fields.hpp:12
@ TimeSignature
Definition transport_fields.hpp:16
@ Playing
Definition transport_fields.hpp:10
@ Tempo
Definition transport_fields.hpp:13
@ Bar
Definition transport_fields.hpp:18
@ SamplePosition
Definition transport_fields.hpp:15
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
Definition beat_division.hpp:11
STL namespace.
Proving the audio thread is outside process() while plugin state is restored under it.
Process context — passed every audio callback with transport state.
Definition process_context.hpp:89
int num_samples
Definition process_context.hpp:91
RenderSpeedHint render_speed_hint
Advisory render-speed category for hosts that know whether the current pass is live,...
Definition process_context.hpp:121
double sample_rate
Definition process_context.hpp:90
ProcessMode process_mode
Runtime mode for this block.
Definition process_context.hpp:96
void * user_data
Definition au_v2_common.hpp:654
AUMIDIOutputCallback callback
Definition au_v2_common.hpp:653
Definition au_v2_common.hpp:312
static constexpr std::size_t kBufferBytes
Definition au_v2_common.hpp:321
const MIDIPacketList * build(const midi::MidiBuffer &midi_out, std::uint32_t frame_count) noexcept
Build a MIDIPacketList from midi_out into the internal buffer.
Definition au_v2_common.hpp:337
static constexpr std::size_t kMaxOutputEvents
Definition au_v2_common.hpp:320
std::size_t dropped
Definition au_v2_common.hpp:327
std::array< std::uint8_t, kBufferBytes > storage
Definition au_v2_common.hpp:322
Definition au_v2_common.hpp:67
pulp::runtime::AliveToken::Handle owner_alive
Definition au_v2_common.hpp:70
pulp::format::Processor * processor
Definition au_v2_common.hpp:68
pulp::format::ContractSessionRegistry * contract_sessions
Contract editors register here (contract_editor_session.hpp) so the AU instance invalidates them befo...
Definition au_v2_common.hpp:73
pulp::state::StateStore * store
Definition au_v2_common.hpp:69
Timestamped MIDI event combining a choc::midi::ShortMessage with timing info.
Definition message.hpp:32