140 std::vector<std::unique_ptr<voice>> voices;
141 voice_routing routing{voice_routing::single};
143 ossia::float_vector fParamMin, fParamMax, fParamInit;
147 std::unique_ptr<uint8_t[]> timePositionBuffer{};
161 std::size_t max_block_size{4096};
164 std::atomic<std::size_t> requested_voices{0};
166 OnExecStart on_start;
167 OnExecFinished on_finished;
170 static constexpr std::size_t kVoicePoolReserve = 256;
173 const LV2Data& dat,
int sampleRate, voice_strategy strat, OnExecStart os,
176 , routing{strat.routing}
180 this->set_not_fp_safe();
182 if(strat.voice_count < 1)
183 strat.voice_count = 1;
185 const auto audio_in_size = data.audio_in_ports.size();
186 const auto audio_out_size = data.audio_out_ports.size();
187 const auto cv_size = data.cv_ports.size();
188 const auto midi_in_size = data.midi_in_ports.size();
189 const auto midi_out_size = data.midi_out_ports.size();
190 const auto atom_in_size = data.atom_in_ports.size();
191 const auto atom_out_size = data.atom_out_ports.size();
192 const auto control_in_size = data.control_in_ports.size();
193 const auto control_out_size = data.control_out_ports.size();
195 if(audio_in_size > 0)
196 m_inlets.push_back(
new ossia::audio_inlet);
197 if(audio_out_size > 0)
198 m_outlets.push_back(
new ossia::audio_outlet);
199 for(std::size_t i = 0; i < cv_size; i++)
200 m_inlets.push_back(
new ossia::audio_inlet);
201 for(std::size_t i = 0; i < midi_in_size; i++)
202 m_inlets.push_back(
new ossia::midi_inlet);
203 for(std::size_t i = 0; i < midi_out_size; i++)
204 m_outlets.push_back(
new ossia::midi_outlet);
205 for(std::size_t i = 0; i < atom_in_size; i++)
206 m_inlets.push_back(
new ossia::value_inlet);
207 for(std::size_t i = 0; i < atom_out_size; i++)
208 m_outlets.push_back(
new ossia::value_outlet);
209 for(std::size_t i = 0; i < control_in_size; i++)
210 m_inlets.push_back(
new ossia::value_inlet);
211 for(std::size_t i = 0; i < control_out_size; i++)
212 m_outlets.push_back(
new ossia::value_outlet);
213 for(std::size_t i = 0; i < data.cv_out_ports.size(); i++)
214 m_outlets.push_back(
new ossia::audio_outlet);
216 data.portRanges(fParamMin, fParamMax, fParamInit);
218 for(std::size_t i = 0; i < control_in_size; i++)
219 fInScale[i] = data.isSampleRatePort(data.control_in_ports[i]) ? sampleRate : 1.f;
220 fOutScale.resize(control_out_size);
221 for(std::size_t i = 0; i < control_out_size; i++)
222 fOutScale[i] = data.isSampleRatePort(data.control_out_ports[i]) ? sampleRate : 1.f;
224 if(!data.effect.instance_holder)
225 throw std::runtime_error(
"Error while creating a LV2 plug-in");
228 routing == voice_routing::per_channel ? kVoicePoolReserve : strat.voice_count);
234 if(
auto* desc = lilv_instance_get_descriptor(data.effect.instance);
235 desc && !desc->activate && !data.effect.ui_instance)
236 renew_primary_instance(sampleRate);
239 voices.push_back(build_voice(data.effect.instance_holder));
242 LilvState* primary_state = (strat.voice_count > 1) ? snapshot_state_raw() :
nullptr;
245 for(std::size_t i = 1; i < strat.voice_count; ++i)
247 auto handle = instantiate_handle(sampleRate);
252 primary_state, handle->instance,
nullptr,
nullptr,
253 LV2_STATE_IS_PORTABLE,
nullptr);
254 voices.push_back(build_voice(std::move(handle)));
258 lilv_state_free(primary_state);
260 if(!data.time_Position_ports.empty())
262 timePositionBuffer = std::make_unique<uint8_t[]>(256);
266 requested_voices.store(voices.size(), std::memory_order_relaxed);
269 ~lv2_node() noexcept
override
274 QMetaObject::invokeMethod(
275 QCoreApplication::instance(),
276 [pending = std::move(voices)]()
mutable { pending.clear(); });
280 std::unique_ptr<voice> build_voice(SharedInstance handle)
282 auto v = std::make_unique<voice>();
283 v->instance_holder = std::move(handle);
284 v->instance = v->instance_holder->instance;
285 v->port_count = data.effect.plugin.get_num_ports();
286 allocate_voice_buffers(*v);
288 v->instance_holder->connected_to = v.get();
294 SharedInstance instantiate_handle(
int sampleRate)
296 auto* inst = lilv_plugin_instantiate(
297 data.effect.plugin.me, sampleRate,
298 data.host.global ? data.host.global->features() : data.host.features);
301 return std::make_shared<InstanceHandle>(inst);
305 void renew_primary_instance(
int sampleRate)
307 auto handle = instantiate_handle(sampleRate);
312 if(LilvState* state = lilv_state_new_from_instance(
313 data.effect.plugin.me, data.effect.instance, &data.host.global->map,
314 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
315 LV2_STATE_IS_PORTABLE,
nullptr))
318 state, handle->instance,
nullptr,
nullptr, LV2_STATE_IS_PORTABLE,
nullptr);
319 lilv_state_free(state);
322 data.effect.instance = handle->instance;
323 data.effect.instance_holder = std::move(handle);
327 std::unique_ptr<voice>
328 make_voice_for_pool(
int sampleRate, LilvState* state)
330 auto handle = instantiate_handle(sampleRate);
336 state, handle->instance,
nullptr,
nullptr, LV2_STATE_IS_PORTABLE,
339 return build_voice(std::move(handle));
343 LilvState* snapshot_state_raw() const noexcept
345 if(voices.empty() || !voices[0]->instance || !data.host.global)
347 return lilv_state_new_from_instance(
348 data.effect.plugin.me, voices[0]->instance, &data.host.global->map,
349 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
350 LV2_STATE_IS_PORTABLE,
nullptr);
354 void append_voice(std::unique_ptr<voice> v)
noexcept
356 voices.push_back(std::move(v));
360 void request_voice_count(std::size_t n)
noexcept
362 auto prev = requested_voices.load(std::memory_order_relaxed);
364 && !requested_voices.compare_exchange_weak(
365 prev, n, std::memory_order_release, std::memory_order_relaxed))
369 void allocate_voice_buffers(voice& v)
371 const auto control_in_size = data.control_in_ports.size();
372 const auto control_out_size = data.control_out_ports.size();
373 const auto cv_size = data.cv_ports.size();
374 const auto other_size = data.control_other_ports.size();
375 const auto midi_in_size = data.midi_in_ports.size();
376 const auto midi_out_size = data.midi_out_ports.size();
377 const auto atom_in_size = data.atom_in_ports.size();
378 const auto atom_out_size = data.atom_out_ports.size();
379 const auto audio_in_size = data.audio_in_ports.size();
380 const auto audio_out_size = data.audio_out_ports.size();
382 v.fInControls.resize(control_in_size);
383 v.fOutControls.resize(control_out_size);
384 v.fOtherControls.resize(other_size);
386 v.fCVs.resize(cv_size);
387 for(
auto& cv : v.fCVs)
388 cv.resize(max_block_size);
389 v.fCVOuts.resize(data.cv_out_ports.size());
390 for(
auto& cv : v.fCVOuts)
391 cv.resize(max_block_size);
393 v.audio_in_scratch.resize(audio_in_size);
394 for(
auto& a : v.audio_in_scratch)
395 a.resize(max_block_size);
397 v.audio_out_scratch.resize(audio_out_size);
398 for(
auto& a : v.audio_out_scratch)
399 a.resize(max_block_size);
401 v.midi_atom_ins.reserve(midi_in_size);
402 v.midi_2to1.resize(midi_in_size);
403 v.message_for_midi_atom_ins.resize(midi_in_size);
404 for(std::size_t i = 0; i < midi_in_size; i++)
405 v.midi_atom_ins.emplace_back(
406 data.atomBufferSize(data.midi_in_ports[i]), data.host.atom_chunk_id,
407 data.host.atom_sequence_id,
true);
409 v.midi_atom_outs.reserve(midi_out_size);
410 v.midi_1to2.resize(midi_out_size);
411 for(std::size_t i = 0; i < midi_out_size; i++)
412 v.midi_atom_outs.emplace_back(
413 data.atomBufferSize(data.midi_out_ports[i]), data.host.atom_chunk_id,
414 data.host.atom_sequence_id,
false);
416 v.atom_ins.reserve(atom_in_size);
417 v.message_for_atom_ins.resize(atom_in_size);
418 for(std::size_t i = 0; i < atom_in_size; i++)
419 v.atom_ins.emplace_back(
420 data.atomBufferSize(data.atom_in_ports[i]), data.host.atom_chunk_id,
421 data.host.atom_sequence_id,
true);
423 v.atom_outs.reserve(atom_out_size);
424 for(std::size_t i = 0; i < atom_out_size; i++)
425 v.atom_outs.emplace_back(
426 data.atomBufferSize(data.atom_out_ports[i]), data.host.atom_chunk_id,
427 data.host.atom_sequence_id,
false);
429 v.atom_others.reserve(data.atom_other_ports.size());
430 for(
int port : data.atom_other_ports)
431 v.atom_others.emplace_back(
432 data.atomBufferSize(port), data.host.atom_chunk_id,
433 data.host.atom_sequence_id, true);
436 v.atom_timePosition_owned_buffers.reserve(data.time_Position_ports.size());
437 for(
int port_index : data.time_Position_ports)
440 for(std::size_t k = 0; k < data.midi_in_ports.size(); ++k)
442 if(data.midi_in_ports[k] == port_index)
444 v.atom_timePosition_midi.push_back({port_index, &v.midi_atom_ins[k]});
451 v.atom_timePosition_owned_buffers.emplace_back(
452 256, data.host.atom_chunk_id, data.host.atom_sequence_id,
true);
453 v.atom_timePosition_owned.push_back(
454 {port_index, &v.atom_timePosition_owned_buffers.back()});
458 if(lilv_plugin_has_feature(data.effect.plugin.me, data.host.work_schedule)
459 && lilv_plugin_has_extension_data(
460 data.effect.plugin.me, data.host.work_interface))
462 v.worker =
static_cast<const LV2_Worker_Interface*
>(
463 lilv_instance_get_extension_data(v.instance, LV2_WORKER__interface));
466 for(std::size_t i = 0; i < control_in_size; i++)
467 v.fInControls[i] = fParamInit[data.control_in_ports[i]] *
fInScale[i];
469 (void)control_out_size;
471 (void)audio_out_size;
479 auto* inst = v.instance;
480 for(std::size_t i = 0; i < data.audio_in_ports.size(); i++)
481 lilv_instance_connect_port(inst, data.audio_in_ports[i], v.audio_in_scratch[i].data());
482 for(std::size_t i = 0; i < data.audio_out_ports.size(); i++)
483 lilv_instance_connect_port(
484 inst, data.audio_out_ports[i], v.audio_out_scratch[i].data());
485 for(std::size_t i = 0; i < data.control_in_ports.size(); i++)
486 lilv_instance_connect_port(inst, data.control_in_ports[i], &v.fInControls[i]);
487 for(std::size_t i = 0; i < data.control_out_ports.size(); i++)
488 lilv_instance_connect_port(inst, data.control_out_ports[i], &v.fOutControls[i]);
489 for(std::size_t i = 0; i < data.cv_ports.size(); i++)
490 lilv_instance_connect_port(inst, data.cv_ports[i], v.fCVs[i].data());
491 for(std::size_t i = 0; i < data.cv_out_ports.size(); i++)
492 lilv_instance_connect_port(inst, data.cv_out_ports[i], v.fCVOuts[i].data());
493 for(std::size_t i = 0; i < data.control_other_ports.size(); i++)
494 lilv_instance_connect_port(
495 inst, data.control_other_ports[i], &v.fOtherControls[i]);
496 for(std::size_t i = 0; i < v.midi_atom_ins.size(); i++)
497 lilv_instance_connect_port(
498 inst, data.midi_in_ports[i], &v.midi_atom_ins[i].buf->atoms);
499 for(std::size_t i = 0; i < v.midi_atom_outs.size(); i++)
500 lilv_instance_connect_port(
501 inst, data.midi_out_ports[i], &v.midi_atom_outs[i].buf->atoms);
502 for(std::size_t i = 0; i < v.atom_ins.size(); i++)
503 lilv_instance_connect_port(
504 inst, data.atom_in_ports[i], &v.atom_ins[i].buf->atoms);
505 for(std::size_t i = 0; i < v.atom_outs.size(); i++)
506 lilv_instance_connect_port(
507 inst, data.atom_out_ports[i], &v.atom_outs[i].buf->atoms);
508 for(
auto& [port, buf] : v.atom_timePosition_owned)
509 lilv_instance_connect_port(inst, port, &buf->buf->atoms);
510 for(std::size_t i = 0; i < v.atom_others.size(); i++)
511 lilv_instance_connect_port(
512 inst, data.atom_other_ports[i], &v.atom_others[i].buf->atoms);
515 void activate_voice(
voice& v)
noexcept
517 if(v.instance_holder && v.instance && !v.instance_holder->activated)
519 lilv_instance_activate(v.instance);
520 v.instance_holder->activated =
true;
524 void all_notes_off() noexcept
override
527 if(data.midi_in_ports.empty())
529 const int midi_port_index = data.midi_in_ports[0];
530 for(
auto& v : voices)
532 if(v->message_for_midi_atom_ins.empty())
534 auto& msg_queue = v->message_for_midi_atom_ins[0];
535 for(uint8_t ch = 0; ch < 16; ++ch)
537 for(uint8_t cc : {uint8_t(120), uint8_t(123)})
540 m.index = uint32_t(midi_port_index);
541 m.protocol = data.host.atom_eventTransfer;
542 m.body.resize(
sizeof(LV2_Atom) + 3);
543 auto* atom =
reinterpret_cast<LV2_Atom*
>(m.body.data());
544 atom->type = data.host.midi_event_id;
546 uint8_t* d = m.body.data() +
sizeof(LV2_Atom);
547 d[0] = uint8_t(0xB0 | ch);
550 msg_queue.push_back(std::move(m));
556 [[nodiscard]] std::string label() const noexcept
override
558 return fmt::format(
"lv2 ({})", data.effect.plugin.get_name().as_string());
561 void updateTime(
const ossia::token_request& tk, ossia::exec_state_facade st)
563 forgeTime(timePositionBuffer.get(), tk, st, tk.speed);
569 uint8_t* buffer,
const ossia::token_request& tk, ossia::exec_state_facade st,
573 auto& forge = host.forge;
574 lv2_atom_forge_set_buffer(&forge, buffer, 256);
575 LV2_Atom_Forge_Frame frame;
576 lv2_atom_forge_object(&forge, &frame, 0, host.time_Position_id);
580 lv2_atom_forge_key(&forge, host.time_frame_id);
582 &forge, tk.speed != 0. ? tk.start_date_to_physical(st.modelToSamples())
583 : this->m_transport_frames);
585 lv2_atom_forge_key(&forge, host.time_framesPerSecond_id);
586 lv2_atom_forge_long(&forge, st.sampleRate());
588 lv2_atom_forge_key(&forge, host.time_speed_id);
589 lv2_atom_forge_float(&forge, speed);
591 lv2_atom_forge_key(&forge, host.time_bar_id);
592 lv2_atom_forge_long(&forge, tk.musical_start_last_bar / 4.);
594 lv2_atom_forge_key(&forge, host.time_beat_id);
595 lv2_atom_forge_double(&forge, tk.musical_start_position);
597 auto barBeat = float(tk.musical_start_position - tk.musical_start_last_bar);
598 lv2_atom_forge_key(&forge, host.time_barBeat_id);
599 lv2_atom_forge_float(&forge, barBeat);
601 lv2_atom_forge_key(&forge, host.time_beatUnit_id);
602 lv2_atom_forge_int(&forge, 4);
604 lv2_atom_forge_key(&forge, host.time_beatsPerBar_id);
605 lv2_atom_forge_float(
606 &forge, 4 *
double(tk.signature.upper) /
double(tk.signature.lower));
608 lv2_atom_forge_key(&forge, host.time_beatsPerMinute_id);
609 lv2_atom_forge_float(&forge, tk.tempo);
611 lv2_atom_forge_pop(&forge, &frame);
615 static std::optional<float>
616 voice_control_value(
const ossia::value& val, std::size_t voice_idx)
noexcept
618 return ossia::apply_nonnull(
619 [voice_idx](
const auto& v) -> std::optional<float> {
620 using T = std::decay_t<
decltype(v)>;
621 if constexpr(std::is_same_v<T, std::vector<ossia::value>>)
625 const auto& elem = (voice_idx < v.size()) ? v[voice_idx] : v.back();
626 return ossia::convert<float>(elem);
628 else if constexpr(std::is_same_v<T, ossia::vec2f>)
629 return v[std::min<std::size_t>(voice_idx, 1)];
630 else if constexpr(std::is_same_v<T, ossia::vec3f>)
631 return v[std::min<std::size_t>(voice_idx, 2)];
632 else if constexpr(std::is_same_v<T, ossia::vec4f>)
633 return v[std::min<std::size_t>(voice_idx, 3)];
635 std::is_same_v<T, float> || std::is_same_v<T, int>
636 || std::is_same_v<T, bool>)
644 void preProcessVoice(voice& v, std::size_t voice_idx)
646 const std::size_t audio_in_size = data.audio_in_ports.size();
647 const std::size_t cv_size = data.cv_ports.size();
648 const std::size_t midi_in_size = data.midi_in_ports.size();
649 const std::size_t atom_in_size = data.atom_in_ports.size();
650 const std::size_t control_in_size = data.control_in_ports.size();
652 int first_midi_idx = (audio_in_size > 0 ? 1 : 0) + cv_size;
653 for(std::size_t i = 0; i < v.midi_atom_ins.size(); i++)
656 = this->m_inlets[i + first_midi_idx]->template cast<ossia::midi_port>();
657 auto& lv2_port = v.midi_atom_ins[i];
662 if(ossia::any_of(v.atom_timePosition_midi, [&](
const auto& t) {
663 return t.buffer == &lv2_port;
667 for(
const Message& msg : v.message_for_midi_atom_ins[i])
669 auto* atom = (LV2_Atom*)msg.body.data();
670 auto* atom_data = (
const uint8_t*)LV2_ATOM_BODY(atom);
671 it.write(0, 0, atom->type, atom->size, atom_data);
676 auto& conv = v.midi_2to1[i];
677 for(
const libremidi::ump& msg : ossia_port.messages)
679 const int64_t frame = std::clamp<int64_t>(
680 msg.timestamp - m_span.start, 0,
681 m_span.samples > 0 ? m_span.samples - 1 : 0);
683 msg.data, msg.size(), frame,
684 [&](
const unsigned char* midi1, std::size_t bytes, int64_t) {
686 it.write(frame, 0, data.host.midi_event_id, bytes, midi1);
687 return stdx::error{};
692 for(
auto& [_, buf] : v.atom_timePosition_owned)
698 const auto control_start
699 = (audio_in_size > 0 ? 1 : 0) + midi_in_size + atom_in_size + cv_size;
700 for(std::size_t i = 0; i < control_in_size; i++)
702 auto& in = m_inlets[control_start + i]
703 ->template cast<ossia::value_port>()
707 if(
auto new_val = voice_control_value(in.back().value, voice_idx))
708 v.fInControls[i] = *new_val *
fInScale[i];
724 template <
typename Channel>
725 static void readChannel(
const Channel& ch,
float* dst,
const buffer_span& s)
noexcept
727 const int64_t n = std::clamp<int64_t>(int64_t(ch.size()) - s.start, 0, s.samples);
728 for(int64_t j = 0; j < n; j++)
729 dst[j] =
float(ch[s.start + j]);
730 std::fill(dst + n, dst + s.samples, 0.f);
733 template <
typename Channel>
734 static void writeChannel(Channel& ch,
const float* src,
const buffer_span& s)
736 if(int64_t(ch.size()) < s.size)
738 std::copy_n(src, s.samples, ch.begin() + s.start);
745 const std::size_t first_cv = data.audio_in_ports.size() > 0 ? 1 : 0;
746 for(std::size_t i = 0; i < v.fCVs.size(); i++)
748 auto* buf = v.fCVs[i].data();
749 const auto& in = m_inlets[first_cv + i]->template cast<ossia::audio_port>();
750 if(
const auto chans = in.channels(); chans > 0)
751 readChannel(in.channel(voice_idx < chans ? voice_idx : 0), buf, m_span);
753 std::fill_n(buf, m_span.samples, 0.f);
760 const std::size_t first_cv = (data.audio_out_ports.size() > 0 ? 1 : 0)
761 + data.midi_out_ports.size()
762 + data.atom_out_ports.size()
763 + data.control_out_ports.size();
764 for(std::size_t i = 0; i < v.fCVOuts.size(); i++)
766 auto& out =
static_cast<ossia::audio_outlet*
>(m_outlets[first_cv + i])->data;
768 writeChannel(out.channel(0), v.fCVOuts[i].data(), m_span);
776 auto write = [&](
const uint8_t* buf) {
777 const LV2_Atom* atom = (
const LV2_Atom*)buf;
778 it.write(0, 0, atom->type, atom->size, (
const uint8_t*)LV2_ATOM_BODY(atom));
780 if(!timePositionBuffer || !m_timeForged)
782 if(m_sendStopped || mustStop)
783 write(stoppedPositionBuffer.get());
785 write(timePositionBuffer.get());
788 void postProcessVoice(
voice& v)
noexcept
790 if(v.worker && v.worker->work_response)
792 std::vector<char> vec;
793 while(v.worker_datas.try_dequeue(vec))
794 v.worker->work_response(v.instance->lv2_handle, vec.size(), vec.data());
796 if(v.worker && v.worker->end_run)
797 v.worker->end_run(v.instance->lv2_handle);
799 for(
auto& port : v.midi_atom_ins)
800 port.buf->reset(true);
801 for(
auto& port : v.atom_ins)
802 port.buf->reset(true);
803 for(
auto& [_, buf] : v.atom_timePosition_owned)
804 buf->buf->reset(true);
805 for(
auto& port : v.midi_atom_outs)
806 port.buf->reset(false);
807 for(
auto& port : v.atom_outs)
808 port.buf->reset(false);
809 for(
auto& port : v.atom_others)
810 port.buf->reset(true);
811 for(
auto& mqueue : v.message_for_midi_atom_ins)
816 void surfaceVoiceZeroOutputs(int64_t offset)
818 auto& v0 = *voices[0];
819 const auto audio_out_size = data.audio_out_ports.size();
820 const auto midi_out_size = data.midi_out_ports.size();
821 const auto control_out_size = data.control_out_ports.size();
823 int first_midi_idx = (audio_out_size > 0 ? 1 : 0);
824 for(std::size_t i = 0; i < v0.midi_atom_outs.size(); i++)
827 = this->m_outlets[i + first_midi_idx]->template cast<ossia::midi_port>();
828 auto& lv2_port = v0.midi_atom_outs[i];
829 auto& conv = v0.midi_1to2[i];
831 lv2_port.buf->for_each_output_event([&](
const LV2_Atom_Event& ev) {
832 if(ev.body.type == data.host.midi_event_id)
834 auto bytes = (const uint8_t*)LV2_ATOM_BODY_CONST(&ev.body);
836 bytes, ev.body.size, ev.time.frames,
837 [&](const uint32_t* ump, int count, int64_t ts) {
839 std::copy_n(ump, std::min(count, 4), u.data);
840 u.timestamp = offset + ts;
841 ossia_port.messages.push_back(u);
842 return stdx::error{};
851 const auto control_start
852 = (audio_out_size > 0 ? 1 : 0) + midi_out_size + data.atom_out_ports.size();
853 for(std::size_t i = 0; i < control_out_size; i++)
856 = m_outlets[control_start + i]->template cast<ossia::value_port>();
857 out.write_value(v0.fOutControls[i] / fOutScale[i], offset);
865 constexpr int64_t fallback = 64;
866 const int64_t n = m_span.samples > 0 ? m_span.samples : fallback;
867 return uint32_t(std::min<int64_t>(n, int64_t(max_block_size)));
874 data.host.current = &data.effect;
875 for(
auto& vp : voices)
878 for(std::size_t i = 0; i < v.midi_atom_ins.size(); i++)
880 auto& lv2_port = v.midi_atom_ins[i];
882 if(ossia::any_of(v.atom_timePosition_midi, [&](
const auto& t) {
883 return t.buffer == &lv2_port;
886 for(
const Message& msg : v.message_for_midi_atom_ins[i])
888 auto* atom = (LV2_Atom*)msg.body.data();
889 it.write(0, 0, atom->type, atom->size, (
const uint8_t*)LV2_ATOM_BODY(atom));
892 for(
auto& [_, buf] : v.atom_timePosition_owned)
898 for(std::size_t i = 0; i < v.audio_in_scratch.size(); i++)
900 auto& scratch = v.audio_in_scratch[i];
901 std::fill(scratch.begin(), scratch.end(), 0.f);
902 lilv_instance_connect_port(v.instance, data.audio_in_ports[i], scratch.data());
904 for(std::size_t i = 0; i < v.audio_out_scratch.size(); i++)
905 lilv_instance_connect_port(
906 v.instance, data.audio_out_ports[i], v.audio_out_scratch[i].data());
913 lilv_instance_run(v.instance, stop_run_samples());
919 void run(
const ossia::token_request& tk, ossia::exec_state_facade st)
noexcept override
926 m_sendStopped =
true;
932 data.host.current = &data.effect;
933 if(!data.time_Position_ports.empty())
936 const auto [tick_start, samples] = st.timings(tk);
937 const bool samples_valid
938 = samples > 0 && std::size_t(samples) <= max_block_size && tick_start >= 0;
940 std::max<int64_t>(tick_start, 0), samples_valid ? samples : 0,
941 std::max<int64_t>(st.bufferSize(), tick_start + samples)};
944 for(std::size_t c = 0; c < voices.size(); ++c)
945 preProcessVoice(*voices[c], c);
949 for(std::size_t c = 0; c < voices.size(); ++c)
950 feedCVInputs(*voices[c], c);
953 case voice_routing::single:
956 case voice_routing::per_channel:
957 runPerChannel(samples);
962 surfaceVoiceZeroOutputs(tk.physical_start(st.modelToSamples()));
965 for(
auto& v : voices)
966 postProcessVoice(*v);
967 m_sendStopped =
false;
976 host.current_worker_datas = &v.worker_datas;
981 void runSingle(
int samples)
noexcept
983 auto& v = *voices[0];
984 const auto audio_ins = data.audio_in_ports.size();
985 const auto audio_outs = data.audio_out_ports.size();
989 const auto& audio_in = m_inlets[0]->template cast<ossia::audio_port>();
990 const auto in_channels = audio_in.channels();
991 for(std::size_t i = 0; i < audio_ins; i++)
993 auto& scratch = v.audio_in_scratch[i];
995 readChannel(audio_in.channel(i), scratch.data(), m_span);
997 std::fill_n(scratch.data(), samples, 0.0f);
998 lilv_instance_connect_port(
999 v.instance, data.audio_in_ports[i], scratch.data());
1003 for(std::size_t i = 0; i < audio_outs; i++)
1004 lilv_instance_connect_port(
1005 v.instance, data.audio_out_ports[i], v.audio_out_scratch[i].data());
1008 worker_routing_scope ws{data.host, v};
1009 lilv_instance_run(v.instance, samples);
1015 auto& out =
static_cast<ossia::audio_outlet*
>(m_outlets[0])->data;
1016 out.set_channels(audio_outs);
1017 for(std::size_t i = 0; i < audio_outs; i++)
1018 writeChannel(out.channel(i), v.audio_out_scratch[i].data(), m_span);
1023 void runPerChannel(
int samples)
noexcept
1028 const auto* audio_in_inlet
1029 = m_inlets.empty() ? nullptr : m_inlets[0]->template target<ossia::audio_port>();
1030 const auto in_channels = audio_in_inlet ? audio_in_inlet->channels() : 0;
1033 const auto requested
1034 = (audio_in_inlet ? std::max<std::size_t>(in_channels, 1) : voices.size());
1035 request_voice_count(requested);
1037 const auto active = std::min<std::size_t>(voices.size(), requested);
1039 auto& out =
static_cast<ossia::audio_outlet*
>(m_outlets[0])->data;
1040 out.set_channels(active);
1042 for(std::size_t c = 0; c < active; ++c)
1044 auto& v = *voices[c];
1048 auto& in_scratch = v.audio_in_scratch[0];
1050 readChannel(audio_in_inlet->channel(c), in_scratch.data(), m_span);
1052 std::fill_n(in_scratch.data(), samples, 0.0f);
1053 lilv_instance_connect_port(
1054 v.instance, data.audio_in_ports[0], in_scratch.data());
1057 auto& out_scratch = v.audio_out_scratch[0];
1058 lilv_instance_connect_port(
1059 v.instance, data.audio_out_ports[0], out_scratch.data());
1062 worker_routing_scope ws{data.host, v};
1063 lilv_instance_run(v.instance, samples);
1066 writeChannel(out.channel(c), out_scratch.data(), m_span);