2#include <ossia/dataflow/graph_node.hpp>
3#include <ossia/dataflow/port.hpp>
6#include <faust/gui/UI.h>
7#include <libremidi/message.hpp>
8#include <libremidi/ump_events.hpp>
12#include <faust/dsp/poly-llvm-dsp.h>
18struct faust_setup_ui : UI
20 faust_setup_ui(T& self) { }
23template <
typename Node,
bool Synth>
24struct faust_exec_ui final : UI
27 faust_exec_ui(Node& n)
32 void addButton(
const char* label, FAUSTFLOAT* zone)
override
36 using namespace std::literals;
37 if(label ==
"Panic"sv || label ==
"gate"sv)
41 fx.root_inputs().push_back(
new ossia::value_inlet);
42 fx.controls.push_back(
43 {fx.root_inputs().back()->template target<ossia::value_port>(), zone});
46 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
48 addButton(label, zone);
51 void addVerticalSlider(
52 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
53 FAUSTFLOAT
max, FAUSTFLOAT step)
override
57 using namespace std::literals;
58 if(label ==
"gain"sv || label ==
"freq"sv || label ==
"sustain"sv)
61 fx.root_inputs().push_back(
new ossia::value_inlet);
62 fx.controls.push_back(
63 {fx.root_inputs().back()->template target<ossia::value_port>(), zone});
66 void addHorizontalSlider(
67 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
68 FAUSTFLOAT
max, FAUSTFLOAT step)
override
70 addVerticalSlider(label, zone, init,
min,
max, step);
74 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
75 FAUSTFLOAT
max, FAUSTFLOAT step)
override
77 addVerticalSlider(label, zone, init,
min,
max, step);
80 void addHorizontalBargraph(
81 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
83 fx.root_outputs().push_back(
new ossia::value_outlet);
84 fx.displays.push_back(
85 {fx.root_outputs().back()->
template target<ossia::value_port>(), zone});
88 void addVerticalBargraph(
89 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
91 addHorizontalBargraph(label, zone,
min,
max);
94 void openTabBox(
const char* label)
override { }
95 void openHorizontalBox(
const char* label)
override { }
96 void openVerticalBox(
const char* label)
override { }
97 void closeBox()
override { }
98 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
100 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
105template <
typename Clone>
106struct faust_exec_ui_clone final : ::UI
111 faust_exec_ui_clone(Clone& s)
116 void addButton(
const char* label, FAUSTFLOAT* zone)
override
118 *zone = *self.controls[i].second;
119 self.controls[i++].second = zone;
122 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
124 addButton(label, zone);
127 void addVerticalSlider(
128 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
129 FAUSTFLOAT
max, FAUSTFLOAT step)
override
131 *zone = *self.controls[i].second;
132 self.controls[i++].second = zone;
135 void addHorizontalSlider(
136 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
137 FAUSTFLOAT
max, FAUSTFLOAT step)
override
139 addVerticalSlider(label, zone, init,
min,
max, step);
143 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
144 FAUSTFLOAT
max, FAUSTFLOAT step)
override
146 addVerticalSlider(label, zone, init,
min,
max, step);
149 void addHorizontalBargraph(
150 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
152 self.displays[o++].second = zone;
155 void addVerticalBargraph(
156 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
158 addHorizontalBargraph(label, zone,
min,
max);
161 void openTabBox(
const char* label)
override { }
162 void openHorizontalBox(
const char* label)
override { }
163 void openVerticalBox(
const char* label)
override { }
164 void closeBox()
override { }
165 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
167 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
172struct faust_node_utils
174 template <
typename Node>
175 static void copy_controls(Node& self)
177 for(
auto ctrl : self.controls)
179 auto& dat = ctrl.first->get_data();
182 *ctrl.second = ossia::convert<float>(dat.back().value);
187 template <
typename Node>
188 static void copy_displays(Node& self, int64_t ts)
190 for(
auto ctrl : self.displays)
192 ctrl.first->write_value(*ctrl.second, ts);
196 template <
typename Node>
197 static void copy_input(
198 Node& self, int64_t d, int64_t n_in,
float* inputs_,
float** input_n,
199 const ossia::audio_port& audio_in)
202 for(int64_t i = 0; i < n_in; i++)
204 input_n[i] = inputs_ + i * d;
205 if(int64_t(audio_in.channels()) > i)
207 auto num_samples = std::min((int64_t)d, (int64_t)audio_in.channel(i).size());
208 for(int64_t j = 0; j < num_samples; j++)
210 input_n[i][j] = (float)audio_in.channel(i)[j];
213 if(d > int64_t(audio_in.channel(i).size()))
215 for(int64_t j = audio_in.channel(i).size(); j < d; j++)
223 for(int64_t j = 0; j < d; j++)
230 template <
typename Node>
231 static void copy_input_mono(
232 Node& self, int64_t d, int64_t i,
float* input,
233 const ossia::audio_channel& audio_in)
236 auto num_samples = std::min((int64_t)d, (int64_t)audio_in.size());
237 for(int64_t j = 0; j < num_samples; j++)
239 input[j] = (float)audio_in[j];
242 if(d > int64_t(audio_in.size()))
244 for(int64_t j = audio_in.size(); j < d; j++)
251 template <
typename Node>
253 init_output(Node& self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n)
255 for(int64_t i = 0; i < n_out; i++)
257 output_n[i] = outputs_ + i * d;
258 for(int64_t j = 0; j < d; j++)
260 output_n[i][j] = 0.f;
265 template <
typename Node>
266 static void copy_output(
267 Node& self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n,
268 ossia::audio_port& audio_out)
270 audio_out.set_channels(n_out);
271 for(int64_t i = 0; i < n_out; i++)
273 audio_out.channel(i).resize(d);
274 for(int64_t j = 0; j < d; j++)
276 audio_out.channel(i)[j] = (double)output_n[i][j];
283 audio_out.set_channels(2);
284 audio_out.channel(1) = audio_out.channel(0);
288 template <
typename Node,
typename Dsp>
289 static void copy_midi(Node& self, Dsp& dsp,
const ossia::midi_port& midi_in)
293 for(
const libremidi::ump& mess : midi_in.messages)
295 if(mess.get_type() != libremidi::midi2::message_type::MIDI_2_CHANNEL)
298 switch(libremidi::message_type(mess.get_status_code()))
300 case libremidi::message_type::NOTE_ON: {
301 auto [channel, note, value] = libremidi::as_midi1::note_on(mess);
302 self.in_flight[note]++;
303 dsp.keyOn(channel, note, value);
306 case libremidi::message_type::NOTE_OFF: {
307 auto [channel, note, value] = libremidi::as_midi1::note_off(mess);
308 self.in_flight[note]--;
309 dsp.keyOff(channel, note, value);
312 case libremidi::message_type::CONTROL_CHANGE: {
313 auto [channel, index, value] = libremidi::as_midi1::control_change(mess);
314 dsp.ctrlChange(channel, index, value);
317 case libremidi::message_type::PITCH_BEND: {
318 auto [channel, value] = libremidi::as_midi1::pitch_bend(mess);
319 dsp.pitchWheel(channel, value);
329 template <
typename Node,
typename DspPoly>
330 void all_notes_off(Node& self, DspPoly& dsp)
332 for(
int k = 0; k < 128; k++)
333 while(self.in_flight[k]-- > 0)
339 template <
typename Node,
typename Dsp>
341 Node& self, Dsp& dsp,
const ossia::token_request& tk,
342 const ossia::exec_state_facade& e)
344 const auto [st, d] = e.timings(tk);
345 ossia::audio_port& audio_in
346 = self.root_inputs()[0]->template cast<ossia::audio_port>();
347 ossia::audio_port& audio_out
348 = self.root_outputs()[0]->template cast<ossia::audio_port>();
350 const int64_t n_in = dsp.getNumInputs();
351 const int64_t n_out = dsp.getNumOutputs();
352 audio_in.set_channels(n_in);
353 audio_out.set_channels(n_out);
355 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
357 float* inputs_ = (
float*)alloca(n_in * d *
sizeof(
float));
358 float* outputs_ = (
float*)alloca(n_out * d *
sizeof(
float));
360 float** input_n = (
float**)alloca(
sizeof(
float*) * n_in);
361 float** output_n = (
float**)alloca(
sizeof(
float*) * n_out);
363 copy_input(self, d, n_in, inputs_, input_n, audio_in);
364 init_output(self, d, n_out, outputs_, output_n);
365 dsp.compute(d, input_n, output_n);
366 copy_output(self, d, n_out, outputs_, output_n, audio_out);
370 double** input_n = (
double**)alloca(
sizeof(
double*) * n_in);
371 double** output_n = (
double**)alloca(
sizeof(
double*) * n_out);
372 for(
int i = 0; i < n_in; i++)
374 audio_in.channel(i).resize(e.bufferSize());
375 input_n[i] = audio_in.channel(i).data() + st;
377 if(BOOST_LIKELY(st == 0 && d == e.bufferSize()))
379 for(
int i = 0; i < n_out; i++)
381 audio_out.channel(i).resize(e.bufferSize(), boost::container::default_init);
382 output_n[i] = audio_out.channel(i).data() + st;
387 for(
int i = 0; i < n_out; i++)
389 audio_out.channel(i).resize(e.bufferSize());
390 output_n[i] = audio_out.channel(i).data() + st;
394 dsp.compute(d, input_n, output_n);
398 template <
typename Node,
typename Dsp>
400 Node& self, Dsp& dsp,
const ossia::token_request& tk,
401 const ossia::exec_state_facade& e)
405 const auto [st, d] = e.timings(tk);
410 do_exec(self, dsp, tk, e);
411 copy_displays(self, st);
415 template <
typename Node,
typename Dsp>
416 static void do_exec_mono_fx(
417 Node& self, Dsp& dsp,
const ossia::token_request& tk,
418 const ossia::exec_state_facade& e)
420 const auto [st, d] = e.timings(tk);
424 ossia::audio_port& audio_in
425 = self.root_inputs()[0]->template cast<ossia::audio_port>();
426 ossia::audio_port& audio_out
427 = self.root_outputs()[0]->template cast<ossia::audio_port>();
429 const int64_t n_in = audio_in.channels();
430 audio_out.set_channels(n_in);
431 while(self.clones.size() < n_in)
433 self.clones.emplace_back(dsp.clone(), self.clones[0]);
437 for(
int k = 0; k < self.controls.size(); ++k)
439 auto ctrl = self.controls[k];
440 auto& dat = ctrl.first->get_data();
443 if(dat.back().value.valid())
444 ossia::apply_nonnull([k,&self] (
const auto& vv){ self.set_control(k, vv); }, dat.back().value.v);
449 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
451 float* input = (
float*)alloca(d *
sizeof(
float));
452 memset(input, 0, d *
sizeof(
float));
453 float* output = (
float*)alloca(d *
sizeof(
float));
455 for(
int i = 0; i < n_in; i++)
457 auto& in_chan = audio_in.channel(i);
458 auto& out_chan = audio_out.channel(i);
459 auto& clone = self.clones[i];
460 in_chan.resize(e.bufferSize());
461 out_chan.resize(e.bufferSize());
463 copy_input_mono(self, d, n_in, input, in_chan);
464 memset(output, 0, d *
sizeof(
float));
465 for(
int z = 0; z < d; z++)
467 assert(!std::isnan(input[z]));
468 assert(!std::isinf(input[z]));
470 clone.fx->compute(d, &input, &output);
471 for(
int z = 0; z < d; z++)
473 if(std::fpclassify(output[z]) != FP_NORMAL)
477 std::copy_n(output, d, out_chan.data() + st);
478 for(
int z = 0; z < e.bufferSize(); z++)
480 assert(!std::isnan(out_chan[z]));
481 assert(!std::isinf(out_chan[z]));
487 for(
int i = 0; i < n_in; i++)
489 auto& in_chan = audio_in.channel(i);
490 auto& out_chan = audio_out.channel(i);
491 in_chan.resize(e.bufferSize());
492 out_chan.resize(e.bufferSize());
494 double* input = in_chan.data() + st;
495 double* output = out_chan.data() + st;
497 self.clones[i].fx->compute(d, &input, &output);
502 template <
typename Node,
typename Dsp>
503 static void exec_mono_fx(
504 Node& self, Dsp& dsp,
const ossia::token_request& tk,
505 const ossia::exec_state_facade& e)
509 const auto [st, d] = e.timings(tk);
513 do_exec_mono_fx(self, dsp, tk, e);
514 copy_displays(self, st);
519 template <
typename Node,
typename DspPoly>
521 Node& self, DspPoly& dsp,
const ossia::token_request& tk,
522 const ossia::exec_state_facade& e)
526 const auto [st, d] = e.timings(tk);
528 auto& midi_in = self.root_inputs()[1]->template cast<ossia::midi_port>();
531 dsp.updateAllZones();
532 copy_midi(self, dsp, midi_in);
536 do_exec(self, dsp, tk, e);
537 copy_displays(self, st);
548class custom_dsp_poly_effect :
public dsp_poly
552 mydsp_poly* fPolyDSP;
555 custom_dsp_poly_effect(mydsp_poly* dsp1, dsp* dsp2)
561 virtual ~custom_dsp_poly_effect()
566 void updateAllZones() { fPolyDSP->fGroups.updateAllZones(); }
568 MapUI* keyOn(
int channel,
int pitch,
int velocity)
570 return fPolyDSP->keyOn(channel, pitch, velocity);
572 void keyOff(
int channel,
int pitch,
int velocity)
574 fPolyDSP->keyOff(channel, pitch, velocity);
576 void keyPress(
int channel,
int pitch,
int press)
578 fPolyDSP->keyPress(channel, pitch, press);
580 void chanPress(
int channel,
int press) { fPolyDSP->chanPress(channel, press); }
581 void ctrlChange(
int channel,
int ctrl,
int value)
583 fPolyDSP->ctrlChange(channel, ctrl, value);
585 void ctrlChange14bits(
int channel,
int ctrl,
int value)
587 fPolyDSP->ctrlChange14bits(channel, ctrl, value);
589 void pitchWheel(
int channel,
int wheel) { fPolyDSP->pitchWheel(channel, wheel); }
590 void progChange(
int channel,
int pgm) { fPolyDSP->progChange(channel, pgm); }
593struct custom_dsp_poly_factory :
public dsp_factory
595 dsp_factory* fProcessFactory;
596 dsp_factory* fEffectFactory;
598 std::vector<std::string> getWarningMessages() {
return {}; }
600 std::string getEffectCode(
const std::string& dsp_content)
602 std::stringstream effect_code;
603 effect_code <<
"adapt(1,1) = _; adapt(2,2) = _,_; adapt(1,2) = _ <: _,_; "
604 "adapt(2,1) = _,_ :> _;";
605 effect_code <<
"adaptor(F,G) = adapt(outputs(F),inputs(G)); dsp_code = "
607 << dsp_content <<
" };";
608 effect_code <<
"process = adaptor(dsp_code.process, dsp_code.effect) : "
610 return effect_code.str();
613 custom_dsp_poly_factory(
614 dsp_factory* process_factory = NULL, dsp_factory* effect_factory = NULL)
615 : fProcessFactory(process_factory)
616 , fEffectFactory(effect_factory)
620 virtual ~custom_dsp_poly_factory() =
default;
622 virtual std::string getJSON()
628 return [](
auto ptr) -> std::string {
629 if constexpr(
requires { ptr->getJSON(); })
630 return ptr->getJSON();
636 virtual std::string getName() {
return fProcessFactory->getName(); }
637 virtual std::string getSHAKey() {
return fProcessFactory->getSHAKey(); }
638 virtual std::string getDSPCode() {
return fProcessFactory->getDSPCode(); }
639 virtual std::string getCompileOptions()
641 return fProcessFactory->getCompileOptions();
643 virtual std::vector<std::string> getLibraryList()
645 return fProcessFactory->getLibraryList();
647 virtual std::vector<std::string> getIncludePathnames()
649 return fProcessFactory->getIncludePathnames();
652 virtual void setMemoryManager(dsp_memory_manager* manager)
654 fProcessFactory->setMemoryManager(manager);
657 fEffectFactory->setMemoryManager(manager);
660 virtual dsp_memory_manager* getMemoryManager()
662 return fProcessFactory->getMemoryManager();
677 custom_dsp_poly_effect* createPolyDSPInstance(
int nvoices,
bool control,
bool group)
680 =
new mydsp_poly(fProcessFactory->createDSPInstance(), nvoices, control, group);
685 return new custom_dsp_poly_effect(
686 dsp_poly,
new dsp_sequencer(dsp_poly, fEffectFactory->createDSPInstance()));
690 return new custom_dsp_poly_effect(dsp_poly, dsp_poly);
695 dsp* createDSPInstance() {
return fProcessFactory->createDSPInstance(); }
697struct custom_llvm_dsp_poly_factory :
public custom_dsp_poly_factory
699 custom_llvm_dsp_poly_factory(
700 const std::string& name_app,
const std::string& dsp_content,
int argc,
701 const char* argv[],
const std::string& target, std::string& error_msg,
704 fProcessFactory = createDSPFactoryFromString(
705 name_app, dsp_content, argc, argv, target, error_msg);
708 fEffectFactory = createDSPFactoryFromString(
709 name_app, getEffectCode(dsp_content), argc, argv, target, error_msg);
712 std::cerr <<
"llvm_dsp_poly_factory : fEffectFactory " << error_msg;
719 std::cerr <<
"llvm_dsp_poly_factory : fProcessFactory " << error_msg;
720 throw std::bad_alloc();
724 virtual ~custom_llvm_dsp_poly_factory()
726 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fProcessFactory));
727 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fEffectFactory));
731static custom_llvm_dsp_poly_factory* createCustomPolyDSPFactoryFromString(
732 const std::string& name_app,
const std::string& dsp_content,
int argc,
733 const char* argv[],
const std::string& target, std::string& error_msg,
738 return new custom_llvm_dsp_poly_factory(
739 name_app, dsp_content, argc, argv, target, error_msg, opt_level);
OSSIA_INLINE constexpr 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
OSSIA_INLINE constexpr 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