105 : component{p.component}
106 , processor{p.processor}
107 , midi_controls{p.midiControls}
115 processor->release();
116 component->release();
124 Steinberg::Vst::IComponent* component{};
125 Steinberg::Vst::IAudioProcessor* processor{};
126 MIDIControls midi_controls;
131 ossia::small_pod_vector<int, 2> m_audioInputChannels{};
132 ossia::small_pod_vector<int, 2> m_audioOutputChannels{};
133 int m_totalAudioIns{};
134 int m_totalAudioOuts{};
135 int m_totalEventIns{};
136 int m_totalEventOuts{};
139 explicit vst_node_base(
const Plugin& ptr)
142 this->set_not_fp_safe();
143 m_inlets.reserve(10);
144 controls.reserve(10);
149 void audioIn(
const Steinberg::Vst::BusInfo& bus,
int idx)
151 self.m_inlets.push_back(
new ossia::audio_inlet);
152 self.m_audioInputChannels.push_back(bus.channelCount);
153 self.m_totalAudioIns += bus.channelCount;
155 void eventIn(
const Steinberg::Vst::BusInfo& bus,
int idx)
157 self.m_inlets.push_back(
new ossia::midi_inlet);
158 self.m_totalEventIns++;
160 void audioOut(
const Steinberg::Vst::BusInfo& bus,
int idx)
162 self.m_outlets.push_back(
new ossia::audio_outlet);
163 self.m_audioOutputChannels.push_back(bus.channelCount);
164 self.m_totalAudioOuts += bus.channelCount;
166 void eventOut(
const Steinberg::Vst::BusInfo& bus,
int idx)
168 self.m_outlets.push_back(
new ossia::midi_outlet);
169 self.m_totalEventOuts++;
173 forEachBus(vis{*
this}, *fx.component);
175 if(
auto err = fx.processor->setProcessing(
true);
176 err != Steinberg::kResultOk && err != Steinberg::kNotImplemented)
178 ossia::logger().warn(
"Couldn't set VST3 processing: {}", err);
181 m_vstData.processMode = Steinberg::Vst::ProcessModes::kRealtime;
182 m_vstData.numInputs = m_audioInputChannels.size();
183 m_vstData.numOutputs = m_audioOutputChannels.size();
184 m_vstInput.resize(m_audioInputChannels.size());
185 m_vstOutput.resize(m_audioOutputChannels.size());
186 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
188 m_vstInput[i].numChannels = m_audioInputChannels[i];
190 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
192 m_vstOutput[i].numChannels = m_audioOutputChannels[i];
195 m_vstData.inputs = m_vstInput.data();
196 m_vstData.outputs = m_vstOutput.data();
197 m_vstData.inputParameterChanges = &m_inputChanges;
198 m_vstData.outputParameterChanges = &m_outputChanges;
199 m_vstData.inputEvents = &m_inputEvents;
200 m_vstData.outputEvents = &m_outputEvents;
201 m_vstData.processContext = &m_context;
203 m_inputEvents.setMaxSize(17 * 128 * m_totalEventIns);
204 m_outputEvents.setMaxSize(128 * m_totalEventOuts);
218 for(
const auto& [key, pid] : fx.midi_controls)
220 if(queue_map.find(pid) != queue_map.end())
222 const auto idx = m_inputChanges.queues.size();
223 m_inputChanges.queues.emplace_back(pid);
224 queue_map[pid] = idx;
231 if(
auto err = fx.processor->setProcessing(
false);
232 err != Steinberg::kResultOk && err != Steinberg::kNotImplemented)
234 ossia::logger().warn(
"Couldn't set VST3 processing: {}", err);
240 Steinberg::Vst::ParamID idx{};
241 std::size_t queue_idx{};
242 ossia::value_port* port{};
245 ossia::hash_map<Steinberg::Vst::ParamID, std::size_t> queue_map;
253 ossia::small_vector<vst_control, 16> controls;
255 std::size_t add_control(ossia::value_inlet* inlet, Steinberg::Vst::ParamID
id,
float v)
257 (**inlet).domain = ossia::domain_base<float>{0.f, 1.f};
258 (**inlet).type = ossia::val_type::FLOAT;
264 if(
auto it = queue_map.find(
id); it != queue_map.end())
266 const auto queue_idx = it->second;
270 this->m_inputChanges.queues[queue_idx].lastValue = v;
271 controls.push_back({id, queue_idx, inlet->target<ossia::value_port>()});
272 root_inputs().push_back(std::move(inlet));
277 auto queue_idx = this->m_inputChanges.queues.size();
278 this->m_inputChanges.queues.emplace_back(
id);
279 this->m_inputChanges.queues.back().lastValue = v;
281 queue_map[id] = queue_idx;
282 controls.push_back({id, queue_idx, inlet->target<ossia::value_port>()});
283 root_inputs().push_back(std::move(inlet));
288 void set_control(std::size_t queue_idx,
float value)
290 auto& queue = this->m_inputChanges.queues[queue_idx];
291 queue.lastValue = value;
293 queue.data.emplace_back(0, value);
298 for(vst_control& p : controls)
300 const auto& vec = p.port->get_data();
303 if(
auto t = last(vec).target<float>())
305 double value = ossia::clamp<double>((
double)*t, 0., 1.);
306 auto& queue = m_inputChanges.queues[p.queue_idx];
308 queue.data.emplace_back(0, value);
309 queue.lastValue = value;
314 void dispatchMidi(int64_t tick_start, int64_t samples)
316 m_inputEvents.clear();
317 m_outputEvents.clear();
320 m_inputChanges.queues[idx].data.clear();
323 int audioBusCount = std::ssize(m_audioInputChannels);
324 for(
int i = audioBusCount; i < audioBusCount + m_totalEventIns; i++)
327 *m_inlets[i]->
template target<ossia::midi_port>(), k++, tick_start, samples);
330 m_vstData.inputEvents
331 = (m_inputEvents.getEventCount() > 0) ? &m_inputEvents : nullptr;
332 m_vstData.outputEvents = &m_outputEvents;
341 const int audioBusCount = std::ssize(m_audioInputChannels);
343 for(
int i = audioBusCount; i < audioBusCount + m_totalEventIns; i++, k++)
345 for(
const libremidi::ump& mess :
346 m_inlets[i]->template target<ossia::midi_port>()->messages)
355 void dispatchMidi(ossia::midi_port& port,
int index, int64_t tick_start, int64_t samples)
358 auto& ip = port.messages;
363 ossia::small_vector<std::pair<const libremidi::ump*, int64_t>, 16> to_send;
366 to_send.push_back({&mess, 0});
367 for(
const libremidi::ump& mess : ip)
369 {&mess, std::clamp<int64_t>(
370 mess.timestamp - tick_start, 0, samples > 0 ? samples - 1 : 0)});
375 using VstEvent = Steinberg::Vst::Event;
381 const auto push_midi_control = [
this, index](
382 int channel,
int controller,
double value,
383 Steinberg::int32 offset) {
384 auto it = this->fx.midi_controls.find({index, channel, controller});
385 if(it == this->fx.midi_controls.end())
390 it = this->fx.midi_controls.find({index, 0, controller});
391 if(it == this->fx.midi_controls.end())
394 const auto queue_it = this->queue_map.find(it->second);
395 if(queue_it == this->queue_map.end())
397 auto& queue = this->m_inputChanges.queues[queue_it->second];
398 queue.data.push_back({offset, value});
399 queue.lastValue = value;
406 for(
const auto& [mess_ptr, sample_offset] : to_send)
408 const libremidi::ump& mess = *mess_ptr;
409 if(mess.get_type() != libremidi::midi2::message_type::MIDI_2_CHANNEL)
412 e.sampleOffset = sample_offset;
413 switch(libremidi::message_type(mess.get_status_code()))
415 case libremidi::message_type::NOTE_ON: {
416 auto [channel, note, value] = libremidi::as_01::note_off(mess);
420 e.type = VstEvent::kNoteOnEvent;
421 e.noteOn.channel = channel;
422 e.noteOn.pitch = note;
423 e.noteOn.velocity = value;
424 e.noteOn.noteId = -1;
425 e.noteOn.tuning = 0.f;
426 m_inputEvents.addEvent(e);
430 e.type = VstEvent::kNoteOffEvent;
431 e.noteOff.channel = mess.get_channel();
432 e.noteOff.pitch = note;
433 e.noteOff.velocity = 0;
434 e.noteOff.noteId = -1;
435 e.noteOff.tuning = 0.f;
436 m_inputEvents.addEvent(e);
440 case libremidi::message_type::NOTE_OFF: {
441 auto [channel, note, value] = libremidi::as_01::note_off(mess);
442 e.type = VstEvent::kNoteOffEvent;
443 e.noteOff.channel = channel;
444 e.noteOff.pitch = note;
445 e.noteOff.velocity = value;
446 e.noteOff.noteId = -1;
447 e.noteOff.tuning = 0.f;
448 m_inputEvents.addEvent(e);
451 case libremidi::message_type::POLY_PRESSURE: {
452 auto [channel, note, value] = libremidi::as_01::poly_pressure(mess);
453 e.type = VstEvent::kPolyPressureEvent;
454 e.polyPressure.channel = channel;
455 e.polyPressure.pitch = note;
456 e.polyPressure.pressure = value;
457 e.polyPressure.noteId = -1;
458 m_inputEvents.addEvent(e);
464 case libremidi::message_type::CONTROL_CHANGE: {
465 const auto cc = libremidi::as_01::control_change(mess);
466 push_midi_control(cc.channel, cc.control, cc.value, e.sampleOffset);
470 case libremidi::message_type::PITCH_BEND: {
471 const auto pb = libremidi::as_01::pitch_bend(mess);
473 pb.channel, Steinberg::Vst::kPitchBend, pb.value, e.sampleOffset);
477 case libremidi::message_type::AFTERTOUCH: {
478 const auto at = libremidi::as_01::aftertouch(mess);
480 at.channel, Steinberg::Vst::kAfterTouch, at.value, e.sampleOffset);
489 void readbackMidi(int64_t tick_start)
491 using VstEvent = Steinberg::Vst::Event;
493 const int audioBusCount = std::ssize(m_audioOutputChannels);
494 const int N = m_outputEvents.getEventCount();
496 for(
int i = 0; i < N; i++)
498 auto event_p = m_outputEvents.getEventByIndex(i);
501 VstEvent& e = *event_p;
503 int bus = e.busIndex;
504 auto& port = *m_outlets[bus + audioBusCount]->template target<ossia::midi_port>();
510 case VstEvent::kNoteOnEvent: {
511 if(e.noteOn.velocity > 0.f)
512 mess = libremidi::from_01::note_on(
513 e.noteOn.channel, e.noteOn.pitch, e.noteOn.velocity);
515 mess = libremidi::from_01::note_off(e.noteOn.channel, e.noteOn.pitch, 0.);
518 case VstEvent::kNoteOffEvent: {
519 mess = libremidi::from_01::note_off(
520 e.noteOff.channel, e.noteOff.pitch, e.noteOff.velocity);
523 case VstEvent::kPolyPressureEvent: {
524 mess = libremidi::from_01::poly_pressure(
525 e.noteOff.channel, e.polyPressure.pitch, e.polyPressure.pressure);
532 mess.timestamp = tick_start + e.sampleOffset;
533 port.messages.push_back(std::move(mess));
537 auto& preparePort(ossia::audio_port& port,
int numChannels, std::size_t samples)
539 port.set_channels(numChannels);
546 void setupTimeInfo(
const ossia::token_request& tk, ossia::exec_state_facade st)
548 using namespace Steinberg::Vst;
549 using F = ProcessContext;
550 Steinberg::Vst::ProcessContext& time_info = this->m_context;
551 time_info.sampleRate = st.sampleRate();
553 time_info.projectTimeSamples = this->m_transport_frames;
555 time_info.systemTime = st.currentDate() - st.startDate();
556 time_info.continousTimeSamples = this->m_processed_frames;
558 time_info.projectTimeMusic = tk.musical_start_position;
559 time_info.barPositionMusic = tk.musical_start_last_bar;
560 time_info.cycleStartMusic = 0.;
561 time_info.cycleEndMusic = 0.;
563 time_info.tempo = tk.tempo;
564 time_info.timeSigNumerator = tk.signature.upper;
565 time_info.timeSigDenominator = tk.signature.lower;
569 time_info.smpteOffsetSubframes = 0;
570 time_info.frameRate = {};
571 time_info.samplesToNextClock = 0;
572 time_info.state = F::kPlaying | F::kSystemTimeValid | F::kContTimeValid
573 | F::kProjectTimeMusicValid | F::kBarPositionValid | F::kTempoValid
577 Steinberg::Vst::ProcessData m_vstData;
578 ossia::small_vector<Steinberg::Vst::AudioBusBuffers, 1> m_vstInput;
579 ossia::small_vector<Steinberg::Vst::AudioBusBuffers, 1> m_vstOutput;
581 Steinberg::Vst::ProcessContext m_context;
582 param_changes m_inputChanges;
583 param_changes m_outputChanges;
584 Steinberg::Vst::EventList m_inputEvents;
585 Steinberg::Vst::EventList m_outputEvents;
589 ossia::small_vector<std::pair<int, libremidi::ump>, 8>
m_deferred;
599 if constexpr(UseDouble)
600 m_vstData.symbolicSampleSize = Steinberg::Vst::kSample64;
602 m_vstData.symbolicSampleSize = Steinberg::Vst::kSample32;
607 std::string label()
const noexcept override {
return "VST3"; }
609 void all_notes_off(
int bus)
noexcept
615 = this->fx.midi_controls.find({bus, 0, Steinberg::Vst::kCtrlAllNotesOff});
616 it != this->fx.midi_controls.end())
618 Steinberg::Vst::ParamID pid = it->second;
619 if(
auto queue_it = this->queue_map.find(pid); queue_it != this->queue_map.end())
621 auto& queue = this->m_inputChanges.queues[queue_it->second];
622 queue.data.push_back({0, 1.});
623 queue.lastValue = 1.;
629 = this->fx.midi_controls.find({bus, 0, Steinberg::Vst::kCtrlAllSoundsOff});
630 it != this->fx.midi_controls.end())
632 Steinberg::Vst::ParamID pid = it->second;
633 if(
auto queue_it = this->queue_map.find(pid); queue_it != this->queue_map.end())
635 auto& queue = this->m_inputChanges.queues[queue_it->second];
636 queue.data.push_back({0, 1.});
637 queue.lastValue = 1.;
645 for(
int k = 0; k <= 16; k++)
646 for(
int i = 0; i <= 127; i++)
648 using VstEvent = Steinberg::Vst::Event;
654 e.type = VstEvent::kNoteOffEvent;
655 e.noteOff.channel = k;
657 e.noteOff.velocity = 0;
658 e.noteOff.noteId = -1;
659 e.noteOff.tuning = 0.f;
660 m_inputEvents.addEvent(e);
665 void all_notes_off()
noexcept override
667 if(m_totalEventIns == 0)
670 m_inputEvents.clear();
674 for(
int i = 0; i < m_totalEventIns; i++)
682 constexpr int samples = 64;
683 Steinberg::Vst::ProcessData dat;
684 memcpy(&dat, &m_vstData,
sizeof(m_vstData));
685 dat.inputEvents = &m_inputEvents;
686 dat.numSamples = samples;
693 if(m_totalAudioIns > 0)
695 input = (
double**)alloca(
sizeof(
double*) * m_totalAudioIns);
697 for(
int k = 0; k < m_totalAudioIns; k++)
699 input[k] = (
double*)alloca(
sizeof(
double) * samples);
700 memset(input[k], 0,
sizeof(
double) * samples);
703 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
705 Steinberg::Vst::AudioBusBuffers& vst_in = dat.inputs[i];
706 vst_in.channelBuffers64 = input;
707 vst_in.silenceFlags = ~0ULL;
712 if(m_totalAudioOuts > 0)
714 output = (
double**)alloca(
sizeof(
double*) * m_totalAudioOuts);
715 for(
int k = 0; k < m_totalAudioOuts; k++)
717 output[k] = (
double*)alloca(
sizeof(
double) * samples);
718 memset(output[k], 0,
sizeof(
double) * samples);
721 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
723 Steinberg::Vst::AudioBusBuffers& vst_out = dat.outputs[i];
724 vst_out.channelBuffers64 = output;
725 vst_out.silenceFlags = ~0ULL;
729 fx.processor->process(dat);
734 void run(
const ossia::token_request& tk, ossia::exec_state_facade st)
noexcept override
736 if(!muted() && !tk.paused())
738 const auto [tick_start, samples] = st.timings(tk);
748 this->setupTimeInfo(tk, st);
750 this->dispatchMidi(tick_start, samples);
752 if constexpr(UseDouble)
754 processDouble(tick_start, samples, st.bufferSize());
758 processFloat(tick_start, samples, st.bufferSize());
761 this->readbackMidi(tick_start);
765 void processFloat(int64_t tick_start, std::size_t samples,
int bufferSize)
768 if constexpr(!UseDouble)
771 if(m_totalAudioIns > 0 || m_totalAudioOuts > 0)
773 float_v.resize(std::max(m_totalAudioIns, m_totalAudioOuts));
774 for(
auto& v : float_v)
781 if(m_totalAudioIns > 0)
783 input = (
float**)alloca(
sizeof(
float*) * m_totalAudioIns);
787 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
789 const int numChannels = m_audioInputChannels[i];
790 auto& port = *m_inlets[i]->template target<ossia::audio_port>();
791 auto& ip = preparePort(port, numChannels, bufferSize);
793 Steinberg::Vst::AudioBusBuffers& vst_in = m_vstInput[i];
794 vst_in.channelBuffers32 = input + channel_k;
795 vst_in.silenceFlags = 0;
797 for(
int k = 0; k < numChannels; k++)
799 const std::size_t avail = ip[k].size() > std::size_t(tick_start)
800 ? ip[k].size() - std::size_t(tick_start)
803 ip[k].data() + tick_start, std::min(samples, avail),
804 float_v[float_k].data());
805 input[channel_k] = float_v[float_k].data();
813 if(m_totalAudioOuts > 0)
816 output = (
float**)alloca(
sizeof(
float*) * m_totalAudioOuts);
820 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
822 const int numChannels = m_audioOutputChannels[i];
823 auto& port = *m_outlets[i]->template target<ossia::audio_port>();
824 preparePort(port, numChannels, bufferSize);
826 Steinberg::Vst::AudioBusBuffers& vst_out = m_vstOutput[i];
827 vst_out.channelBuffers32 = output + channel_k;
828 vst_out.silenceFlags = 0;
829 for(
int k = 0; k < numChannels; k++)
831 output[channel_k] = float_v[float_k].data();
841 m_vstData.numSamples = samples;
843 fx.processor->process(m_vstData);
847 if(m_totalAudioOuts > 0)
850 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
852 const int numChannels = m_audioOutputChannels[i];
853 ossia::audio_port& port = *m_outlets[i]->template target<ossia::audio_port>();
854 for(
int k = 0; k < numChannels; k++)
856 auto& audio_out = port.channel(k);
858 float_v[float_k].data(), samples, audio_out.data() + tick_start);
866 void processDouble(int64_t tick_start, std::size_t samples,
int bufferSize)
870 if constexpr(UseDouble)
876 if(m_totalAudioIns > 0)
878 input = (
double**)alloca(
sizeof(
double*) * m_totalAudioIns);
881 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
883 const int numChannels = m_audioInputChannels[i];
884 auto& port = *m_inlets[i]->template target<ossia::audio_port>();
885 auto& ip = preparePort(port, numChannels, bufferSize);
887 Steinberg::Vst::AudioBusBuffers& vst_in = m_vstInput[i];
888 vst_in.channelBuffers64 = input + channel_k;
889 vst_in.silenceFlags = 0;
890 for(
int k = 0; k < numChannels; k++)
892 input[channel_k++] = ip[k].data() + tick_start;
898 if(m_totalAudioOuts > 0)
900 output = (
double**)alloca(
sizeof(
double*) * m_totalAudioOuts);
902 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
904 const int numChannels = m_audioOutputChannels[i];
905 auto& port = *m_outlets[i]->template target<ossia::audio_port>();
906 auto& op = preparePort(port, numChannels, bufferSize);
908 Steinberg::Vst::AudioBusBuffers& vst_out = m_vstOutput[i];
909 vst_out.channelBuffers64 = output + channel_k;
910 vst_out.silenceFlags = 0;
911 for(
int k = 0; k < numChannels; k++)
913 output[channel_k++] = op[k].data() + tick_start;
920 m_vstData.numSamples = samples;
922 fx.processor->process(m_vstData);
930 std::conditional_t<!UseDouble, std::vector<ossia::float_vector>,
dummy_t> float_v;