2 #include <Process/Dataflow/TimeSignature.hpp>
4 #include <Vst3/EffectModel.hpp>
6 #include <ossia/dataflow/fx_node.hpp>
7 #include <ossia/dataflow/graph_node.hpp>
8 #include <ossia/dataflow/port.hpp>
9 #include <ossia/detail/logger.hpp>
10 #include <ossia/detail/math.hpp>
11 #include <ossia/detail/pod_vector.hpp>
12 #include <ossia/detail/ssize.hpp>
13 #include <ossia/editor/scenario/time_signature.hpp>
15 #include <pluginterfaces/vst/ivstmidicontrollers.h>
17 #include <public.sdk/source/vst/hosting/eventlist.h>
18 #include <public.sdk/source/vst/hosting/parameterchanges.h>
22 class param_queue final :
public Steinberg::Vst::IParamValueQueue
31 Steinberg::Vst::ParamID
id{};
32 ossia::small_vector<std::pair<int32_t, Steinberg::Vst::ParamValue>, 1> data;
33 Steinberg::Vst::ParamValue lastValue{};
35 Steinberg::tresult queryInterface(
const Steinberg::TUID _iid,
void** obj)
override
37 return Steinberg::kResultOk;
39 Steinberg::uint32 addRef()
override {
return 1; }
40 Steinberg::uint32 release()
override {
return 1; }
42 Steinberg::Vst::ParamID getParameterId()
override {
return id; }
43 Steinberg::int32 getPointCount()
override {
return data.size(); }
44 Steinberg::tresult getPoint(
45 Steinberg::int32 index, Steinberg::int32& sampleOffset,
46 Steinberg::Vst::ParamValue& value)
override
48 if(ossia::valid_index(index, data))
49 std::tie(sampleOffset, value) = data[index];
56 return Steinberg::kResultOk;
59 Steinberg::tresult addPoint(
60 Steinberg::int32 sampleOffset, Steinberg::Vst::ParamValue value,
61 Steinberg::int32& index)
override
64 data.emplace_back(sampleOffset, value);
65 return Steinberg::kResultOk;
72 std::vector<param_queue> queues;
73 Steinberg::tresult queryInterface(
const Steinberg::TUID _iid,
void** obj)
override
75 return Steinberg::kResultOk;
77 Steinberg::uint32 addRef()
override {
return 1; }
78 Steinberg::uint32 release()
override {
return 1; }
80 Steinberg::int32 getParameterCount()
override {
return queues.size(); }
82 param_queue* getParameterData(Steinberg::int32 index)
override
84 return &queues[index];
88 const Steinberg::Vst::ParamID&
id, Steinberg::int32& index )
override
90 index = queues.size();
91 queues.emplace_back(
id);
92 return &queues.back();
102 : component{p.component}
103 , processor{p.processor}
104 , midi_controls{p.midiControls}
116 Steinberg::Vst::IComponent* component{};
117 Steinberg::Vst::IAudioProcessor* processor{};
118 MIDIControls midi_controls;
123 ossia::small_pod_vector<int, 2> m_audioInputChannels{};
124 ossia::small_pod_vector<int, 2> m_audioOutputChannels{};
125 int m_totalAudioIns{};
126 int m_totalAudioOuts{};
127 int m_totalEventIns{};
128 int m_totalEventOuts{};
131 explicit vst_node_base(
const Plugin& ptr)
134 m_inlets.reserve(10);
135 controls.reserve(10);
140 void audioIn(
const Steinberg::Vst::BusInfo& bus,
int idx)
142 self.m_inlets.push_back(
new ossia::audio_inlet);
143 self.m_audioInputChannels.push_back(bus.channelCount);
144 self.m_totalAudioIns += bus.channelCount;
146 void eventIn(
const Steinberg::Vst::BusInfo& bus,
int idx)
148 self.m_inlets.push_back(
new ossia::midi_inlet);
149 self.m_totalEventIns++;
151 void audioOut(
const Steinberg::Vst::BusInfo& bus,
int idx)
153 self.m_outlets.push_back(
new ossia::audio_outlet);
154 self.m_audioOutputChannels.push_back(bus.channelCount);
155 self.m_totalAudioOuts += bus.channelCount;
157 void eventOut(
const Steinberg::Vst::BusInfo& bus,
int idx)
159 self.m_outlets.push_back(
new ossia::midi_outlet);
160 self.m_totalEventOuts++;
164 forEachBus(vis{*
this}, *fx.component);
166 if(
auto err = fx.processor->setProcessing(
true);
167 err != Steinberg::kResultOk && err != Steinberg::kNotImplemented)
169 ossia::logger().warn(
"Couldn't set VST3 processing: {}", err);
172 m_vstData.processMode = Steinberg::Vst::ProcessModes::kRealtime;
173 m_vstData.numInputs = m_audioInputChannels.size();
174 m_vstData.numOutputs = m_audioOutputChannels.size();
175 m_vstInput.resize(m_audioInputChannels.size());
176 m_vstOutput.resize(m_audioOutputChannels.size());
177 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
179 m_vstInput[i].numChannels = m_audioInputChannels[i];
181 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
183 m_vstOutput[i].numChannels = m_audioOutputChannels[i];
186 m_vstData.inputs = m_vstInput.data();
187 m_vstData.outputs = m_vstOutput.data();
188 m_vstData.inputParameterChanges = &m_inputChanges;
189 m_vstData.outputParameterChanges = &m_outputChanges;
190 m_vstData.inputEvents = &m_inputEvents;
191 m_vstData.outputEvents = &m_outputEvents;
192 m_vstData.processContext = &m_context;
194 m_inputEvents.setMaxSize(17 * 128 * m_totalEventIns);
195 m_outputEvents.setMaxSize(128 * m_totalEventOuts);
200 if(
auto err = fx.processor->setProcessing(
false);
201 err != Steinberg::kResultOk && err != Steinberg::kNotImplemented)
203 ossia::logger().warn(
"Couldn't set VST3 processing: {}", err);
209 Steinberg::Vst::ParamID idx{};
210 std::size_t queue_idx{};
211 ossia::value_port* port{};
214 ossia::hash_map<Steinberg::Vst::ParamID, std::size_t> queue_map;
217 ossia::small_vector<vst_control, 16> controls;
219 std::size_t add_control(ossia::value_inlet* inlet, Steinberg::Vst::ParamID
id,
float v)
221 (**inlet).domain = ossia::domain_base<float>{0.f, 1.f};
222 (**inlet).type = ossia::val_type::FLOAT;
225 auto queue_idx = this->m_inputChanges.queues.size();
226 this->m_inputChanges.queues.emplace_back(
id);
227 this->m_inputChanges.queues.back().lastValue = v;
229 queue_map[id] = queue_idx;
230 controls.push_back({id, queue_idx, inlet->target<ossia::value_port>()});
231 root_inputs().push_back(std::move(inlet));
236 void set_control(std::size_t queue_idx,
float value)
238 auto& queue = this->m_inputChanges.queues[queue_idx];
239 queue.lastValue = value;
241 queue.data.emplace_back(0, value);
246 for(vst_control& p : controls)
248 const auto& vec = p.port->get_data();
251 if(
auto t = last(vec).target<float>())
253 double value = ossia::clamp<double>((
double)*t, 0., 1.);
254 auto& queue = m_inputChanges.queues[p.queue_idx];
256 queue.data.emplace_back(0, value);
257 queue.lastValue = value;
264 m_inputEvents.clear();
265 m_outputEvents.clear();
268 int audioBusCount = std::ssize(m_audioInputChannels);
269 for(
int i = audioBusCount; i < audioBusCount + m_totalEventIns; i++)
271 dispatchMidi(*m_inlets[i]->
template target<ossia::midi_port>(), k++);
273 m_vstData.inputEvents
274 = (m_inputEvents.getEventCount() > 0) ? &m_inputEvents :
nullptr;
275 m_vstData.outputEvents = &m_outputEvents;
278 void dispatchMidi(ossia::midi_port& port,
int index)
281 auto& ip = port.messages;
285 using VstEvent = Steinberg::Vst::Event;
290 for(
const libremidi::message& mess : ip)
292 e.sampleOffset = mess.timestamp;
293 switch(mess.get_message_type())
295 case libremidi::message_type::NOTE_ON: {
296 if(mess.bytes[2] > 0)
298 e.type = VstEvent::kNoteOnEvent;
299 e.noteOn.channel = mess.get_channel();
300 e.noteOn.pitch = mess.bytes[1];
301 e.noteOn.velocity = mess.bytes[2] / 127.f;
302 e.noteOn.noteId = -1;
303 e.noteOn.tuning = 0.f;
304 m_inputEvents.addEvent(e);
308 e.type = VstEvent::kNoteOffEvent;
309 e.noteOff.channel = mess.get_channel();
310 e.noteOff.pitch = mess.bytes[1];
311 e.noteOff.velocity = 0;
312 e.noteOff.noteId = -1;
313 e.noteOff.tuning = 0.f;
314 m_inputEvents.addEvent(e);
318 case libremidi::message_type::NOTE_OFF: {
319 e.type = VstEvent::kNoteOffEvent;
320 e.noteOff.channel = mess.get_channel();
321 e.noteOff.pitch = mess.bytes[1];
322 e.noteOff.velocity = mess.bytes[2] / 127.f;
323 e.noteOff.noteId = -1;
324 e.noteOff.tuning = 0.f;
325 m_inputEvents.addEvent(e);
328 case libremidi::message_type::POLY_PRESSURE: {
329 e.type = VstEvent::kPolyPressureEvent;
330 e.polyPressure.channel = mess.get_channel();
331 e.polyPressure.pitch = mess.bytes[1];
332 e.polyPressure.pressure = mess.bytes[2] / 127.f;
333 e.polyPressure.noteId = -1;
334 m_inputEvents.addEvent(e);
338 case libremidi::message_type::PITCH_BEND: {
339 if(
auto it = this->fx.midi_controls.find({index, Steinberg::Vst::kPitchBend});
340 it != this->fx.midi_controls.end())
342 double pitch = (mess.bytes[2] * 128 + mess.bytes[1]) / (128. * 128.);
343 Steinberg::Vst::ParamID pid = it->second;
344 if(
auto queue_it = this->queue_map.find(pid);
345 queue_it != this->queue_map.end())
347 auto& queue = this->m_inputChanges.queues[queue_it->second];
348 queue.data.push_back({e.sampleOffset, pitch});
349 queue.lastValue = pitch;
354 case libremidi::message_type::AFTERTOUCH: {
355 if(
auto it = this->fx.midi_controls.find({index, Steinberg::Vst::kAfterTouch});
356 it != this->fx.midi_controls.end())
358 double value = mess.bytes[1] / 128.;
359 Steinberg::Vst::ParamID pid = it->second;
360 if(
auto queue_it = this->queue_map.find(pid);
361 queue_it != this->queue_map.end())
363 auto& queue = this->m_inputChanges.queues[queue_it->second];
364 queue.data.push_back({e.sampleOffset, value});
365 queue.lastValue = value;
377 using VstEvent = Steinberg::Vst::Event;
379 const int audioBusCount = std::ssize(m_audioOutputChannels);
380 const int N = m_outputEvents.getEventCount();
382 for(
int i = 0; i < N; i++)
384 auto event_p = m_outputEvents.getEventByIndex(i);
387 VstEvent& e = *event_p;
389 int bus = e.busIndex;
390 auto& port = *m_outlets[bus + audioBusCount]->template target<ossia::midi_port>();
392 libremidi::message mess;
396 case VstEvent::kNoteOnEvent: {
397 if(e.noteOn.velocity > 0.f)
398 mess = libremidi::channel_events::note_on(
399 e.noteOn.channel, e.noteOn.pitch, e.noteOn.velocity * 127.f);
401 mess = libremidi::channel_events::note_off(
402 e.noteOn.channel, e.noteOn.pitch, 0.);
405 case VstEvent::kNoteOffEvent: {
406 mess = libremidi::channel_events::note_off(
407 e.noteOff.channel, e.noteOff.pitch, 0.);
410 case VstEvent::kPolyPressureEvent: {
411 mess = libremidi::channel_events::poly_pressure(
412 e.noteOff.channel, e.polyPressure.pitch, e.polyPressure.pressure * 127.f);
419 mess.timestamp = e.sampleOffset;
420 port.messages.push_back(std::move(mess));
424 auto& preparePort(ossia::audio_port& port,
int numChannels, std::size_t samples)
426 port.set_channels(numChannels);
433 void setupTimeInfo(
const ossia::token_request& tk, ossia::exec_state_facade st)
435 using namespace Steinberg::Vst;
436 using F = ProcessContext;
437 Steinberg::Vst::ProcessContext& time_info = this->m_context;
438 time_info.sampleRate = st.sampleRate();
441 time_info.projectTimeSamples = tk.start_date_to_physical(st.modelToSamples());
443 time_info.systemTime = st.currentDate() - st.startDate();
444 time_info.continousTimeSamples = time_info.projectTimeSamples;
446 time_info.projectTimeMusic = tk.musical_start_position;
447 time_info.barPositionMusic = tk.musical_start_last_bar;
448 time_info.cycleStartMusic = 0.;
449 time_info.cycleEndMusic = 0.;
451 time_info.tempo = tk.tempo;
452 time_info.timeSigNumerator = tk.signature.upper;
453 time_info.timeSigDenominator = tk.signature.lower;
457 time_info.smpteOffsetSubframes = 0;
458 time_info.frameRate = {};
459 time_info.samplesToNextClock = 0;
460 time_info.state = F::kPlaying | F::kSystemTimeValid | F::kContTimeValid
461 | F::kProjectTimeMusicValid | F::kBarPositionValid | F::kTempoValid
465 Steinberg::Vst::ProcessData m_vstData;
466 ossia::small_vector<Steinberg::Vst::AudioBusBuffers, 1> m_vstInput;
467 ossia::small_vector<Steinberg::Vst::AudioBusBuffers, 1> m_vstOutput;
469 Steinberg::Vst::ProcessContext m_context;
470 param_changes m_inputChanges;
471 param_changes m_outputChanges;
472 Steinberg::Vst::EventList m_inputEvents;
473 Steinberg::Vst::EventList m_outputEvents;
476 template <
bool UseDouble>
483 if constexpr(UseDouble)
484 m_vstData.symbolicSampleSize = Steinberg::Vst::kSample64;
486 m_vstData.symbolicSampleSize = Steinberg::Vst::kSample32;
491 std::string label()
const noexcept
override {
return "VST3"; }
493 void all_notes_off(
int bus) noexcept
496 if(
auto it = this->fx.midi_controls.find({bus, Steinberg::Vst::kCtrlAllNotesOff});
497 it != this->fx.midi_controls.end())
499 Steinberg::Vst::ParamID pid = it->second;
500 if(
auto queue_it = this->queue_map.find(pid); queue_it != this->queue_map.end())
502 auto& queue = this->m_inputChanges.queues[queue_it->second];
503 queue.data.push_back({0, 1.});
504 queue.lastValue = 1.;
509 if(
auto it = this->fx.midi_controls.find({bus, Steinberg::Vst::kCtrlAllSoundsOff});
510 it != this->fx.midi_controls.end())
512 Steinberg::Vst::ParamID pid = it->second;
513 if(
auto queue_it = this->queue_map.find(pid); queue_it != this->queue_map.end())
515 auto& queue = this->m_inputChanges.queues[queue_it->second];
516 queue.data.push_back({0, 1.});
517 queue.lastValue = 1.;
525 for(
int k = 0; k <= 16; k++)
526 for(
int i = 0; i <= 127; i++)
528 using VstEvent = Steinberg::Vst::Event;
534 e.type = VstEvent::kNoteOffEvent;
535 e.noteOff.channel = k;
537 e.noteOff.velocity = 0;
538 e.noteOff.noteId = -1;
539 e.noteOff.tuning = 0.f;
540 m_inputEvents.addEvent(e);
545 void all_notes_off() noexcept
override
547 if(m_totalEventIns == 0)
550 m_inputEvents.clear();
554 for(
int i = 0; i < m_totalEventIns; i++)
562 constexpr
int samples = 64;
563 Steinberg::Vst::ProcessData dat;
564 memcpy(&dat, &m_vstData,
sizeof(m_vstData));
565 dat.inputEvents = &m_inputEvents;
566 dat.numSamples = samples;
573 if(m_totalAudioIns > 0)
575 input = (
double**)alloca(
sizeof(
double*) * m_totalAudioIns);
577 for(
int k = 0; k < m_totalAudioIns; k++)
579 input[k] = (
double*)alloca(
sizeof(
double) * samples);
580 memset(input[k], 0,
sizeof(
double) * samples);
583 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
585 Steinberg::Vst::AudioBusBuffers& vst_in = dat.inputs[i];
586 vst_in.channelBuffers64 = input;
587 vst_in.silenceFlags = ~0ULL;
592 if(m_totalAudioOuts > 0)
594 output = (
double**)alloca(
sizeof(
double*) * m_totalAudioOuts);
595 for(
int k = 0; k < m_totalAudioOuts; k++)
597 output[k] = (
double*)alloca(
sizeof(
double) * samples);
598 memset(output[k], 0,
sizeof(
double) * samples);
601 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
603 Steinberg::Vst::AudioBusBuffers& vst_out = dat.outputs[i];
604 vst_out.channelBuffers64 = output;
605 vst_out.silenceFlags = ~0ULL;
609 fx.processor->process(dat);
614 void run(
const ossia::token_request& tk, ossia::exec_state_facade st) noexcept
override
616 if(!muted() && tk.date > tk.prev_date)
618 const auto [tick_start, samples] = st.timings(tk);
620 this->setupTimeInfo(tk, st);
622 this->dispatchMidi();
624 if constexpr(UseDouble)
626 processDouble(samples);
630 processFloat(samples);
633 this->readbackMidi();
637 void processFloat(std::size_t samples)
640 if constexpr(!UseDouble)
643 if(m_totalAudioIns > 0 || m_totalAudioOuts > 0)
645 float_v.resize(std::max(m_totalAudioIns, m_totalAudioOuts));
646 for(
auto& v : float_v)
653 if(m_totalAudioIns > 0)
655 input = (
float**)alloca(
sizeof(
float*) * m_totalAudioIns);
659 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
661 const int numChannels = m_audioInputChannels[i];
662 auto& port = *m_inlets[i]->template target<ossia::audio_port>();
663 auto& ip = preparePort(port, numChannels, samples);
665 Steinberg::Vst::AudioBusBuffers& vst_in = m_vstInput[i];
666 vst_in.channelBuffers32 = input + channel_k;
667 vst_in.silenceFlags = 0;
669 for(
int k = 0; k < numChannels; k++)
672 ip[k].data(), std::min(samples, ip[k].size()),
673 float_v[float_k].data());
674 input[channel_k] = float_v[float_k].data();
682 if(m_totalAudioOuts > 0)
685 output = (
float**)alloca(
sizeof(
float*) * m_totalAudioOuts);
689 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
691 const int numChannels = m_audioOutputChannels[i];
692 auto& port = *m_outlets[i]->template target<ossia::audio_port>();
693 preparePort(port, numChannels, samples);
695 Steinberg::Vst::AudioBusBuffers& vst_out = m_vstOutput[i];
696 vst_out.channelBuffers32 = output + channel_k;
697 vst_out.silenceFlags = 0;
698 for(
int k = 0; k < numChannels; k++)
700 output[channel_k] = float_v[float_k].data();
710 m_vstData.numSamples = samples;
712 fx.processor->process(m_vstData);
716 if(m_totalAudioOuts > 0)
719 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
721 const int numChannels = m_audioOutputChannels[i];
722 ossia::audio_port& port = *m_outlets[i]->template target<ossia::audio_port>();
723 for(
int k = 0; k < numChannels; k++)
725 auto& audio_out = port.channel(k);
726 std::copy_n(float_v[float_k].data(), samples, audio_out.data());
733 void processDouble(std::size_t samples)
737 if constexpr(UseDouble)
743 if(m_totalAudioIns > 0)
745 input = (
double**)alloca(
sizeof(
double*) * m_totalAudioIns);
748 for(std::size_t i = 0; i < m_audioInputChannels.size(); i++)
750 const int numChannels = m_audioInputChannels[i];
751 auto& port = *m_inlets[i]->template target<ossia::audio_port>();
752 auto& ip = preparePort(port, numChannels, samples);
754 Steinberg::Vst::AudioBusBuffers& vst_in = m_vstInput[i];
755 vst_in.channelBuffers64 = input + channel_k;
756 vst_in.silenceFlags = 0;
757 for(
int k = 0; k < numChannels; k++)
759 input[channel_k++] = ip[k].data();
765 if(m_totalAudioOuts > 0)
767 output = (
double**)alloca(
sizeof(
double*) * m_totalAudioOuts);
769 for(std::size_t i = 0; i < m_audioOutputChannels.size(); i++)
771 const int numChannels = m_audioOutputChannels[i];
772 auto& port = *m_outlets[i]->template target<ossia::audio_port>();
773 auto& op = preparePort(port, numChannels, samples);
775 Steinberg::Vst::AudioBusBuffers& vst_out = m_vstOutput[i];
776 vst_out.channelBuffers64 = output + channel_k;
777 vst_out.silenceFlags = 0;
778 for(
int k = 0; k < numChannels; k++)
780 output[channel_k++] = op[k].data();
787 m_vstData.numSamples = samples;
789 fx.processor->process(m_vstData);
797 std::conditional_t<!UseDouble, std::vector<ossia::float_vector>,
dummy_t> float_v;
800 template <
bool b1,
typename... Args>
801 auto make_vst_fx(Args&... args)
803 return ossia::make_node<vst_node<b1>>(args...);
Definition: score-plugin-vst3/Vst3/Node.hpp:70
Definition: score-plugin-vst3/Vst3/Node.hpp:23
Definition: score-plugin-vst3/Vst3/Node.hpp:97
Definition: score-plugin-vst3/Vst3/Node.hpp:478
Definition: Plugin.hpp:37
Definition: score-plugin-vst3/Vst3/Node.hpp:795
Definition: score-plugin-vst3/Vst3/Node.hpp:100
Definition: score-plugin-vst3/Vst3/Node.hpp:208