21 std::shared_ptr<AEffectWrapper> fx{};
27 this->set_not_fp_safe();
36 ossia::value_port* port{};
40 int32_t opcode, int32_t index = 0, intptr_t value = 0,
void* ptr =
nullptr,
43 fx->dispatch(opcode, index, value, ptr, opt);
47 ossia::small_vector<vst_control, 16> controls;
51 for(vst_control& p : controls)
53 const auto& vec = p.port->get_data();
56 auto t = ossia::convert<float>(last(vec));
58 p.value = ossia::clamp<float>(t, 0.f, 1.f);
59 fx->fx->setParameter(fx->fx, p.idx, p.value);
64 auto& prepareInput(int64_t offset, int64_t samples)
66 const auto bs = offset + samples;
67 auto& p = *m_inlets[0]->template target<ossia::audio_port>();
72 p.channel(0).resize(bs);
73 p.channel(1).resize(bs);
78 p.channel(0).resize(bs);
79 p.channel(1).assign(p.channel(0).begin(), p.channel(0).end());
92 auto& prepareOutput(int64_t offset, int64_t samples)
94 const auto bs = offset + samples;
95 auto& p = *m_outlets[0]->template target<ossia::audio_port>();
98 chan.resize(bs, boost::container::default_init);
102 void setupTimeInfo(
const ossia::token_request& tk, ossia::exec_state_facade st)
104 auto& time_info = fx->info;
105 time_info.samplePos = this->m_transport_frames;
106 time_info.sampleRate = st.sampleRate();
107 time_info.nanoSeconds = st.currentDate() - st.startDate();
108 time_info.ppqPos = tk.musical_start_position;
109 time_info.tempo = tk.tempo;
110 time_info.barStartPos = tk.musical_start_last_bar;
111 time_info.cycleStartPos = 0.;
112 time_info.cycleEndPos = 0.;
113 time_info.timeSigNumerator = tk.signature.upper;
114 time_info.timeSigDenominator = tk.signature.lower;
115 time_info.smpteOffset = 0;
116 time_info.smpteFrameRate = 0;
117 time_info.samplesToNextClock = 0;
118 time_info.flags = kVstTransportPlaying | kVstNanosValid | kVstPpqPosValid
119 | kVstTempoValid | kVstBarsValid | kVstTimeSigValid
128 static constexpr bool synth = IsSynth;
129 VstSpeakerArrangement i_arr{};
130 VstSpeakerArrangement o_arr{};
133 vst_node(std::shared_ptr<AEffectWrapper> dat,
int sampleRate,
int bs)
138 m_inlets.push_back(
new ossia::audio_inlet);
139 if constexpr(IsSynth)
140 m_inlets.push_back(
new ossia::midi_inlet);
143 m_outlets.push_back(
new ossia::audio_outlet);
146 memset(&i_arr, 0,
sizeof(i_arr));
147 memset(&o_arr, 0,
sizeof(o_arr));
148 i_arr.type = kSpeakerArrStereo;
149 i_arr.numChannels = 2;
150 i_arr.speakers[0].type = kSpeakerL;
151 i_arr.speakers[1].type = kSpeakerR;
153 o_arr.type = kSpeakerArrStereo;
154 o_arr.numChannels = 2;
155 o_arr.speakers[0].type = kSpeakerL;
156 o_arr.speakers[1].type = kSpeakerR;
157 dispatch(effSetSpeakerArrangement, 0, (intptr_t)&i_arr, (
void*)&o_arr, 0);
160 dispatch(effSetSampleRate, 0, sampleRate,
nullptr, sampleRate);
161 dispatch(effSetBlockSize, 0, bs,
nullptr, bs);
163 effSetProcessPrecision, 0,
164 UseDouble ? kVstProcessPrecision64 : kVstProcessPrecision32);
165 dispatch(effMainsChanged, 0, 1);
166 dispatch(effStartProcess);
168 fx->fx->resvd2 =
reinterpret_cast<intptr_t
>(
this);
174 dispatch(effStopProcess);
175 dispatch(effMainsChanged, 0, 0);
178 std::string label()
const noexcept override
180 char paramName[512] = {0};
181 fx->fx->dispatcher(fx->fx, effGetProductString, 0, 0, paramName, 0.0f);
185 void all_notes_off()
noexcept override
187 if constexpr(IsSynth)
191 constexpr auto sz =
sizeof(VstEvents) +
sizeof(
void*) * 32 * 2;
192 VstEvents* events = (VstEvents*)alloca(sz);
193 std::memset(events, 0, sz);
195 events->numEvents = 32;
197 VstMidiEvent ev[64] = {};
198 memset(&ev, 0,
sizeof(ev));
201 for(
int i = 0; i < 16; i++)
204 e.type = kVstMidiType;
205 e.flags = kVstMidiEventIsRealtime;
206 e.byteSize =
sizeof(VstMidiEvent);
208 e.midiData[0] = (char)(uint8_t)176 + i;
209 e.midiData[1] = (char)(uint8_t)123;
213 events->events[i] =
reinterpret_cast<VstEvent*
>(&e);
217 for(
int i = 0; i < 16; i++)
219 auto& e = ev[16 + i];
220 e.type = kVstMidiType;
221 e.flags = kVstMidiEventIsRealtime;
222 e.byteSize =
sizeof(VstMidiEvent);
224 e.midiData[0] = (char)(uint8_t)176 + i;
225 e.midiData[1] = (char)(uint8_t)121;
229 events->events[16 + i] =
reinterpret_cast<VstEvent*
>(&e);
232 dispatch(effProcessEvents, 0, 0, events, 0.f);
234 if constexpr(!UseDouble)
236 float* dummy = (
float*)alloca(
sizeof(
float) * m_bs);
237 std::fill_n(dummy, m_bs, 0.f);
240 = (
float**)alloca(
sizeof(
float*) * std::max(2, this->fx->fx->numInputs));
241 for(
int i = 0; i < this->fx->fx->numInputs; i++)
245 = (
float**)alloca(
sizeof(
float*) * std::max(2, this->fx->fx->numOutputs));
246 for(
int i = 0; i < this->fx->fx->numOutputs; i++)
249 fx->fx->processReplacing(fx->fx, input, output, m_bs);
253 double* dummy = (
double*)alloca(
sizeof(
double) * m_bs);
254 std::fill_n(dummy, m_bs, 0.);
257 = (
double**)alloca(
sizeof(
double*) * std::max(2, this->fx->fx->numInputs));
258 for(
int i = 0; i < this->fx->fx->numInputs; i++)
262 = (
double**)alloca(
sizeof(
double*) * std::max(2, this->fx->fx->numOutputs));
263 for(
int i = 0; i < this->fx->fx->numOutputs; i++)
266 fx->fx->processDoubleReplacing(fx->fx, input, output, m_bs);
279 for(
const libremidi::ump& mess :
280 static_cast<ossia::midi_inlet*
>(m_inlets[1])->data.messages)
288 template <
typename Fun>
289 void dispatchMidi(int64_t offset, int64_t samples, Fun&& f)
293 auto& ip =
static_cast<ossia::midi_inlet*
>(m_inlets[1])->data.messages;
294 const auto n_mess = ip.size() +
m_deferred.size();
302 const auto sz =
sizeof(VstEvents) +
sizeof(
void*) * n_mess * 2;
303 VstEvents* events = (VstEvents*)alloca(sz);
304 std::memset(events, 0, sz);
305 events->numEvents = n_mess;
307 ossia::small_vector<std::pair<const libremidi::ump*, int64_t>, 16> to_send;
309 to_send.push_back({&mess, 0});
310 for(
const libremidi::ump& mess : ip)
312 {&mess, std::clamp<int64_t>(
313 mess.timestamp - offset, 0, samples > 0 ? samples - 1 : 0)});
315 ossia::small_vector<VstMidiEvent, 16> vec;
318 for(
const auto& [mess_ptr, delta] : to_send)
320 const libremidi::ump& mess = *mess_ptr;
321 if(
auto type = mess.get_type();
322 (type == libremidi::midi2::message_type::SYSEX7)
323 || (type == libremidi::midi2::message_type::SYSEX8_MDS))
329 VstMidiEvent& e = vec[i];
330 std::memset(&e, 0,
sizeof(VstMidiEvent));
331 e.type = kVstMidiType;
332 e.byteSize =
sizeof(VstMidiEvent);
333 e.deltaFrames = delta;
334 e.flags = kVstMidiEventIsRealtime;
336 if(
auto n = cmidi2_convert_single_ump_to_midi1(
337 (uint8_t*)e.midiData, 4, (cmidi2_ump*)mess.data);
340 events->events[i] =
reinterpret_cast<VstEvent*
>(&e);
349 dispatch(effProcessEvents, 0, 0, events, 0.f);
353 void run(
const ossia::token_request& tk, ossia::exec_state_facade st)
noexcept override
355 if(!muted() && !tk.paused())
357 const auto timings = st.timings(tk);
358 if(timings.length <= 0)
362 if constexpr(IsSynth)
368 this->setupTimeInfo(tk, st);
370 if constexpr(UseDouble)
372 if constexpr(IsSynth)
374 dispatchMidi(timings.start_sample, timings.length, [
this, timings] {
375 processDouble(timings.start_sample, timings.length);
380 processDouble(timings.start_sample, timings.length);
385 if constexpr(IsSynth)
387 dispatchMidi(timings.start_sample, timings.length, [
this, timings] {
388 processFloat(timings.start_sample, timings.length);
393 processFloat(timings.start_sample, timings.length);
398 if(this->fx->fx->numOutputs == 1)
400 auto& op = m_outlets[0]->template target<ossia::audio_port>()->get();
401 op[1].assign(op[0].begin(), op[0].end());
406 void processFloat(int64_t offset, int64_t samples)
408 if constexpr(!UseDouble)
413 SCORE_ASSERT(m_bs >= offset + samples);
415 const auto max_i = std::max(2, this->fx->fx->numInputs);
416 const auto max_o = std::max(2, this->fx->fx->numOutputs);
417 const auto max_io = std::max(max_i, max_o);
419 const auto max_samples = std::max(samples, (int64_t)m_bs);
424 auto& ip = prepareInput(offset, samples);
425 SCORE_ASSERT(ip.size() >= 2);
427 auto& op = prepareOutput(offset, samples);
428 SCORE_ASSERT(op.size() >= 2);
431 float_v[0].resize(max_samples);
432 float_v[1].resize(max_samples);
434 std::copy_n(ip[0].data() + offset, samples, float_v[0].data());
435 std::copy_n(ip[1].data() + offset, samples, float_v[1].data());
437 float** io = (
float**)alloca(
sizeof(
float*) * max_io);
438 io[0] = float_v[0].data();
439 io[1] = float_v[1].data();
445 float* dummy = (
float*)alloca(
sizeof(
float) * max_samples);
446 std::fill_n(dummy, max_samples, 0.f);
448 for(
int i = 2; i < max_io; i++)
452 fx->fx->processReplacing(fx->fx, io, io, samples);
454 std::copy_n(float_v[0].data(), samples, op[0].data() + offset);
455 std::copy_n(float_v[1].data(), samples, op[1].data() + offset);
462 void processDouble(int64_t offset, int64_t samples)
464 if constexpr(UseDouble)
469 SCORE_ASSERT(m_bs >= offset + samples);
471 const auto max_i = std::max(2, this->fx->fx->numInputs);
472 const auto max_o = std::max(2, this->fx->fx->numOutputs);
473 const auto max_io = std::max(max_i, max_o);
476 auto& ip = prepareInput(offset, samples);
477 SCORE_ASSERT(ip.size() >= 2);
479 auto& op = prepareOutput(offset, samples);
480 SCORE_ASSERT(op.size() >= 2);
482 double** input = (
double**)alloca(
sizeof(
double*) * max_i);
483 input[0] = ip[0].data() + offset;
484 input[1] = ip[1].data() + offset;
486 double** output = (
double**)alloca(
sizeof(
double*) * max_o);
487 output[0] = op[0].data() + offset;
488 output[1] = op[1].data() + offset;
494 double* dummy = (
double*)alloca(
sizeof(
double) * m_bs);
495 std::fill_n(dummy, m_bs, 0.);
496 for(
int i = 2; i < this->fx->fx->numInputs; i++)
498 for(
int i = 2; i < this->fx->fx->numOutputs; i++)
502 fx->fx->processDoubleReplacing(fx->fx, input, output, samples);
509 std::conditional_t<!UseDouble, std::array<ossia::float_vector, 2>,
dummy_t> float_v;