2 #include <Process/Dataflow/TimeSignature.hpp>
4 #include <Vst/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/pod_vector.hpp>
10 #include <ossia/editor/scenario/time_signature.hpp>
17 std::shared_ptr<AEffectWrapper> fx{};
31 ossia::value_port* port{};
35 int32_t opcode, int32_t index = 0, intptr_t value = 0,
void* ptr =
nullptr,
38 fx->dispatch(opcode, index, value, ptr, opt);
42 ossia::small_vector<vst_control, 16> controls;
46 for(vst_control& p : controls)
48 const auto& vec = p.port->get_data();
51 auto t = ossia::convert<float>(last(vec));
53 p.value = ossia::clamp<float>(t, 0.f, 1.f);
54 fx->fx->setParameter(fx->fx, p.idx, p.value);
59 auto& prepareInput(int64_t offset, int64_t samples)
61 const auto bs = offset + samples;
62 auto& p = *m_inlets[0]->template target<ossia::audio_port>();
67 p.channel(0).resize(bs);
68 p.channel(1).resize(bs);
73 p.channel(0).resize(bs);
74 p.channel(1).assign(p.channel(0).begin(), p.channel(0).end());
87 auto& prepareOutput(int64_t offset, int64_t samples)
89 const auto bs = offset + samples;
90 auto& p = *m_outlets[0]->template target<ossia::audio_port>();
93 chan.resize(bs, boost::container::default_init);
97 void setupTimeInfo(
const ossia::token_request& tk, ossia::exec_state_facade st)
99 static const constexpr
double ppq_reference = 960.;
101 auto& time_info = fx->info;
104 time_info.samplePos = tk.start_date_to_physical(st.modelToSamples());
105 time_info.sampleRate = st.sampleRate();
106 time_info.nanoSeconds = st.currentDate() - st.startDate();
107 time_info.ppqPos = tk.musical_start_position;
108 time_info.tempo = tk.tempo;
109 time_info.barStartPos = tk.musical_start_last_bar;
110 time_info.cycleStartPos = 0.;
111 time_info.cycleEndPos = 0.;
112 time_info.timeSigNumerator = tk.signature.upper;
113 time_info.timeSigDenominator = tk.signature.lower;
114 time_info.smpteOffset = 0;
115 time_info.smpteFrameRate = 0;
116 time_info.samplesToNextClock = 0;
117 time_info.flags = kVstTransportPlaying | kVstNanosValid | kVstPpqPosValid
118 | kVstTempoValid | kVstBarsValid | kVstTimeSigValid
123 template <
bool UseDouble,
bool IsSynth>
127 static constexpr
bool synth = IsSynth;
128 VstSpeakerArrangement i_arr{};
129 VstSpeakerArrangement o_arr{};
132 vst_node(std::shared_ptr<AEffectWrapper> dat,
int sampleRate,
int bs)
137 m_inlets.push_back(
new ossia::audio_inlet);
138 if constexpr(IsSynth)
139 m_inlets.push_back(
new ossia::midi_inlet);
142 m_outlets.push_back(
new ossia::audio_outlet);
145 memset(&i_arr, 0,
sizeof(i_arr));
146 memset(&o_arr, 0,
sizeof(o_arr));
147 i_arr.type = kSpeakerArrStereo;
148 i_arr.numChannels = 2;
149 i_arr.speakers[0].type = kSpeakerL;
150 i_arr.speakers[1].type = kSpeakerR;
152 o_arr.type = kSpeakerArrStereo;
153 o_arr.numChannels = 2;
154 o_arr.speakers[0].type = kSpeakerL;
155 o_arr.speakers[1].type = kSpeakerR;
156 dispatch(effSetSpeakerArrangement, 0, (intptr_t)&i_arr, (
void*)&o_arr, 0);
159 dispatch(effSetSampleRate, 0, sampleRate,
nullptr, sampleRate);
160 dispatch(effSetBlockSize, 0, bs,
nullptr, bs);
162 effSetProcessPrecision, 0,
163 UseDouble ? kVstProcessPrecision64 : kVstProcessPrecision32);
164 dispatch(effMainsChanged, 0, 1);
165 dispatch(effStartProcess);
167 fx->fx->resvd2 =
reinterpret_cast<intptr_t
>(
this);
173 dispatch(effStopProcess);
174 dispatch(effMainsChanged, 0, 0);
177 std::string label()
const noexcept
override {
return ""; }
179 void all_notes_off() noexcept
override
181 if constexpr(IsSynth)
185 constexpr
auto sz =
sizeof(VstEvents) +
sizeof(
void*) * 32 * 2;
186 VstEvents* events = (VstEvents*)alloca(sz);
187 std::memset(events, 0, sz);
189 events->numEvents = 32;
191 VstMidiEvent ev[64] = {};
192 memset(&ev, 0,
sizeof(ev));
195 for(
int i = 0; i < 16; i++)
198 e.type = kVstMidiType;
199 e.flags = kVstMidiEventIsRealtime;
200 e.byteSize =
sizeof(VstMidiEvent);
202 e.midiData[0] = (char)(uint8_t)176 + i;
203 e.midiData[1] = (char)(uint8_t)123;
207 events->events[i] =
reinterpret_cast<VstEvent*
>(&e);
211 for(
int i = 0; i < 16; i++)
213 auto& e = ev[16 + i];
214 e.type = kVstMidiType;
215 e.flags = kVstMidiEventIsRealtime;
216 e.byteSize =
sizeof(VstMidiEvent);
218 e.midiData[0] = (char)(uint8_t)176 + i;
219 e.midiData[1] = (char)(uint8_t)121;
223 events->events[16 + i] =
reinterpret_cast<VstEvent*
>(&e);
226 dispatch(effProcessEvents, 0, 0, events, 0.f);
228 if constexpr(!UseDouble)
230 float* dummy = (
float*)alloca(
sizeof(
float) * m_bs);
231 std::fill_n(dummy, m_bs, 0.f);
234 = (
float**)alloca(
sizeof(
float*) * std::max(2, this->fx->fx->numInputs));
235 for(
int i = 0; i < this->fx->fx->numInputs; i++)
239 = (
float**)alloca(
sizeof(
float*) * std::max(2, this->fx->fx->numOutputs));
240 for(
int i = 0; i < this->fx->fx->numOutputs; i++)
243 fx->fx->processReplacing(fx->fx, input, output, m_bs);
247 double* dummy = (
double*)alloca(
sizeof(
double) * m_bs);
248 std::fill_n(dummy, m_bs, 0.);
251 = (
double**)alloca(
sizeof(
double*) * std::max(2, this->fx->fx->numInputs));
252 for(
int i = 0; i < this->fx->fx->numInputs; i++)
256 = (
double**)alloca(
sizeof(
double*) * std::max(2, this->fx->fx->numOutputs));
257 for(
int i = 0; i < this->fx->fx->numOutputs; i++)
260 fx->fx->processDoubleReplacing(fx->fx, input, output, m_bs);
268 template <
typename Fun>
269 void dispatchMidi(int64_t offset, Fun&& f)
272 auto& ip =
static_cast<ossia::midi_inlet*
>(m_inlets[1])->data.messages;
273 const auto n_mess = ip.size();
281 const auto sz =
sizeof(VstEvents) +
sizeof(
void*) * n_mess * 2;
282 VstEvents* events = (VstEvents*)alloca(sz);
283 std::memset(events, 0, sz);
284 events->numEvents = n_mess;
286 ossia::small_vector<VstMidiEvent, 16> vec;
289 for(libremidi::message& mess : ip)
291 VstMidiEvent& e = vec[i];
292 std::memset(&e, 0,
sizeof(VstMidiEvent));
294 e.type = kVstMidiType;
295 e.byteSize =
sizeof(VstMidiEvent);
296 e.deltaFrames = mess.timestamp - offset;
297 e.flags = kVstMidiEventIsRealtime;
300 e.midiData, mess.bytes.data(), std::min(mess.bytes.size(), (std::size_t)4));
305 events->events[i] =
reinterpret_cast<VstEvent*
>(&e);
308 dispatch(effProcessEvents, 0, 0, events, 0.f);
312 void run(
const ossia::token_request& tk, ossia::exec_state_facade st) noexcept
override
314 if(!muted() && tk.date > tk.prev_date)
316 const auto timings = st.timings(tk);
318 this->setupTimeInfo(tk, st);
320 if constexpr(UseDouble)
322 if constexpr(IsSynth)
324 dispatchMidi(timings.start_sample, [
this, timings] {
325 processDouble(timings.start_sample, timings.length);
330 processDouble(timings.start_sample, timings.length);
335 if constexpr(IsSynth)
337 dispatchMidi(timings.start_sample, [
this, timings] {
338 processFloat(timings.start_sample, timings.length);
343 processFloat(timings.start_sample, timings.length);
348 if(this->fx->fx->numOutputs == 1)
350 auto& op = m_outlets[0]->template target<ossia::audio_port>()->get();
351 op[1].assign(op[0].begin(), op[0].end());
356 void processFloat(int64_t offset, int64_t samples)
358 if constexpr(!UseDouble)
363 SCORE_ASSERT(m_bs >= offset + samples);
365 const auto max_i = std::max(2, this->fx->fx->numInputs);
366 const auto max_o = std::max(2, this->fx->fx->numOutputs);
367 const auto max_io = std::max(max_i, max_o);
369 const auto max_samples = std::max(samples, (int64_t)m_bs);
374 auto& ip = prepareInput(offset, samples);
375 SCORE_ASSERT(ip.size() >= 2);
377 auto& op = prepareOutput(offset, samples);
378 SCORE_ASSERT(op.size() >= 2);
381 float_v[0].resize(max_samples);
382 float_v[1].resize(max_samples);
384 std::copy_n(ip[0].data() + offset, samples, float_v[0].data());
385 std::copy_n(ip[1].data() + offset, samples, float_v[1].data());
387 float** io = (
float**)alloca(
sizeof(
float*) * max_io);
388 io[0] = float_v[0].data();
389 io[1] = float_v[1].data();
395 float* dummy = (
float*)alloca(
sizeof(
float) * max_samples);
396 std::fill_n(dummy, max_samples, 0.f);
398 for(
int i = 2; i < max_io; i++)
402 fx->fx->processReplacing(fx->fx, io, io, samples);
404 std::copy_n(float_v[0].data(), samples, op[0].data() + offset);
405 std::copy_n(float_v[1].data(), samples, op[1].data() + offset);
412 void processDouble(int64_t offset, int64_t samples)
414 if constexpr(UseDouble)
419 SCORE_ASSERT(m_bs >= offset + samples);
421 const auto max_i = std::max(2, this->fx->fx->numInputs);
422 const auto max_o = std::max(2, this->fx->fx->numOutputs);
423 const auto max_io = std::max(max_i, max_o);
426 auto& ip = prepareInput(offset, samples);
427 SCORE_ASSERT(ip.size() >= 2);
429 auto& op = prepareOutput(offset, samples);
430 SCORE_ASSERT(op.size() >= 2);
432 double** input = (
double**)alloca(
sizeof(
double*) * max_i);
433 input[0] = ip[0].data() + offset;
434 input[1] = ip[1].data() + offset;
436 double** output = (
double**)alloca(
sizeof(
double*) * max_o);
437 output[0] = op[0].data() + offset;
438 output[1] = op[1].data() + offset;
444 double* dummy = (
double*)alloca(
sizeof(
double) * m_bs);
445 std::fill_n(dummy, m_bs, 0.);
446 for(
int i = 2; i < this->fx->fx->numInputs; i++)
448 for(
int i = 2; i < this->fx->fx->numOutputs; i++)
452 fx->fx->processDoubleReplacing(fx->fx, input, output, samples);
459 std::conditional_t<!UseDouble, std::array<ossia::float_vector, 2>,
dummy_t> float_v;
462 template <
bool b1,
bool b2,
typename... Args>
463 auto make_vst_fx(Args&... args)
465 return ossia::make_node<vst_node<b1, b2>>(args...);
Definition: score-plugin-vst/Vst/Node.hpp:15
Definition: score-plugin-vst/Vst/Node.hpp:125
Definition: score-plugin-vst/Vst/Node.hpp:457
Definition: score-plugin-vst/Vst/Node.hpp:28