108 std::vector<std::unique_ptr<voice>> voices;
109 voice_routing routing{voice_routing::single};
111 ossia::float_vector fParamMin, fParamMax, fParamInit;
112 std::unique_ptr<uint8_t[]> timePositionBuffer{};
115 std::size_t max_block_size{4096};
118 std::atomic<std::size_t> requested_voices{0};
121 OnExecFinished on_finished;
124 static constexpr std::size_t kVoicePoolReserve = 256;
130 , routing{strat.routing}
134 this->set_not_fp_safe();
136 if(strat.voice_count < 1)
137 strat.voice_count = 1;
139 const auto audio_in_size = data.audio_in_ports.size();
140 const auto audio_out_size = data.audio_out_ports.size();
141 const auto cv_size = data.cv_ports.size();
142 const auto midi_in_size = data.midi_in_ports.size();
143 const auto midi_out_size = data.midi_out_ports.size();
144 const auto atom_in_size = data.atom_in_ports.size();
145 const auto atom_out_size = data.atom_out_ports.size();
146 const auto control_in_size = data.control_in_ports.size();
147 const auto control_out_size = data.control_out_ports.size();
149 if(audio_in_size > 0)
150 m_inlets.push_back(
new ossia::audio_inlet);
151 if(audio_out_size > 0)
152 m_outlets.push_back(
new ossia::audio_outlet);
153 for(std::size_t i = 0; i < cv_size; i++)
154 m_inlets.push_back(
new ossia::audio_inlet);
155 for(std::size_t i = 0; i < midi_in_size; i++)
156 m_inlets.push_back(
new ossia::midi_inlet);
157 for(std::size_t i = 0; i < midi_out_size; i++)
158 m_outlets.push_back(
new ossia::midi_outlet);
159 for(std::size_t i = 0; i < atom_in_size; i++)
160 m_inlets.push_back(
new ossia::value_inlet);
161 for(std::size_t i = 0; i < atom_out_size; i++)
162 m_outlets.push_back(
new ossia::value_outlet);
163 for(std::size_t i = 0; i < control_in_size; i++)
164 m_inlets.push_back(
new ossia::value_inlet);
165 for(std::size_t i = 0; i < control_out_size; i++)
166 m_outlets.push_back(
new ossia::value_outlet);
168 const auto num_ports = data.effect.plugin.get_num_ports();
169 fParamMin.resize(num_ports);
170 fParamMax.resize(num_ports);
171 fParamInit.resize(num_ports);
172 data.effect.plugin.get_port_ranges_float(
173 fParamMin.data(), fParamMax.data(), fParamInit.data());
175 if(!data.effect.instance_holder)
176 throw std::runtime_error(
"Error while creating a LV2 plug-in");
179 routing == voice_routing::per_channel ? kVoicePoolReserve : strat.voice_count);
182 voices.push_back(build_voice(data.effect.instance_holder));
185 LilvState* primary_state = (strat.voice_count > 1) ? snapshot_state_raw() :
nullptr;
188 for(std::size_t i = 1; i < strat.voice_count; ++i)
190 auto handle = instantiate_handle(sampleRate);
195 primary_state, handle->instance,
nullptr,
nullptr,
196 LV2_STATE_IS_PORTABLE,
nullptr);
197 voices.push_back(build_voice(std::move(handle)));
201 lilv_state_free(primary_state);
203 if(!data.time_Position_ports.empty())
204 timePositionBuffer = std::make_unique<uint8_t[]>(256);
206 requested_voices.store(voices.size(), std::memory_order_relaxed);
214 QMetaObject::invokeMethod(
215 QCoreApplication::instance(),
216 [pending = std::move(voices)]()
mutable { pending.clear(); });
220 std::unique_ptr<voice> build_voice(SharedInstance handle)
222 auto v = std::make_unique<voice>();
223 v->instance_holder = std::move(handle);
224 v->instance = v->instance_holder->instance;
225 allocate_voice_buffers(*v);
226 connect_voice_ports(*v);
232 SharedInstance instantiate_handle(
int sampleRate)
234 auto* inst = lilv_plugin_instantiate(
235 data.effect.plugin.me, sampleRate,
236 data.host.global ? data.host.global->features() : data.host.features);
239 return std::make_shared<InstanceHandle>(inst);
243 std::unique_ptr<voice>
244 make_voice_for_pool(
int sampleRate, LilvState* state)
246 auto handle = instantiate_handle(sampleRate);
252 state, handle->instance,
nullptr,
nullptr, LV2_STATE_IS_PORTABLE,
255 return build_voice(std::move(handle));
259 LilvState* snapshot_state_raw()
const noexcept
261 if(voices.empty() || !voices[0]->instance || !data.host.global)
263 return lilv_state_new_from_instance(
264 data.effect.plugin.me, voices[0]->instance, &data.host.global->map,
265 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
266 LV2_STATE_IS_PORTABLE,
nullptr);
270 void append_voice(std::unique_ptr<voice> v)
noexcept
272 voices.push_back(std::move(v));
276 void request_voice_count(std::size_t n)
noexcept
278 auto prev = requested_voices.load(std::memory_order_relaxed);
280 && !requested_voices.compare_exchange_weak(
281 prev, n, std::memory_order_release, std::memory_order_relaxed))
285 void allocate_voice_buffers(
voice& v)
287 const auto control_in_size = data.control_in_ports.size();
288 const auto control_out_size = data.control_out_ports.size();
289 const auto cv_size = data.cv_ports.size();
290 const auto other_size = data.control_other_ports.size();
291 const auto midi_in_size = data.midi_in_ports.size();
292 const auto midi_out_size = data.midi_out_ports.size();
293 const auto atom_in_size = data.atom_in_ports.size();
294 const auto atom_out_size = data.atom_out_ports.size();
295 const auto audio_in_size = data.audio_in_ports.size();
296 const auto audio_out_size = data.audio_out_ports.size();
298 v.fInControls.resize(control_in_size);
299 v.fOutControls.resize(control_out_size);
300 v.fOtherControls.resize(other_size);
302 v.fCVs.resize(cv_size);
303 for(
auto& cv : v.fCVs)
304 cv.resize(max_block_size);
306 v.audio_in_scratch.resize(audio_in_size);
307 for(
auto& a : v.audio_in_scratch)
308 a.resize(max_block_size);
310 v.audio_out_scratch.resize(audio_out_size);
311 for(
auto& a : v.audio_out_scratch)
312 a.resize(max_block_size);
314 v.midi_atom_ins.reserve(midi_in_size);
315 v.midi_2to1.resize(midi_in_size);
316 v.message_for_midi_atom_ins.resize(midi_in_size);
317 for(std::size_t i = 0; i < midi_in_size; i++)
318 v.midi_atom_ins.emplace_back(
319 2048, data.host.atom_chunk_id, data.host.midi_event_id,
true);
321 v.midi_atom_outs.reserve(midi_out_size);
322 v.midi_1to2.resize(midi_out_size);
323 for(std::size_t i = 0; i < midi_out_size; i++)
324 v.midi_atom_outs.emplace_back(
325 2048, data.host.atom_chunk_id, data.host.midi_event_id,
false);
327 v.atom_ins.reserve(atom_in_size);
328 v.message_for_atom_ins.resize(atom_in_size);
329 for(std::size_t i = 0; i < atom_in_size; i++)
330 v.atom_ins.emplace_back(
331 2048, data.host.atom_chunk_id, data.host.atom_object_id,
true);
333 v.atom_outs.reserve(atom_out_size);
334 for(std::size_t i = 0; i < atom_out_size; i++)
335 v.atom_outs.emplace_back(
336 2048, data.host.atom_chunk_id, data.host.atom_object_id,
false);
339 v.atom_timePosition_owned_buffers.reserve(data.time_Position_ports.size());
340 for(
int port_index : data.time_Position_ports)
343 for(std::size_t k = 0; k < data.midi_in_ports.size(); ++k)
345 if(data.midi_in_ports[k] == port_index)
347 v.atom_timePosition_midi.push_back({port_index, &v.midi_atom_ins[k]});
354 v.atom_timePosition_owned_buffers.emplace_back(
355 256, data.host.atom_chunk_id, data.host.time_Position_id,
true);
356 v.atom_timePosition_owned.push_back(
357 {port_index, &v.atom_timePosition_owned_buffers.back()});
361 if(lilv_plugin_has_feature(data.effect.plugin.me, data.host.work_schedule)
362 && lilv_plugin_has_extension_data(
363 data.effect.plugin.me, data.host.work_interface))
365 v.worker =
static_cast<const LV2_Worker_Interface*
>(
366 lilv_instance_get_extension_data(v.instance, LV2_WORKER__interface));
369 for(std::size_t i = 0; i < control_in_size; i++)
370 v.fInControls[i] = fParamInit[data.control_in_ports[i]];
372 (void)control_out_size;
374 (void)audio_out_size;
377 void connect_voice_ports(
voice& v)
noexcept
379 auto* inst = v.instance;
380 for(std::size_t i = 0; i < data.control_in_ports.size(); i++)
381 lilv_instance_connect_port(inst, data.control_in_ports[i], &v.fInControls[i]);
382 for(std::size_t i = 0; i < data.control_out_ports.size(); i++)
383 lilv_instance_connect_port(inst, data.control_out_ports[i], &v.fOutControls[i]);
384 for(std::size_t i = 0; i < data.cv_ports.size(); i++)
385 lilv_instance_connect_port(inst, data.cv_ports[i], v.fCVs[i].data());
386 for(std::size_t i = 0; i < data.control_other_ports.size(); i++)
387 lilv_instance_connect_port(
388 inst, data.control_other_ports[i], &v.fOtherControls[i]);
389 for(std::size_t i = 0; i < v.midi_atom_ins.size(); i++)
390 lilv_instance_connect_port(
391 inst, data.midi_in_ports[i], &v.midi_atom_ins[i].buf->atoms);
392 for(std::size_t i = 0; i < v.midi_atom_outs.size(); i++)
393 lilv_instance_connect_port(
394 inst, data.midi_out_ports[i], &v.midi_atom_outs[i].buf->atoms);
395 for(std::size_t i = 0; i < v.atom_ins.size(); i++)
396 lilv_instance_connect_port(
397 inst, data.atom_in_ports[i], &v.atom_ins[i].buf->atoms);
398 for(std::size_t i = 0; i < v.atom_outs.size(); i++)
399 lilv_instance_connect_port(
400 inst, data.atom_out_ports[i], &v.atom_outs[i].buf->atoms);
401 for(
auto& [port, buf] : v.atom_timePosition_owned)
402 lilv_instance_connect_port(inst, port, &buf->buf->atoms);
405 void activate_voice(
voice& v)
noexcept
407 if(v.instance_holder && v.instance && !v.instance_holder->activated)
409 lilv_instance_activate(v.instance);
410 v.instance_holder->activated =
true;
414 void all_notes_off()
noexcept override
417 if(data.midi_in_ports.empty())
419 const int midi_port_index = data.midi_in_ports[0];
420 for(
auto& v : voices)
422 if(v->message_for_midi_atom_ins.empty())
424 auto& msg_queue = v->message_for_midi_atom_ins[0];
425 for(uint8_t ch = 0; ch < 16; ++ch)
427 for(uint8_t cc : {uint8_t(120), uint8_t(123)})
430 m.index = uint32_t(midi_port_index);
431 m.protocol = data.host.atom_eventTransfer;
432 m.body.resize(
sizeof(LV2_Atom) + 3);
433 auto* atom =
reinterpret_cast<LV2_Atom*
>(m.body.data());
434 atom->type = data.host.midi_event_id;
436 uint8_t* d = m.body.data() +
sizeof(LV2_Atom);
437 d[0] = uint8_t(0xB0 | ch);
440 msg_queue.push_back(std::move(m));
446 [[nodiscard]] std::string label()
const noexcept override
448 return fmt::format(
"lv2 ({})", data.effect.plugin.get_name().as_string());
451 void updateTime(
const ossia::token_request& tk, ossia::exec_state_facade st)
454 auto& forge = host.forge;
455 uint8_t* buffer = timePositionBuffer.get();
456 lv2_atom_forge_set_buffer(&forge, buffer, 256);
457 LV2_Atom_Forge_Frame frame;
458 lv2_atom_forge_object(&forge, &frame, 0, host.time_Position_id);
460 lv2_atom_forge_key(&forge, host.time_frame_id);
461 lv2_atom_forge_long(&forge, this->m_transport_frames);
463 lv2_atom_forge_key(&forge, host.time_framesPerSecond_id);
464 lv2_atom_forge_long(&forge, st.sampleRate());
466 lv2_atom_forge_key(&forge, host.time_speed_id);
467 lv2_atom_forge_float(&forge, tk.speed);
469 lv2_atom_forge_key(&forge, host.time_bar_id);
470 lv2_atom_forge_long(&forge, tk.musical_start_last_bar / 4.);
472 lv2_atom_forge_key(&forge, host.time_beat_id);
473 lv2_atom_forge_double(&forge, tk.musical_start_position);
475 auto barBeat = float(tk.musical_start_position - tk.musical_start_last_bar);
476 lv2_atom_forge_key(&forge, host.time_barBeat_id);
477 lv2_atom_forge_float(&forge, barBeat);
479 lv2_atom_forge_key(&forge, host.time_beatUnit_id);
480 lv2_atom_forge_int(&forge, 4);
482 lv2_atom_forge_key(&forge, host.time_beatsPerBar_id);
483 lv2_atom_forge_float(
484 &forge, 4 *
double(tk.signature.upper) /
double(tk.signature.lower));
486 lv2_atom_forge_key(&forge, host.time_beatsPerMinute_id);
487 lv2_atom_forge_float(&forge, tk.tempo);
489 lv2_atom_forge_pop(&forge, &frame);
493 static std::optional<float>
494 voice_control_value(
const ossia::value& val, std::size_t voice_idx)
noexcept
496 return ossia::apply_nonnull(
497 [voice_idx](
const auto& v) -> std::optional<float> {
498 using T = std::decay_t<
decltype(v)>;
499 if constexpr(std::is_same_v<T, std::vector<ossia::value>>)
503 const auto& elem = (voice_idx < v.size()) ? v[voice_idx] : v.back();
504 return ossia::convert<float>(elem);
506 else if constexpr(std::is_same_v<T, ossia::vec2f>)
507 return v[std::min<std::size_t>(voice_idx, 1)];
508 else if constexpr(std::is_same_v<T, ossia::vec3f>)
509 return v[std::min<std::size_t>(voice_idx, 2)];
510 else if constexpr(std::is_same_v<T, ossia::vec4f>)
511 return v[std::min<std::size_t>(voice_idx, 3)];
513 std::is_same_v<T, float> || std::is_same_v<T, int>
514 || std::is_same_v<T, bool>)
522 void preProcessVoice(
voice& v, std::size_t voice_idx)
524 const std::size_t audio_in_size = data.audio_in_ports.size();
525 const std::size_t cv_size = data.cv_ports.size();
526 const std::size_t midi_in_size = data.midi_in_ports.size();
527 const std::size_t atom_in_size = data.atom_in_ports.size();
528 const std::size_t control_in_size = data.control_in_ports.size();
530 int first_midi_idx = (audio_in_size > 0 ? 1 : 0) + cv_size;
531 for(std::size_t i = 0; i < v.midi_atom_ins.size(); i++)
534 = this->m_inlets[i + first_midi_idx]->template cast<ossia::midi_port>();
535 auto& lv2_port = v.midi_atom_ins[i];
538 for(
const Message& msg : v.message_for_midi_atom_ins[i])
540 auto* atom = (LV2_Atom*)msg.body.data();
541 auto* atom_data = (
const uint8_t*)LV2_ATOM_BODY(atom);
542 it.write(0, 0, atom->type, atom->size, atom_data);
545 auto& conv = v.midi_2to1[i];
546 for(
const libremidi::ump& msg : ossia_port.messages)
549 msg.data, msg.size(), msg.timestamp,
550 [&](
unsigned char* midi1,
int bytes, int64_t) {
552 it.write(msg.timestamp, 0, data.host.midi_event_id, bytes, midi1);
553 return stdx::error{};
557 if(!v.atom_timePosition_midi.empty())
559 const LV2_Atom* atom = (
const LV2_Atom*)timePositionBuffer.get();
560 it.write(0, 0, atom->type, atom->size, (
const uint8_t*)LV2_ATOM_BODY(atom));
564 for(
auto& [_, buf] : v.atom_timePosition_owned)
567 const LV2_Atom* atom = (
const LV2_Atom*)timePositionBuffer.get();
568 it.write(0, 0, atom->type, atom->size, (
const uint8_t*)LV2_ATOM_BODY(atom));
571 const auto control_start
572 = (audio_in_size > 0 ? 1 : 0) + midi_in_size + atom_in_size + cv_size;
573 for(std::size_t i = 0; i < control_in_size; i++)
575 auto& in = m_inlets[control_start + i]
576 ->template cast<ossia::value_port>()
580 if(
auto new_val = voice_control_value(in.back().value, voice_idx))
581 v.fInControls[i] = *new_val;
587 void postProcessVoice(
voice& v)
noexcept
589 if(v.worker && v.worker->work_response)
591 std::vector<char> vec;
592 while(v.worker_datas.try_dequeue(vec))
593 v.worker->work_response(v.instance->lv2_handle, vec.size(), vec.data());
595 if(v.worker && v.worker->end_run)
596 v.worker->end_run(v.instance->lv2_handle);
598 for(
auto& port : v.midi_atom_ins)
599 port.buf->reset(
true);
600 for(
auto& port : v.atom_ins)
601 port.buf->reset(
true);
602 for(
auto& [_, buf] : v.atom_timePosition_owned)
603 buf->buf->reset(
true);
604 for(
auto& port : v.midi_atom_outs)
605 port.buf->reset(
false);
606 for(
auto& port : v.atom_outs)
607 port.buf->reset(
false);
608 for(
auto& mqueue : v.message_for_midi_atom_ins)
613 void surfaceVoiceZeroOutputs(int64_t offset)
615 auto& v0 = *voices[0];
616 const auto audio_out_size = data.audio_out_ports.size();
617 const auto midi_out_size = data.midi_out_ports.size();
618 const auto control_out_size = data.control_out_ports.size();
620 int first_midi_idx = (audio_out_size > 0 ? 1 : 0);
621 for(std::size_t i = 0; i < v0.midi_atom_outs.size(); i++)
624 = this->m_outlets[i + first_midi_idx]->template cast<ossia::midi_port>();
625 auto& lv2_port = v0.midi_atom_outs[i];
626 auto& conv = v0.midi_1to2[i];
628 LV2_ATOM_SEQUENCE_FOREACH(&lv2_port.buf->atoms, ev)
630 if(ev->body.type == data.host.midi_event_id)
632 auto bytes = (uint8_t*)LV2_ATOM_BODY_CONST(&ev->body);
634 bytes, ev->body.size, ev->time.frames,
635 [&](
const uint32_t* ump,
int count, int64_t ts) {
637 std::copy_n(ump, std::min(count, 4), u.data);
639 ossia_port.messages.push_back(u);
640 return stdx::error{};
646 qDebug() <<
"Unhandled LV2 event type: " << ev->body.type;
651 const auto control_start = (audio_out_size > 0 ? 1 : 0) + midi_out_size;
652 for(std::size_t i = 0; i < control_out_size; i++)
655 = m_outlets[control_start + i]->template cast<ossia::value_port>();
656 out.write_value(v0.fOutControls[i], offset);
660 void run(
const ossia::token_request& tk, ossia::exec_state_facade st)
noexcept override
665 data.host.current = &data.effect;
666 if(!data.time_Position_ports.empty())
670 for(std::size_t c = 0; c < voices.size(); ++c)
671 preProcessVoice(*voices[c], c);
673 const auto [tick_start, samples] = st.timings(tk);
674 const bool samples_valid
675 = samples > 0 && std::size_t(samples) <= max_block_size;
681 case voice_routing::single:
684 case voice_routing::per_channel:
685 runPerChannel(samples);
690 surfaceVoiceZeroOutputs(tk.physical_start(st.modelToSamples()));
693 for(
auto& v : voices)
694 postProcessVoice(*v);
703 host.current_worker_datas = &v.worker_datas;
708 void runSingle(
int samples)
noexcept
710 auto& v = *voices[0];
711 const auto audio_ins = data.audio_in_ports.size();
712 const auto audio_outs = data.audio_out_ports.size();
716 const auto& audio_in = m_inlets[0]->template cast<ossia::audio_port>();
717 const auto in_channels = audio_in.channels();
718 for(std::size_t i = 0; i < audio_ins; i++)
720 auto& scratch = v.audio_in_scratch[i];
721 std::fill_n(scratch.data(), samples, 0.0f);
724 const auto& ch = audio_in.channel(i);
725 const auto n = std::min<std::size_t>(samples, ch.size());
726 for(std::size_t j = 0; j < n; j++)
727 scratch[j] =
float(ch[j]);
729 lilv_instance_connect_port(
730 v.instance, data.audio_in_ports[i], scratch.data());
734 for(std::size_t i = 0; i < audio_outs; i++)
735 lilv_instance_connect_port(
736 v.instance, data.audio_out_ports[i], v.audio_out_scratch[i].data());
739 worker_routing_scope ws{data.host, v};
740 lilv_instance_run(v.instance, samples);
745 auto& out =
static_cast<ossia::audio_outlet*
>(m_outlets[0])->data;
746 out.set_channels(audio_outs);
747 for(std::size_t i = 0; i < audio_outs; i++)
749 auto& ch = out.channel(i);
751 v.audio_out_scratch[i].begin(),
752 v.audio_out_scratch[i].begin() + samples);
758 void runPerChannel(
int samples)
noexcept
763 const auto* audio_in_inlet
764 = m_inlets.empty() ? nullptr : m_inlets[0]->template target<ossia::audio_port>();
765 const auto in_channels = audio_in_inlet ? audio_in_inlet->channels() : 0;
769 = (audio_in_inlet ? std::max<std::size_t>(in_channels, 1) : voices.size());
770 request_voice_count(requested);
772 const auto active = std::min<std::size_t>(voices.size(), requested);
774 auto& out =
static_cast<ossia::audio_outlet*
>(m_outlets[0])->data;
775 out.set_channels(active);
777 for(std::size_t c = 0; c < active; ++c)
779 auto& v = *voices[c];
783 auto& in_scratch = v.audio_in_scratch[0];
784 std::fill_n(in_scratch.data(), samples, 0.0f);
787 const auto& src = audio_in_inlet->channel(c);
788 const auto n = std::min<std::size_t>(samples, src.size());
789 for(std::size_t j = 0; j < n; j++)
790 in_scratch[j] =
float(src[j]);
792 lilv_instance_connect_port(
793 v.instance, data.audio_in_ports[0], in_scratch.data());
796 auto& out_scratch = v.audio_out_scratch[0];
797 lilv_instance_connect_port(
798 v.instance, data.audio_out_ports[0], out_scratch.data());
801 worker_routing_scope ws{data.host, v};
802 lilv_instance_run(v.instance, samples);
805 auto& dst = out.channel(c);
806 dst.assign(out_scratch.begin(), out_scratch.begin() + samples);