Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
program.hpp
Go to the documentation of this file.
1#pragma once
2
13
14#include <atomic>
15#include <cstddef>
16#include <cstdint>
17#include <memory>
18#include <span>
19#include <utility>
20#include <vector>
21
22namespace pulp::playback {
23
24class ProgramCompilerTask;
29
37
42
45
46enum class ProviderKind : std::uint8_t { Arrangement, Launcher, ExternalInput };
47
50 std::uint8_t available_mask = 1u;
51
52 constexpr bool available(ProviderKind provider) const noexcept {
53 const auto index = static_cast<unsigned>(provider);
54 return index <= static_cast<unsigned>(ProviderKind::ExternalInput) &&
55 (available_mask & (1u << index)) != 0;
56 }
57};
58
59enum class RendererStatePolicy : std::uint8_t { Stateless, CarryByItemId };
60
61enum class NoteProgramEventKind : std::uint8_t { Off, On };
62
81
90
93const CompiledNoteModifier* find_note_modifier(std::span<const CompiledNoteModifier> modifiers,
94 timeline::ItemId note_id) noexcept;
95
100inline constexpr std::size_t kMaximumControllerEventsPerTrack = std::size_t{1} << 20;
101
110enum class ControllerProgramEventOrigin : std::uint8_t { Authored, Chased };
111
138
150 const ControllerProgramEvent& rhs) noexcept {
151 if (lhs.sample != rhs.sample)
152 return lhs.sample < rhs.sample;
153 if (lhs.tick != rhs.tick)
154 return lhs.tick < rhs.tick;
155 if (lhs.address != rhs.address)
156 return lhs.address < rhs.address;
157 if (lhs.origin != rhs.origin)
158 return lhs.origin < rhs.origin; // chased first at one exact position
159 if (lhs.clip_id != rhs.clip_id)
160 return lhs.clip_id < rhs.clip_id;
161 if (lhs.lane_id != rhs.lane_id)
162 return lhs.lane_id < rhs.lane_id;
163 return lhs.point_id < rhs.point_id;
164}
165
167 const NoteProgramEvent& rhs) noexcept {
168 if (lhs.sample != rhs.sample)
169 return lhs.sample < rhs.sample;
170 if (lhs.tick != rhs.tick)
171 return lhs.tick < rhs.tick;
172 if (lhs.kind != rhs.kind)
173 return lhs.kind < rhs.kind; // note-offs first at one exact tick
174 if (lhs.clip_id != rhs.clip_id)
175 return lhs.clip_id < rhs.clip_id;
176 return lhs.note_id < rhs.note_id;
177}
178
179class TrackProgram {
180 public:
181 timeline::ItemId id() const noexcept {
182 return id_;
183 }
184 ProgramGeneration generation() const noexcept {
185 return generation_;
186 }
188 return provider_;
189 }
191 return state_policy_;
192 }
193
197 return requested_state_policy_;
198 }
200 return arrangement_production_;
201 }
202 std::span<const timeline::ItemId> ordered_clip_ids() const noexcept {
203 return clip_ids_;
204 }
205 std::span<const NoteProgramEvent> arrangement_note_events() const noexcept {
206 return note_events_;
207 }
208
215 std::span<const ControllerProgramEvent> arrangement_controller_events() const noexcept {
216 return controller_events_;
217 }
218
219 std::span<const CompiledNoteModifier> note_modifiers() const noexcept {
220 return note_modifiers_;
221 }
222 const AudioTrackRendererProgram* audio_program() const noexcept {
223 return audio_program_.get();
224 }
225 std::span<const timeline::ItemId> ordered_device_placement_ids() const noexcept {
226 return device_placement_ids_;
227 }
229 return automation_program_.get();
230 }
231 const std::shared_ptr<const TrackAutomationProgram>& automation_program_owner() const noexcept {
232 return automation_program_;
233 }
234 std::uint64_t expanded_clip_count() const noexcept {
235 return expanded_clip_count_;
236 }
237 std::uint64_t expanded_note_event_count() const noexcept {
238 return expanded_note_event_count_;
239 }
240 std::uint64_t generated_id_count() const noexcept {
241 return generated_id_count_;
242 }
243 std::uint64_t generated_id_start() const noexcept {
244 return generated_id_start_;
245 }
246
250 const TrackMixerProgram& mixer() const noexcept {
251 return mixer_;
252 }
253
254 private:
258 RendererStatePolicy state_policy, std::vector<timeline::ItemId> clip_ids,
259 std::vector<NoteProgramEvent> note_events,
260 std::vector<ControllerProgramEvent> controller_events,
261 std::vector<CompiledNoteModifier> note_modifiers,
262 std::shared_ptr<const AudioTrackRendererProgram> audio_program,
263 std::vector<timeline::ItemId> device_placement_ids,
264 std::shared_ptr<const TrackAutomationProgram> automation_program,
265 std::uint64_t expanded_clip_count, std::uint64_t expanded_note_event_count,
266 std::uint64_t generated_id_start, std::uint64_t generated_id_count,
268 TrackMixerProgram mixer) noexcept;
269
271 ProgramGeneration generation_ = 0;
272 ProviderSelectorProgram provider_;
275 std::vector<timeline::ItemId> clip_ids_;
276 std::vector<NoteProgramEvent> note_events_;
277 std::vector<ControllerProgramEvent> controller_events_;
278 std::vector<CompiledNoteModifier> note_modifiers_;
279 std::shared_ptr<const AudioTrackRendererProgram> audio_program_;
280 std::vector<timeline::ItemId> device_placement_ids_;
281 std::shared_ptr<const TrackAutomationProgram> automation_program_;
282 std::uint64_t expanded_clip_count_ = 0;
283 std::uint64_t expanded_note_event_count_ = 0;
284 std::uint64_t generated_id_start_ = 0;
285 std::uint64_t generated_id_count_ = 0;
286 timeline::ProductionDeclaration arrangement_production_;
287 TrackMixerProgram mixer_;
288};
289
290class PlaybackProgram {
291 public:
292 ProgramGeneration generation() const noexcept {
293 return generation_;
294 }
295 std::uint64_t document_revision() const noexcept {
296 return document_revision_;
297 }
298 timeline::ItemId project_id() const noexcept {
299 return project_id_;
300 }
301 timeline::ItemId sequence_id() const noexcept {
302 return sequence_id_;
303 }
304
305 const std::shared_ptr<const timeline::Project>& project_owner() const noexcept {
306 return project_;
307 }
308 const timebase::CompiledTempoMap& tempo_map() const noexcept {
309 return *tempo_map_;
310 }
311 const std::shared_ptr<const timebase::CompiledTempoMap>& tempo_map_owner() const noexcept {
312 return tempo_map_;
313 }
314 const std::shared_ptr<const CompileContextRegistry>& content_compilers_owner() const noexcept {
315 return content_compilers_;
316 }
317 const std::shared_ptr<const void>& content_compiler_generation() const noexcept {
318 return content_compiler_generation_;
319 }
320 std::uint64_t content_compiler_revision() const noexcept {
321 return content_compiler_revision_;
322 }
323 const std::shared_ptr<const DecodedAudioAssetPool>& audio_assets_owner() const noexcept {
324 return audio_assets_;
325 }
326 const AudioRendererLimits& audio_limits() const noexcept {
327 return audio_limits_;
328 }
330 return automation_limits_;
331 }
332 std::uint64_t generated_id_base() const noexcept {
333 return generated_id_base_;
334 }
335 std::span<const std::shared_ptr<const TrackProgram>> tracks() const noexcept {
336 return tracks_;
337 }
338 const TrackProgram* find_track(timeline::ItemId id) const noexcept;
339
340 private:
342 PlaybackProgram(ProgramGeneration generation, std::uint64_t document_revision,
344 std::shared_ptr<const timeline::Project> project,
345 std::shared_ptr<const timebase::CompiledTempoMap> tempo_map,
346 std::shared_ptr<const CompileContextRegistry> content_compilers,
347 std::shared_ptr<const void> content_compiler_generation,
348 std::uint64_t content_compiler_revision,
349 std::shared_ptr<const DecodedAudioAssetPool> audio_assets,
351 std::uint64_t generated_id_base,
352 std::vector<std::shared_ptr<const TrackProgram>> tracks) noexcept;
353 const std::shared_ptr<const TrackProgram>* find_track_owner(timeline::ItemId id) const noexcept;
354
355 ProgramGeneration generation_ = 0;
356 std::uint64_t document_revision_ = 0;
357 timeline::ItemId project_id_;
358 timeline::ItemId sequence_id_;
359 std::shared_ptr<const timeline::Project> project_;
360 std::shared_ptr<const timebase::CompiledTempoMap> tempo_map_;
361 std::shared_ptr<const CompileContextRegistry> content_compilers_;
362 std::shared_ptr<const void> content_compiler_generation_;
363 std::uint64_t content_compiler_revision_ = 0;
364 std::shared_ptr<const DecodedAudioAssetPool> audio_assets_;
365 AudioRendererLimits audio_limits_;
366 AutomationPlaybackLimits automation_limits_;
367 std::uint64_t generated_id_base_ = 0;
368 std::vector<std::shared_ptr<const TrackProgram>> tracks_;
369};
370
372 public:
374 [[nodiscard]] ReadGuard read() const noexcept {
375 return slot_.read();
376 }
377 bool has_value() const noexcept {
378 return slot_.has_value();
379 }
380
381 private:
384 void publish(std::shared_ptr<const PlaybackProgram> program,
385 std::shared_ptr<const timeline::Project> project) {
386 live_project_ = std::move(project);
387 slot_.publish(std::move(program));
388 }
389 const std::shared_ptr<const PlaybackProgram>& live() const noexcept {
390 return slot_.live();
391 }
392 const std::shared_ptr<const timeline::Project>& live_project() const noexcept {
393 return live_project_;
394 }
395 bool try_bind_compiler() noexcept {
396 bool expected = false;
397 return compiler_bound_.compare_exchange_strong(expected, true, std::memory_order_acq_rel);
398 }
399 void unbind_compiler() noexcept {
400 compiler_bound_.store(false, std::memory_order_release);
401 }
402 runtime::Slot<const PlaybackProgram> slot_;
403 // Control-thread provenance for exact same-revision adoption by a newly
404 // bound compiler. Render threads never touch this sidecar.
405 std::shared_ptr<const timeline::Project> live_project_;
406 std::atomic<bool> compiler_bound_{false};
407};
408
409} // namespace pulp::playback
Definition audio_renderer.hpp:169
The declaration side of the compile-context subscription contract.
Definition compile_context_registry.hpp:148
Immutable, ID-sorted ownership table prepared off the audio thread.
Definition audio_renderer.hpp:65
Definition program.hpp:371
ReadGuard read() const noexcept
Definition program.hpp:374
friend class ProgramCompilerTask
Definition program.hpp:383
bool has_value() const noexcept
Definition program.hpp:377
runtime::Slot< const PlaybackProgram >::ReadGuard ReadGuard
Definition program.hpp:373
friend struct PlaybackProgramCompilerCore
Definition program.hpp:382
std::uint64_t document_revision() const noexcept
Definition program.hpp:295
const AudioRendererLimits & audio_limits() const noexcept
Definition program.hpp:326
const timebase::CompiledTempoMap & tempo_map() const noexcept
Definition program.hpp:308
const TrackProgram * find_track(timeline::ItemId id) const noexcept
const AutomationPlaybackLimits & automation_limits() const noexcept
Definition program.hpp:329
std::uint64_t generated_id_base() const noexcept
Definition program.hpp:332
const std::shared_ptr< const void > & content_compiler_generation() const noexcept
Definition program.hpp:317
std::span< const std::shared_ptr< const TrackProgram > > tracks() const noexcept
Definition program.hpp:335
const std::shared_ptr< const CompileContextRegistry > & content_compilers_owner() const noexcept
Definition program.hpp:314
const std::shared_ptr< const timebase::CompiledTempoMap > & tempo_map_owner() const noexcept
Definition program.hpp:311
std::uint64_t content_compiler_revision() const noexcept
Definition program.hpp:320
const std::shared_ptr< const DecodedAudioAssetPool > & audio_assets_owner() const noexcept
Definition program.hpp:323
ProgramGeneration generation() const noexcept
Definition program.hpp:292
timeline::ItemId project_id() const noexcept
Definition program.hpp:298
friend class ProgramCompilerTask
Definition program.hpp:341
const std::shared_ptr< const timeline::Project > & project_owner() const noexcept
Exact immutable document snapshot used to compile this program.
Definition program.hpp:305
timeline::ItemId sequence_id() const noexcept
Definition program.hpp:301
Immutable compiler-supplied grouping of one track's compiled automation lanes.
Definition track_automation_program.hpp:44
Definition program.hpp:179
RendererStatePolicy requested_state_policy() const noexcept
The control-thread policy before registered arrangement content widens it to Stateless.
Definition program.hpp:196
const TrackMixerProgram & mixer() const noexcept
The track's own level and stereo placement, with any lanes that automate them already resolved.
Definition program.hpp:250
std::span< const ControllerProgramEvent > arrangement_controller_events() const noexcept
Controller and expression values in controller_program_event_less order.
Definition program.hpp:215
std::uint64_t generated_id_count() const noexcept
Definition program.hpp:240
std::span< const timeline::ItemId > ordered_clip_ids() const noexcept
Definition program.hpp:202
ProgramGeneration generation() const noexcept
Definition program.hpp:184
const TrackAutomationProgram * automation_program() const noexcept
Definition program.hpp:228
RendererStatePolicy state_policy() const noexcept
Definition program.hpp:190
const AudioTrackRendererProgram * audio_program() const noexcept
Definition program.hpp:222
std::uint64_t expanded_clip_count() const noexcept
Definition program.hpp:234
timeline::ItemId id() const noexcept
Definition program.hpp:181
std::span< const timeline::ItemId > ordered_device_placement_ids() const noexcept
Definition program.hpp:225
const timeline::ProductionDeclaration & arrangement_production() const noexcept
Definition program.hpp:199
friend class ProgramCompilerTask
Definition program.hpp:255
ProviderSelectorProgram provider() const noexcept
Definition program.hpp:187
std::uint64_t generated_id_start() const noexcept
Definition program.hpp:243
const std::shared_ptr< const TrackAutomationProgram > & automation_program_owner() const noexcept
Definition program.hpp:231
std::span< const CompiledNoteModifier > note_modifiers() const noexcept
Sorted by note id. Empty for a track whose notes all play by default.
Definition program.hpp:219
std::span< const NoteProgramEvent > arrangement_note_events() const noexcept
Definition program.hpp:205
std::uint64_t expanded_note_event_count() const noexcept
Definition program.hpp:237
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
RAII pin.
Definition slot.hpp:93
const std::shared_ptr< T > & live() const noexcept
Publisher thread only.
Definition slot.hpp:207
Definition compiled_tempo_map.hpp:91
Definition audio_renderer.hpp:20
ControllerProgramEventOrigin
Whether a lowered controller value was authored at its own position or synthesized at a window bounda...
Definition program.hpp:110
@ Authored
Definition program.hpp:110
RendererStatePolicy
Definition program.hpp:59
@ Stateless
Definition program.hpp:59
@ CarryByItemId
Definition program.hpp:59
constexpr bool controller_program_event_less(const ControllerProgramEvent &lhs, const ControllerProgramEvent &rhs) noexcept
Total order for controller events sharing a block.
Definition program.hpp:149
NoteProgramEventKind
Definition program.hpp:61
@ On
Definition program.hpp:61
@ Off
Definition program.hpp:61
constexpr bool note_program_event_less(const NoteProgramEvent &lhs, const NoteProgramEvent &rhs) noexcept
Definition program.hpp:166
@ InvalidGeneration
Definition automation_program.hpp:27
@ MissingTempoMap
Definition automation_program.hpp:28
const CompiledNoteModifier * find_note_modifier(std::span< const CompiledNoteModifier > modifiers, timeline::ItemId note_id) noexcept
Looks up the modifier for note_id in a table sorted by note id.
runtime::Result< ProgramGeneration, ProgramError > next_program_generation(ProgramGeneration current) noexcept
constexpr std::size_t kMaximumControllerEventsPerTrack
Ceiling on controller events one track program may carry.
Definition program.hpp:100
ProviderKind
Definition program.hpp:46
@ Launcher
Definition program.hpp:46
@ ExternalInput
Definition program.hpp:46
@ Arrangement
Definition program.hpp:46
ProgramErrorCode
Definition program.hpp:30
@ DuplicateClip
Definition program.hpp:34
@ InvalidGeneration
Definition program.hpp:31
@ DuplicateTrack
Definition program.hpp:33
@ CarryByItemId
Definition compile_context_registry.hpp:34
std::uint64_t ProgramGeneration
Definition program_identity.hpp:10
@ InvalidIdentity
Definition audio_renderer.hpp:30
How content is produced, and how honestly a render of it can be replayed.
Result<T, E> — success / failure union for fallible operations.
Publishing a value built off the audio thread, and reclaiming the old one without ever calling a dest...
Shared compile and RT ceilings.
Definition audio_renderer_limits.hpp:10
Preparation and callback-work ceilings shared by document compilation and track automation rendering.
Definition automation_limits.hpp:12
One note's playback modifier, lowered with its draw key already folded from the content's authored se...
Definition program.hpp:86
std::uint64_t draw_key
Definition program.hpp:87
timeline::NoteModifier modifier
Definition program.hpp:88
Immutable controller/expression value lowered by the program compiler.
Definition program.hpp:127
timeline::ItemId point_id
Definition program.hpp:132
timeline::ItemId lane_id
Definition program.hpp:131
ControllerProgramEventOrigin origin
Definition program.hpp:135
constexpr auto operator<=>(const ControllerProgramEvent &) const =default
timebase::SamplePosition sample
Definition program.hpp:128
timebase::TickPosition tick
Definition program.hpp:129
timeline::ItemId clip_id
Definition program.hpp:130
timeline::MidiLaneAddress address
Definition program.hpp:133
std::uint32_t value
Definition program.hpp:134
Immutable arrangement-note event lowered by the program compiler.
Definition program.hpp:70
std::uint8_t channel
Definition program.hpp:77
timeline::ItemId clip_id
Definition program.hpp:73
timebase::SamplePosition sample
Definition program.hpp:71
std::uint16_t velocity
Definition program.hpp:75
constexpr auto operator<=>(const NoteProgramEvent &) const =default
timeline::ItemId note_id
Definition program.hpp:74
std::uint8_t pitch
Definition program.hpp:76
timebase::TickPosition tick
Definition program.hpp:72
NoteProgramEventKind kind
Definition program.hpp:78
Definition program.hpp:38
ProgramErrorCode code
Definition program.hpp:39
timeline::ItemId item
Definition program.hpp:40
std::uint8_t available_mask
Definition program.hpp:50
constexpr bool available(ProviderKind provider) const noexcept
Definition program.hpp:52
ProviderKind selected
Definition program.hpp:49
The compiled form of a track's own level and stereo placement.
Definition track_mixer_program.hpp:28
Definition rational_time.hpp:9
Definition tick.hpp:61
Nonzero monotonic identity for a Timeline-owned object.
Definition item_id.hpp:19
Address of one continuous controller stream within a MidiContent.
Definition midi_lane.hpp:41
Sparse playback modifier attached to one note identity.
Definition note_modifier.hpp:103
What a piece of content declares about its own production.
Definition production_mode.hpp:88