2 #include <ossia/dataflow/graph_node.hpp>
3 #include <ossia/dataflow/port.hpp>
6 #include <faust/gui/UI.h>
8 #include <faust/dsp/poly-llvm-dsp.h>
10 namespace ossia::nodes
14 struct faust_setup_ui : UI
16 faust_setup_ui(T&
self) { }
19 template <
typename Node,
bool Synth>
20 struct faust_exec_ui final : UI
23 faust_exec_ui(Node& n)
28 void addButton(
const char* label, FAUSTFLOAT* zone)
override
32 using namespace std::literals;
33 if(label ==
"Panic"sv || label ==
"gate"sv)
37 fx.root_inputs().push_back(
new ossia::value_inlet);
38 fx.controls.push_back(
39 {fx.root_inputs().back()->
template target<ossia::value_port>(), zone});
42 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
44 addButton(label, zone);
47 void addVerticalSlider(
48 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
49 FAUSTFLOAT
max, FAUSTFLOAT step)
override
53 using namespace std::literals;
54 if(label ==
"gain"sv || label ==
"freq"sv || label ==
"sustain"sv)
57 fx.root_inputs().push_back(
new ossia::value_inlet);
58 fx.controls.push_back(
59 {fx.root_inputs().back()->
template target<ossia::value_port>(), zone});
62 void addHorizontalSlider(
63 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
64 FAUSTFLOAT
max, FAUSTFLOAT step)
override
66 addVerticalSlider(label, zone, init,
min,
max, step);
70 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
71 FAUSTFLOAT
max, FAUSTFLOAT step)
override
73 addVerticalSlider(label, zone, init,
min,
max, step);
76 void addHorizontalBargraph(
77 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
79 fx.root_outputs().push_back(
new ossia::value_outlet);
80 fx.displays.push_back(
81 {fx.root_outputs().back()->
template target<ossia::value_port>(), zone});
84 void addVerticalBargraph(
85 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
87 addHorizontalBargraph(label, zone,
min,
max);
90 void openTabBox(
const char* label)
override { }
91 void openHorizontalBox(
const char* label)
override { }
92 void openVerticalBox(
const char* label)
override { }
93 void closeBox()
override { }
94 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
96 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
101 template <
typename Clone>
102 struct faust_exec_ui_clone final : UI
107 faust_exec_ui_clone(Clone& s)
112 void addButton(
const char* label, FAUSTFLOAT* zone)
override
114 *zone = *
self.controls[i].second;
115 self.controls[i++].second = zone;
118 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
120 addButton(label, zone);
123 void addVerticalSlider(
124 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
125 FAUSTFLOAT
max, FAUSTFLOAT step)
override
127 *zone = *
self.controls[i].second;
128 self.controls[i++].second = zone;
131 void addHorizontalSlider(
132 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
133 FAUSTFLOAT
max, FAUSTFLOAT step)
override
135 addVerticalSlider(label, zone, init,
min,
max, step);
139 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
140 FAUSTFLOAT
max, FAUSTFLOAT step)
override
142 addVerticalSlider(label, zone, init,
min,
max, step);
145 void addHorizontalBargraph(
146 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
148 self.displays[o++].second = zone;
151 void addVerticalBargraph(
152 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
154 addHorizontalBargraph(label, zone,
min,
max);
157 void openTabBox(
const char* label)
override { }
158 void openHorizontalBox(
const char* label)
override { }
159 void openVerticalBox(
const char* label)
override { }
160 void closeBox()
override { }
161 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
163 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
168 struct faust_node_utils
170 template <
typename Node>
171 static void copy_controls(Node&
self)
173 for(
auto ctrl :
self.controls)
175 auto& dat = ctrl.first->get_data();
178 *ctrl.second = ossia::convert<float>(dat.back().value);
183 template <
typename Node>
184 static void copy_displays(Node&
self, int64_t ts)
186 for(
auto ctrl :
self.displays)
188 ctrl.first->write_value(*ctrl.second, ts);
192 template <
typename Node>
193 static void copy_input(
194 Node&
self, int64_t d, int64_t n_in,
float* inputs_,
float** input_n,
195 const ossia::audio_port& audio_in)
198 for(int64_t i = 0; i < n_in; i++)
200 input_n[i] = inputs_ + i * d;
201 if(int64_t(audio_in.channels()) > i)
203 auto num_samples =
std::min((int64_t)d, (int64_t)audio_in.channel(i).size());
204 for(int64_t j = 0; j < num_samples; j++)
206 input_n[i][j] = (float)audio_in.channel(i)[j];
209 if(d > int64_t(audio_in.channel(i).size()))
211 for(int64_t j = audio_in.channel(i).size(); j < d; j++)
219 for(int64_t j = 0; j < d; j++)
226 template <
typename Node>
227 static void copy_input_mono(
228 Node&
self, int64_t d, int64_t i,
float* input,
229 const ossia::audio_channel& audio_in)
232 auto num_samples =
std::min((int64_t)d, (int64_t)audio_in.size());
233 for(int64_t j = 0; j < num_samples; j++)
235 input[j] = (float)audio_in[j];
238 if(d > int64_t(audio_in.size()))
240 for(int64_t j = audio_in.size(); j < d; j++)
247 template <
typename Node>
249 init_output(Node&
self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n)
251 for(int64_t i = 0; i < n_out; i++)
253 output_n[i] = outputs_ + i * d;
254 for(int64_t j = 0; j < d; j++)
256 output_n[i][j] = 0.f;
261 template <
typename Node>
262 static void copy_output(
263 Node&
self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n,
264 ossia::audio_port& audio_out)
266 audio_out.set_channels(n_out);
267 for(int64_t i = 0; i < n_out; i++)
269 audio_out.channel(i).resize(d);
270 for(int64_t j = 0; j < d; j++)
272 audio_out.channel(i)[j] = (double)output_n[i][j];
279 audio_out.set_channels(2);
280 audio_out.channel(1) = audio_out.channel(0);
284 template <
typename Node,
typename Dsp>
285 static void copy_midi(Node&
self, Dsp& dsp,
const ossia::midi_port& midi_in)
289 for(
const libremidi::message& mess : midi_in.messages)
291 switch(mess.get_message_type())
293 case libremidi::message_type::NOTE_ON: {
294 self.in_flight[mess[1]]++;
295 dsp.keyOn(mess[0], mess[1], mess[2]);
298 case libremidi::message_type::NOTE_OFF: {
299 self.in_flight[mess[1]]--;
300 dsp.keyOff(mess[0], mess[1], mess[2]);
303 case libremidi::message_type::CONTROL_CHANGE: {
304 dsp.ctrlChange(mess[0], mess[1], mess[2]);
307 case libremidi::message_type::PITCH_BEND: {
308 dsp.pitchWheel(mess[0], mess.bytes[2] * 128 + mess.bytes[1]);
318 template <
typename Node,
typename DspPoly>
319 void all_notes_off(Node&
self, DspPoly& dsp)
321 for(
int k = 0; k < 128; k++)
322 while(
self.in_flight[k]-- > 0)
328 template <
typename Node,
typename Dsp>
330 Node&
self, Dsp& dsp,
const ossia::token_request& tk,
331 const ossia::exec_state_facade& e)
333 const auto [st, d] = e.timings(tk);
334 ossia::audio_port& audio_in
335 =
self.root_inputs()[0]->template cast<ossia::audio_port>();
336 ossia::audio_port& audio_out
337 =
self.root_outputs()[0]->template cast<ossia::audio_port>();
339 const int64_t n_in = dsp.getNumInputs();
340 const int64_t n_out = dsp.getNumOutputs();
341 audio_in.set_channels(n_in);
342 audio_out.set_channels(n_out);
344 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
346 float* inputs_ = (
float*)alloca(n_in * d *
sizeof(
float));
347 float* outputs_ = (
float*)alloca(n_out * d *
sizeof(
float));
349 float** input_n = (
float**)alloca(
sizeof(
float*) * n_in);
350 float** output_n = (
float**)alloca(
sizeof(
float*) * n_out);
352 copy_input(
self, d, n_in, inputs_, input_n, audio_in);
353 init_output(
self, d, n_out, outputs_, output_n);
354 dsp.compute(d, input_n, output_n);
355 copy_output(
self, d, n_out, outputs_, output_n, audio_out);
359 double** input_n = (
double**)alloca(
sizeof(
double*) * n_in);
360 double** output_n = (
double**)alloca(
sizeof(
double*) * n_out);
361 for(
int i = 0; i < n_in; i++)
363 audio_in.channel(i).resize(e.bufferSize());
364 input_n[i] = audio_in.channel(i).data() + st;
366 if(BOOST_LIKELY(st == 0 && d == e.bufferSize()))
368 for(
int i = 0; i < n_out; i++)
370 audio_out.channel(i).resize(e.bufferSize(), boost::container::default_init);
371 output_n[i] = audio_out.channel(i).data() + st;
376 for(
int i = 0; i < n_out; i++)
378 audio_out.channel(i).resize(e.bufferSize());
379 output_n[i] = audio_out.channel(i).data() + st;
383 dsp.compute(d, input_n, output_n);
387 template <
typename Node,
typename Dsp>
389 Node&
self, Dsp& dsp,
const ossia::token_request& tk,
390 const ossia::exec_state_facade& e)
394 const auto [st, d] = e.timings(tk);
399 do_exec(
self, dsp, tk, e);
400 copy_displays(
self, st);
404 template <
typename Node,
typename Dsp>
405 static void do_exec_mono_fx(
406 Node&
self, Dsp& dsp,
const ossia::token_request& tk,
407 const ossia::exec_state_facade& e)
409 const auto [st, d] = e.timings(tk);
413 ossia::audio_port& audio_in
414 =
self.root_inputs()[0]->template cast<ossia::audio_port>();
415 ossia::audio_port& audio_out
416 =
self.root_outputs()[0]->template cast<ossia::audio_port>();
418 const int64_t n_in = audio_in.channels();
419 audio_out.set_channels(n_in);
420 while(
self.clones.size() < n_in)
422 self.clones.emplace_back(dsp.clone(),
self.clones[0]);
426 for(
int k = 0; k <
self.controls.size(); ++k)
428 auto ctrl =
self.controls[k];
429 auto& dat = ctrl.first->get_data();
432 float v = ossia::convert<float>(dat.back().value);
433 self.set_control(k, v);
438 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
440 float* input = (
float*)alloca(d *
sizeof(
float));
441 memset(input, 0, d *
sizeof(
float));
442 float* output = (
float*)alloca(d *
sizeof(
float));
444 for(
int i = 0; i < n_in; i++)
446 auto& in_chan = audio_in.channel(i);
447 auto& out_chan = audio_out.channel(i);
448 auto& clone =
self.clones[i];
449 in_chan.resize(e.bufferSize());
450 out_chan.resize(e.bufferSize());
452 copy_input_mono(
self, d, n_in, input, in_chan);
453 memset(output, 0, d *
sizeof(
float));
454 for(
int z = 0; z < d; z++)
456 assert(!std::isnan(input[z]));
457 assert(!std::isinf(input[z]));
459 clone.fx->compute(d, &input, &output);
460 for(
int z = 0; z < d; z++)
462 if(std::fpclassify(output[z]) != FP_NORMAL)
466 std::copy_n(output, d, out_chan.data() + st);
467 for(
int z = 0; z < e.bufferSize(); z++)
469 assert(!std::isnan(out_chan[z]));
470 assert(!std::isinf(out_chan[z]));
476 for(
int i = 0; i < n_in; i++)
478 auto& in_chan = audio_in.channel(i);
479 auto& out_chan = audio_out.channel(i);
480 in_chan.resize(e.bufferSize());
481 out_chan.resize(e.bufferSize());
483 double* input = in_chan.data() + st;
484 double* output = out_chan.data() + st;
486 self.clones[i].fx->compute(d, &input, &output);
491 template <
typename Node,
typename Dsp>
492 static void exec_mono_fx(
493 Node&
self, Dsp& dsp,
const ossia::token_request& tk,
494 const ossia::exec_state_facade& e)
498 const auto [st, d] = e.timings(tk);
502 do_exec_mono_fx(
self, dsp, tk, e);
503 copy_displays(
self, st);
508 template <
typename Node,
typename DspPoly>
510 Node&
self, DspPoly& dsp,
const ossia::token_request& tk,
511 const ossia::exec_state_facade& e)
515 const auto [st, d] = e.timings(tk);
517 auto& midi_in =
self.root_inputs()[1]->template cast<ossia::midi_port>();
520 dsp.updateAllZones();
521 copy_midi(
self, dsp, midi_in);
525 do_exec(
self, dsp, tk, e);
526 copy_displays(
self, st);
537 class custom_dsp_poly_effect :
public dsp_poly
541 mydsp_poly* fPolyDSP;
544 custom_dsp_poly_effect(mydsp_poly* dsp1, dsp* dsp2)
550 virtual ~custom_dsp_poly_effect()
555 void updateAllZones() { fPolyDSP->fGroups.updateAllZones(); }
557 MapUI* keyOn(
int channel,
int pitch,
int velocity)
559 return fPolyDSP->keyOn(channel, pitch, velocity);
561 void keyOff(
int channel,
int pitch,
int velocity)
563 fPolyDSP->keyOff(channel, pitch, velocity);
565 void keyPress(
int channel,
int pitch,
int press)
567 fPolyDSP->keyPress(channel, pitch, press);
569 void chanPress(
int channel,
int press) { fPolyDSP->chanPress(channel, press); }
570 void ctrlChange(
int channel,
int ctrl,
int value)
572 fPolyDSP->ctrlChange(channel, ctrl, value);
574 void ctrlChange14bits(
int channel,
int ctrl,
int value)
576 fPolyDSP->ctrlChange14bits(channel, ctrl, value);
578 void pitchWheel(
int channel,
int wheel) { fPolyDSP->pitchWheel(channel, wheel); }
579 void progChange(
int channel,
int pgm) { fPolyDSP->progChange(channel, pgm); }
582 struct custom_dsp_poly_factory :
public dsp_factory
584 dsp_factory* fProcessFactory;
585 dsp_factory* fEffectFactory;
587 std::vector<std::string> getWarningMessages() {
return {}; }
589 std::string getEffectCode(
const std::string& dsp_content)
591 std::stringstream effect_code;
592 effect_code <<
"adapt(1,1) = _; adapt(2,2) = _,_; adapt(1,2) = _ <: _,_; "
593 "adapt(2,1) = _,_ :> _;";
594 effect_code <<
"adaptor(F,G) = adapt(outputs(F),inputs(G)); dsp_code = "
596 << dsp_content <<
" };";
597 effect_code <<
"process = adaptor(dsp_code.process, dsp_code.effect) : "
599 return effect_code.str();
602 custom_dsp_poly_factory(
603 dsp_factory* process_factory = NULL, dsp_factory* effect_factory = NULL)
604 : fProcessFactory(process_factory)
605 , fEffectFactory(effect_factory)
609 virtual ~custom_dsp_poly_factory() =
default;
611 virtual std::string getName() {
return fProcessFactory->getName(); }
612 virtual std::string getSHAKey() {
return fProcessFactory->getSHAKey(); }
613 virtual std::string getDSPCode() {
return fProcessFactory->getDSPCode(); }
614 virtual std::string getCompileOptions()
616 return fProcessFactory->getCompileOptions();
618 virtual std::vector<std::string> getLibraryList()
620 return fProcessFactory->getLibraryList();
622 virtual std::vector<std::string> getIncludePathnames()
624 return fProcessFactory->getIncludePathnames();
627 virtual void setMemoryManager(dsp_memory_manager* manager)
629 fProcessFactory->setMemoryManager(manager);
632 fEffectFactory->setMemoryManager(manager);
635 virtual dsp_memory_manager* getMemoryManager()
637 return fProcessFactory->getMemoryManager();
652 custom_dsp_poly_effect* createPolyDSPInstance(
int nvoices,
bool control,
bool group)
655 =
new mydsp_poly(fProcessFactory->createDSPInstance(), nvoices, control, group);
660 return new custom_dsp_poly_effect(
661 dsp_poly,
new dsp_sequencer(dsp_poly, fEffectFactory->createDSPInstance()));
665 return new custom_dsp_poly_effect(dsp_poly, dsp_poly);
670 dsp* createDSPInstance() {
return fProcessFactory->createDSPInstance(); }
672 struct custom_llvm_dsp_poly_factory :
public custom_dsp_poly_factory
674 custom_llvm_dsp_poly_factory(
675 const std::string& name_app,
const std::string& dsp_content,
int argc,
676 const char* argv[],
const std::string& target, std::string& error_msg,
679 fProcessFactory = createDSPFactoryFromString(
680 name_app, dsp_content, argc, argv, target, error_msg);
683 fEffectFactory = createDSPFactoryFromString(
684 name_app, getEffectCode(dsp_content), argc, argv, target, error_msg);
687 std::cerr <<
"llvm_dsp_poly_factory : fEffectFactory " << error_msg;
694 std::cerr <<
"llvm_dsp_poly_factory : fProcessFactory " << error_msg;
695 throw std::bad_alloc();
699 virtual ~custom_llvm_dsp_poly_factory()
701 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fProcessFactory));
702 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fEffectFactory));
706 static custom_llvm_dsp_poly_factory* createCustomPolyDSPFactoryFromString(
707 const std::string& name_app,
const std::string& dsp_content,
int argc,
708 const char* argv[],
const std::string& target, std::string& error_msg,
713 return new custom_llvm_dsp_poly_factory(
714 name_app, dsp_content, argc, argv, target, error_msg, opt_level);
constexpr OSSIA_INLINE auto min(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
min function tailored for values
Definition: math.hpp:125
constexpr OSSIA_INLINE auto max(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
max function tailored for values
Definition: math.hpp:96