35 std::shared_ptr<PluginSlot> old_slot,
36 std::size_t fade_samples,
41 old_slot_(
std::move(old_slot)),
42 scratch_channels_(
std::max(0, out_channels)),
43 scratch_frames_(
std::max(0, max_block)) {
44 mixer_.configure(fade_samples, curve);
45 if (fade_samples == 0 || !old_slot_) {
46 done_.store(
true, std::memory_order_release);
48 scratch_storage_.assign(
49 static_cast<std::size_t
>(scratch_channels_) *
static_cast<std::size_t
>(scratch_frames_),
51 scratch_ptrs_.resize(
static_cast<std::size_t
>(scratch_channels_));
52 for (
int c = 0; c < scratch_channels_; ++c) {
53 scratch_ptrs_[
static_cast<std::size_t
>(c)] =
54 scratch_storage_.data() +
static_cast<std::size_t
>(c) *
static_cast<std::size_t
>(scratch_frames_);
59 old_midi_in_.reserve(64, 0);
60 old_midi_out_.reserve(64, 0);
61 old_midi_in_.set_realtime_capacity_limit(
true);
62 old_midi_out_.set_realtime_capacity_limit(
true);
67 bool fade_done() const noexcept {
return done_.load(std::memory_order_acquire); }
70 const std::shared_ptr<PluginSlot>&
new_slot() const noexcept {
return new_slot_; }
78 int num_samples)
override {
80 new_slot_->process(output, input, midi_in, midi_out, param_events, num_samples);
81 blend_old_into_(output, input, num_samples);
85 new_slot_->begin_process();
87 old_slot_->begin_process();
101 int num_samples)
override {
103 if (skip_blend_(
audio, num_samples)) {
104 new_slot_->process(
audio, midi_in, midi_out, param_events, num_samples);
110 old_midi_in_.clear();
111 old_midi_out_.clear();
112 old_slot_->process(
audio, old_midi_in_, old_midi_out_, empty_params_, num_samples);
113 blend_after_old_(
audio, [&] {
114 new_slot_->process(
audio, midi_in, midi_out, param_events, num_samples);
125 if (skip_blend_(
audio, num_samples)) {
126 new_slot_->process(
audio, midi_in, midi_out, param_events, num_samples, transport);
131 old_midi_in_.clear();
132 old_midi_out_.clear();
133 old_slot_->process(
audio, old_midi_in_, old_midi_out_, empty_params_, num_samples, transport);
134 blend_after_old_(
audio, [&] {
135 new_slot_->process(
audio, midi_in, midi_out, param_events, num_samples, transport);
141 bool is_loaded()
const override {
return new_slot_->is_loaded(); }
142 bool prepare(
double sr,
int block)
override {
return new_slot_->prepare(sr, block); }
143 void release()
override { new_slot_->release(); }
144 std::vector<HostParamInfo>
parameters()
const override {
return new_slot_->parameters(); }
145 float get_parameter(uint32_t
id)
const override {
return new_slot_->get_parameter(
id); }
146 void set_parameter(uint32_t
id,
float v)
override { new_slot_->set_parameter(
id, v); }
147 void set_bypass(
bool b)
override { new_slot_->set_bypass(b); }
148 bool is_bypassed()
const override {
return new_slot_->is_bypassed(); }
150 std::vector<uint8_t>
save_state()
const override {
return new_slot_->save_state(); }
151 bool restore_state(
const std::vector<uint8_t>& d)
override {
return new_slot_->restore_state(d); }
152 bool has_editor()
const override {
return new_slot_->has_editor(); }
156 return new_slot_->create_hosted_editor(parent);
159 new_slot_->destroy_hosted_editor(std::move(ed));
162 int tail_samples()
const override {
return new_slot_->tail_samples(); }
171 if (done_.load(std::memory_order_relaxed) || !old_slot_)
return true;
172 auto* main_out =
audio.main_output();
173 if (main_out ==
nullptr)
return true;
174 const int ch = std::min<int>(scratch_channels_,
static_cast<int>(main_out->num_channels()));
175 if (num_samples > scratch_frames_ || ch <= 0) {
176 done_.store(
true, std::memory_order_release);
186 template <
class RenderNew>
188 auto* main_out = audio.main_output();
189 const int ch = std::min<int>(scratch_channels_,
static_cast<int>(main_out->num_channels()));
190 for (
int c = 0; c < ch; ++c) {
191 std::copy_n(main_out->channel_ptr(
static_cast<std::size_t
>(c)),
192 static_cast<std::size_t
>(num_samples),
193 scratch_ptrs_[
static_cast<std::size_t
>(c)]);
196 audio::BufferView<float> scratch(scratch_ptrs_.data(),
static_cast<std::size_t
>(ch),
197 static_cast<std::size_t
>(num_samples));
199 done_.store(
true, std::memory_order_release);
207 void blend_old_into_(audio::BufferView<float>& output,
208 const audio::BufferView<const float>& input,
210 if (done_.load(std::memory_order_relaxed) || !old_slot_)
return;
211 const int ch = std::min<int>(scratch_channels_,
static_cast<int>(output.num_channels()));
212 if (num_samples > scratch_frames_ || ch <= 0) {
214 done_.store(
true, std::memory_order_release);
217 audio::BufferView<float> scratch(scratch_ptrs_.data(),
static_cast<std::size_t
>(ch),
218 static_cast<std::size_t
>(num_samples));
219 old_midi_in_.clear();
220 old_midi_out_.clear();
221 old_slot_->process(scratch, input, old_midi_in_, old_midi_out_, empty_params_, num_samples);
223 done_.store(
true, std::memory_order_release);
227 std::shared_ptr<PluginSlot> new_slot_;
228 std::shared_ptr<PluginSlot> old_slot_;
230 std::vector<float> scratch_storage_;
231 std::vector<float*> scratch_ptrs_;
232 int scratch_channels_ = 0;
233 int scratch_frames_ = 0;
234 std::atomic<bool> done_{
false};
235 midi::MidiBuffer old_midi_in_;
236 midi::MidiBuffer old_midi_out_;
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
ProcessStatus process_status() const noexcept override
Definition crossfade_plugin_slot.hpp:90
void set_parameter(uint32_t id, float v) override
Definition crossfade_plugin_slot.hpp:146
void * create_editor_view() override
Definition crossfade_plugin_slot.hpp:153
const PluginInfo & info() const override
Definition crossfade_plugin_slot.hpp:140
bool restore_state(const std::vector< uint8_t > &d) override
Definition crossfade_plugin_slot.hpp:151
std::vector< HostParamInfo > parameters() const override
Definition crossfade_plugin_slot.hpp:144
bool is_loaded() const override
Definition crossfade_plugin_slot.hpp:141
int latency_samples() const override
Definition crossfade_plugin_slot.hpp:161
float get_parameter(uint32_t id) const override
Definition crossfade_plugin_slot.hpp:145
bool fade_done() const noexcept
Definition crossfade_plugin_slot.hpp:67
int tail_samples() const override
Definition crossfade_plugin_slot.hpp:162
void destroy_editor_view() override
Definition crossfade_plugin_slot.hpp:154
std::vector< uint8_t > save_state() const override
Definition crossfade_plugin_slot.hpp:150
bool prepare(double sr, int block) override
Definition crossfade_plugin_slot.hpp:142
std::unique_ptr< HostedEditor > create_hosted_editor(void *parent) override
Create the hosted editor.
Definition crossfade_plugin_slot.hpp:155
void set_bypass(bool b) override
Definition crossfade_plugin_slot.hpp:147
void destroy_hosted_editor(std::unique_ptr< HostedEditor > ed) override
Tear down a hosted editor. Default routes to destroy_editor_view().
Definition crossfade_plugin_slot.hpp:158
const std::shared_ptr< PluginSlot > & new_slot() const noexcept
Definition crossfade_plugin_slot.hpp:70
void accept(NativeHandleVisitor &v) const override
Definition crossfade_plugin_slot.hpp:163
void process(format::ProcessBuffers &audio, const midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ParameterEventQueue ¶m_events, int num_samples, const format::ProcessContext &transport) override
Definition crossfade_plugin_slot.hpp:118
void release() override
Definition crossfade_plugin_slot.hpp:143
bool has_editor() const override
Definition crossfade_plugin_slot.hpp:152
BypassSurface bypass_surface() const override
Where this plugin keeps its own bypass control.
Definition crossfade_plugin_slot.hpp:149
bool wants_transport() const override
Definition crossfade_plugin_slot.hpp:164
CrossfadePluginSlot(std::shared_ptr< PluginSlot > new_slot, std::shared_ptr< PluginSlot > old_slot, std::size_t fade_samples, signal::TransitionCurve curve, int out_channels, int max_block)
Definition crossfade_plugin_slot.hpp:34
bool is_bypassed() const override
Definition crossfade_plugin_slot.hpp:148
void process(audio::BufferView< float > &output, const audio::BufferView< const float > &input, const midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ParameterEventQueue ¶m_events, int num_samples) override
Definition crossfade_plugin_slot.hpp:73
void begin_process() noexcept override
Definition crossfade_plugin_slot.hpp:84
void process(format::ProcessBuffers &audio, const midi::MidiBuffer &midi_in, midi::MidiBuffer &midi_out, const ParameterEventQueue ¶m_events, int num_samples) override
Definition crossfade_plugin_slot.hpp:97
Definition native_handle_visitor.hpp:116
Definition plugin_slot.hpp:94
ProcessStatus
Definition plugin_slot.hpp:101
@ failed
Definition plugin_slot.hpp:101
@ ok
Definition plugin_slot.hpp:101
Collection of timestamped MIDI events within a single audio buffer period.
Definition buffer.hpp:31
Definition analyzer_provider.hpp:12
Bounded event contracts shared by host ingress and graph-authored nodes.
Definition anticipation_eligibility.hpp:9
::pulp::state::ParameterEventQueue ParameterEventQueue
Definition parameter_event_queue.hpp:8
BypassSurface
Definition plugin_slot.hpp:64
TransitionMixerT< float > TransitionMixer
Definition transition_mixer.hpp:83
TransitionCurve
Definition transition_mixer.hpp:34
bool blend_fade_out(Mixer &mixer, OutView &out, const OldView &old_render) noexcept
Blend an already-rendered fading-out buffer into the live output under a TransitionMixer's old->new g...
Definition transition_mixer.hpp:97
Process context — passed every audio callback with transport state.
Definition process_context.hpp:89
Definition scanner.hpp:35
Shared click-free crossfade primitive.