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>
10#include <faust/dsp/poly-llvm-dsp.h>
16struct faust_setup_ui : UI
18 faust_setup_ui(T& self) { }
21template <
typename Node,
bool Synth>
22struct faust_exec_ui final : UI
25 faust_exec_ui(Node& n)
30 void addButton(
const char* label, FAUSTFLOAT* zone)
override
34 using namespace std::literals;
35 if(label ==
"Panic"sv || label ==
"gate"sv)
39 fx.root_inputs().push_back(
new ossia::value_inlet);
40 fx.controls.push_back(
41 {fx.root_inputs().back()->template target<ossia::value_port>(), zone});
44 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
46 addButton(label, zone);
49 void addVerticalSlider(
50 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
51 FAUSTFLOAT
max, FAUSTFLOAT step)
override
55 using namespace std::literals;
56 if(label ==
"gain"sv || label ==
"freq"sv || label ==
"sustain"sv)
59 fx.root_inputs().push_back(
new ossia::value_inlet);
60 fx.controls.push_back(
61 {fx.root_inputs().back()->template target<ossia::value_port>(), zone});
64 void addHorizontalSlider(
65 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
66 FAUSTFLOAT
max, FAUSTFLOAT step)
override
68 addVerticalSlider(label, zone, init,
min,
max, step);
72 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
73 FAUSTFLOAT
max, FAUSTFLOAT step)
override
75 addVerticalSlider(label, zone, init,
min,
max, step);
78 void addHorizontalBargraph(
79 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
81 fx.root_outputs().push_back(
new ossia::value_outlet);
82 fx.displays.push_back(
83 {fx.root_outputs().back()->
template target<ossia::value_port>(), zone});
86 void addVerticalBargraph(
87 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
89 addHorizontalBargraph(label, zone,
min,
max);
92 void openTabBox(
const char* label)
override { }
93 void openHorizontalBox(
const char* label)
override { }
94 void openVerticalBox(
const char* label)
override { }
95 void closeBox()
override { }
96 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
98 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
103template <
typename Clone>
104struct faust_exec_ui_clone final : ::UI
109 faust_exec_ui_clone(Clone& s)
114 void addButton(
const char* label, FAUSTFLOAT* zone)
override
116 *zone = *self.controls[i].second;
117 self.controls[i++].second = zone;
120 void addCheckButton(
const char* label, FAUSTFLOAT* zone)
override
122 addButton(label, zone);
125 void addVerticalSlider(
126 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
127 FAUSTFLOAT
max, FAUSTFLOAT step)
override
129 *zone = *self.controls[i].second;
130 self.controls[i++].second = zone;
133 void addHorizontalSlider(
134 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
135 FAUSTFLOAT
max, FAUSTFLOAT step)
override
137 addVerticalSlider(label, zone, init,
min,
max, step);
141 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT
min,
142 FAUSTFLOAT
max, FAUSTFLOAT step)
override
144 addVerticalSlider(label, zone, init,
min,
max, step);
147 void addHorizontalBargraph(
148 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
150 self.displays[o++].second = zone;
153 void addVerticalBargraph(
154 const char* label, FAUSTFLOAT* zone, FAUSTFLOAT
min, FAUSTFLOAT
max)
override
156 addHorizontalBargraph(label, zone,
min,
max);
159 void openTabBox(
const char* label)
override { }
160 void openHorizontalBox(
const char* label)
override { }
161 void openVerticalBox(
const char* label)
override { }
162 void closeBox()
override { }
163 void declare(FAUSTFLOAT* zone,
const char* key,
const char* val)
override { }
165 addSoundfile(
const char* label,
const char* filename, Soundfile** sf_zone)
override
170struct faust_node_utils
172 template <
typename Node>
173 static void copy_controls(Node& self)
175 for(
auto ctrl : self.controls)
177 auto& dat = ctrl.first->get_data();
180 *ctrl.second = ossia::convert<float>(dat.back().value);
185 template <
typename Node>
186 static void copy_displays(Node& self, int64_t ts)
188 for(
auto ctrl : self.displays)
190 ctrl.first->write_value(*ctrl.second, ts);
194 template <
typename Node>
195 static void copy_input(
196 Node& self, int64_t d, int64_t n_in,
float* inputs_,
float** input_n,
197 const ossia::audio_port& audio_in)
200 for(int64_t i = 0; i < n_in; i++)
202 input_n[i] = inputs_ + i * d;
203 if(int64_t(audio_in.channels()) > i)
205 auto num_samples = std::min((int64_t)d, (int64_t)audio_in.channel(i).size());
206 for(int64_t j = 0; j < num_samples; j++)
208 input_n[i][j] = (float)audio_in.channel(i)[j];
211 if(d > int64_t(audio_in.channel(i).size()))
213 for(int64_t j = audio_in.channel(i).size(); j < d; j++)
221 for(int64_t j = 0; j < d; j++)
228 template <
typename Node>
229 static void copy_input_mono(
230 Node& self, int64_t d, int64_t i,
float* input,
231 const ossia::audio_channel& audio_in)
234 auto num_samples = std::min((int64_t)d, (int64_t)audio_in.size());
235 for(int64_t j = 0; j < num_samples; j++)
237 input[j] = (float)audio_in[j];
240 if(d > int64_t(audio_in.size()))
242 for(int64_t j = audio_in.size(); j < d; j++)
249 template <
typename Node>
251 init_output(Node& self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n)
253 for(int64_t i = 0; i < n_out; i++)
255 output_n[i] = outputs_ + i * d;
256 for(int64_t j = 0; j < d; j++)
258 output_n[i][j] = 0.f;
263 template <
typename Node>
264 static void copy_output(
265 Node& self, int64_t d, int64_t n_out,
float* outputs_,
float** output_n,
266 ossia::audio_port& audio_out)
268 audio_out.set_channels(n_out);
269 for(int64_t i = 0; i < n_out; i++)
271 audio_out.channel(i).resize(d);
272 for(int64_t j = 0; j < d; j++)
274 audio_out.channel(i)[j] = (double)output_n[i][j];
281 audio_out.set_channels(2);
282 audio_out.channel(1) = audio_out.channel(0);
286 template <
typename Node,
typename Dsp>
287 static void copy_midi(Node& self, Dsp& dsp,
const ossia::midi_port& midi_in)
291 for(
const libremidi::ump& mess : midi_in.messages)
293 if(mess.get_type() != libremidi::midi2::message_type::MIDI_2_CHANNEL)
296 switch(libremidi::message_type(mess.get_status_code()))
298 case libremidi::message_type::NOTE_ON: {
299 auto [channel, note, value] = libremidi::as_midi1::note_on(mess);
300 self.in_flight[note]++;
301 dsp.keyOn(channel, note, value);
304 case libremidi::message_type::NOTE_OFF: {
305 auto [channel, note, value] = libremidi::as_midi1::note_off(mess);
306 self.in_flight[note]--;
307 dsp.keyOff(channel, note, value);
310 case libremidi::message_type::CONTROL_CHANGE: {
311 auto [channel, index, value] = libremidi::as_midi1::control_change(mess);
312 dsp.ctrlChange(channel, index, value);
315 case libremidi::message_type::PITCH_BEND: {
316 auto [channel, value] = libremidi::as_midi1::pitch_bend(mess);
317 dsp.pitchWheel(channel, value);
327 template <
typename Node,
typename DspPoly>
328 void all_notes_off(Node& self, DspPoly& dsp)
330 for(
int k = 0; k < 128; k++)
331 while(self.in_flight[k]-- > 0)
337 template <
typename Node,
typename Dsp>
339 Node& self, Dsp& dsp,
const ossia::token_request& tk,
340 const ossia::exec_state_facade& e)
342 const auto [st, d] = e.timings(tk);
343 ossia::audio_port& audio_in
344 = self.root_inputs()[0]->template cast<ossia::audio_port>();
345 ossia::audio_port& audio_out
346 = self.root_outputs()[0]->template cast<ossia::audio_port>();
348 const int64_t n_in = dsp.getNumInputs();
349 const int64_t n_out = dsp.getNumOutputs();
350 audio_in.set_channels(n_in);
351 audio_out.set_channels(n_out);
353 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
355 float* inputs_ = (
float*)alloca(n_in * d *
sizeof(
float));
356 float* outputs_ = (
float*)alloca(n_out * d *
sizeof(
float));
358 float** input_n = (
float**)alloca(
sizeof(
float*) * n_in);
359 float** output_n = (
float**)alloca(
sizeof(
float*) * n_out);
361 copy_input(self, d, n_in, inputs_, input_n, audio_in);
362 init_output(self, d, n_out, outputs_, output_n);
363 dsp.compute(d, input_n, output_n);
364 copy_output(self, d, n_out, outputs_, output_n, audio_out);
368 double** input_n = (
double**)alloca(
sizeof(
double*) * n_in);
369 double** output_n = (
double**)alloca(
sizeof(
double*) * n_out);
370 for(
int i = 0; i < n_in; i++)
372 audio_in.channel(i).resize(e.bufferSize());
373 input_n[i] = audio_in.channel(i).data() + st;
375 if(BOOST_LIKELY(st == 0 && d == e.bufferSize()))
377 for(
int i = 0; i < n_out; i++)
379 audio_out.channel(i).resize(e.bufferSize(), boost::container::default_init);
380 output_n[i] = audio_out.channel(i).data() + st;
385 for(
int i = 0; i < n_out; i++)
387 audio_out.channel(i).resize(e.bufferSize());
388 output_n[i] = audio_out.channel(i).data() + st;
392 dsp.compute(d, input_n, output_n);
396 template <
typename Node,
typename Dsp>
398 Node& self, Dsp& dsp,
const ossia::token_request& tk,
399 const ossia::exec_state_facade& e)
403 const auto [st, d] = e.timings(tk);
408 do_exec(self, dsp, tk, e);
409 copy_displays(self, st);
413 template <
typename Node,
typename Dsp>
414 static void do_exec_mono_fx(
415 Node& self, Dsp& dsp,
const ossia::token_request& tk,
416 const ossia::exec_state_facade& e)
418 const auto [st, d] = e.timings(tk);
422 ossia::audio_port& audio_in
423 = self.root_inputs()[0]->template cast<ossia::audio_port>();
424 ossia::audio_port& audio_out
425 = self.root_outputs()[0]->template cast<ossia::audio_port>();
427 const int64_t n_in = audio_in.channels();
428 audio_out.set_channels(n_in);
429 while(self.clones.size() < n_in)
431 self.clones.emplace_back(dsp.clone(), self.clones[0]);
435 for(
int k = 0; k < self.controls.size(); ++k)
437 auto ctrl = self.controls[k];
438 auto& dat = ctrl.first->get_data();
441 if(dat.back().value.valid())
442 ossia::apply_nonnull([k,&self] (
const auto& vv){ self.set_control(k, vv); }, dat.back().value.v);
447 if constexpr(std::is_same_v<FAUSTFLOAT, float>)
449 float* input = (
float*)alloca(d *
sizeof(
float));
450 memset(input, 0, d *
sizeof(
float));
451 float* output = (
float*)alloca(d *
sizeof(
float));
453 for(
int i = 0; i < n_in; i++)
455 auto& in_chan = audio_in.channel(i);
456 auto& out_chan = audio_out.channel(i);
457 auto& clone = self.clones[i];
458 in_chan.resize(e.bufferSize());
459 out_chan.resize(e.bufferSize());
461 copy_input_mono(self, d, n_in, input, in_chan);
462 memset(output, 0, d *
sizeof(
float));
463 for(
int z = 0; z < d; z++)
465 assert(!std::isnan(input[z]));
466 assert(!std::isinf(input[z]));
468 clone.fx->compute(d, &input, &output);
469 for(
int z = 0; z < d; z++)
471 if(std::fpclassify(output[z]) != FP_NORMAL)
475 std::copy_n(output, d, out_chan.data() + st);
476 for(
int z = 0; z < e.bufferSize(); z++)
478 assert(!std::isnan(out_chan[z]));
479 assert(!std::isinf(out_chan[z]));
485 for(
int i = 0; i < n_in; i++)
487 auto& in_chan = audio_in.channel(i);
488 auto& out_chan = audio_out.channel(i);
489 in_chan.resize(e.bufferSize());
490 out_chan.resize(e.bufferSize());
492 double* input = in_chan.data() + st;
493 double* output = out_chan.data() + st;
495 self.clones[i].fx->compute(d, &input, &output);
500 template <
typename Node,
typename Dsp>
501 static void exec_mono_fx(
502 Node& self, Dsp& dsp,
const ossia::token_request& tk,
503 const ossia::exec_state_facade& e)
507 const auto [st, d] = e.timings(tk);
511 do_exec_mono_fx(self, dsp, tk, e);
512 copy_displays(self, st);
517 template <
typename Node,
typename DspPoly>
519 Node& self, DspPoly& dsp,
const ossia::token_request& tk,
520 const ossia::exec_state_facade& e)
524 const auto [st, d] = e.timings(tk);
526 auto& midi_in = self.root_inputs()[1]->template cast<ossia::midi_port>();
529 dsp.updateAllZones();
530 copy_midi(self, dsp, midi_in);
534 do_exec(self, dsp, tk, e);
535 copy_displays(self, st);
546class custom_dsp_poly_effect :
public dsp_poly
550 mydsp_poly* fPolyDSP;
553 custom_dsp_poly_effect(mydsp_poly* dsp1, dsp* dsp2)
559 virtual ~custom_dsp_poly_effect()
564 void updateAllZones() { fPolyDSP->fGroups.updateAllZones(); }
566 MapUI* keyOn(
int channel,
int pitch,
int velocity)
568 return fPolyDSP->keyOn(channel, pitch, velocity);
570 void keyOff(
int channel,
int pitch,
int velocity)
572 fPolyDSP->keyOff(channel, pitch, velocity);
574 void keyPress(
int channel,
int pitch,
int press)
576 fPolyDSP->keyPress(channel, pitch, press);
578 void chanPress(
int channel,
int press) { fPolyDSP->chanPress(channel, press); }
579 void ctrlChange(
int channel,
int ctrl,
int value)
581 fPolyDSP->ctrlChange(channel, ctrl, value);
583 void ctrlChange14bits(
int channel,
int ctrl,
int value)
585 fPolyDSP->ctrlChange14bits(channel, ctrl, value);
587 void pitchWheel(
int channel,
int wheel) { fPolyDSP->pitchWheel(channel, wheel); }
588 void progChange(
int channel,
int pgm) { fPolyDSP->progChange(channel, pgm); }
591struct custom_dsp_poly_factory :
public dsp_factory
593 dsp_factory* fProcessFactory;
594 dsp_factory* fEffectFactory;
596 std::vector<std::string> getWarningMessages() {
return {}; }
598 std::string getEffectCode(
const std::string& dsp_content)
600 std::stringstream effect_code;
601 effect_code <<
"adapt(1,1) = _; adapt(2,2) = _,_; adapt(1,2) = _ <: _,_; "
602 "adapt(2,1) = _,_ :> _;";
603 effect_code <<
"adaptor(F,G) = adapt(outputs(F),inputs(G)); dsp_code = "
605 << dsp_content <<
" };";
606 effect_code <<
"process = adaptor(dsp_code.process, dsp_code.effect) : "
608 return effect_code.str();
611 custom_dsp_poly_factory(
612 dsp_factory* process_factory = NULL, dsp_factory* effect_factory = NULL)
613 : fProcessFactory(process_factory)
614 , fEffectFactory(effect_factory)
618 virtual ~custom_dsp_poly_factory() =
default;
620 virtual std::string getName() {
return fProcessFactory->getName(); }
621 virtual std::string getSHAKey() {
return fProcessFactory->getSHAKey(); }
622 virtual std::string getDSPCode() {
return fProcessFactory->getDSPCode(); }
623 virtual std::string getCompileOptions()
625 return fProcessFactory->getCompileOptions();
627 virtual std::vector<std::string> getLibraryList()
629 return fProcessFactory->getLibraryList();
631 virtual std::vector<std::string> getIncludePathnames()
633 return fProcessFactory->getIncludePathnames();
636 virtual void setMemoryManager(dsp_memory_manager* manager)
638 fProcessFactory->setMemoryManager(manager);
641 fEffectFactory->setMemoryManager(manager);
644 virtual dsp_memory_manager* getMemoryManager()
646 return fProcessFactory->getMemoryManager();
661 custom_dsp_poly_effect* createPolyDSPInstance(
int nvoices,
bool control,
bool group)
664 =
new mydsp_poly(fProcessFactory->createDSPInstance(), nvoices, control, group);
669 return new custom_dsp_poly_effect(
670 dsp_poly,
new dsp_sequencer(dsp_poly, fEffectFactory->createDSPInstance()));
674 return new custom_dsp_poly_effect(dsp_poly, dsp_poly);
679 dsp* createDSPInstance() {
return fProcessFactory->createDSPInstance(); }
681struct custom_llvm_dsp_poly_factory :
public custom_dsp_poly_factory
683 custom_llvm_dsp_poly_factory(
684 const std::string& name_app,
const std::string& dsp_content,
int argc,
685 const char* argv[],
const std::string& target, std::string& error_msg,
688 fProcessFactory = createDSPFactoryFromString(
689 name_app, dsp_content, argc, argv, target, error_msg);
692 fEffectFactory = createDSPFactoryFromString(
693 name_app, getEffectCode(dsp_content), argc, argv, target, error_msg);
696 std::cerr <<
"llvm_dsp_poly_factory : fEffectFactory " << error_msg;
703 std::cerr <<
"llvm_dsp_poly_factory : fProcessFactory " << error_msg;
704 throw std::bad_alloc();
708 virtual ~custom_llvm_dsp_poly_factory()
710 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fProcessFactory));
711 deleteDSPFactory(
static_cast<llvm_dsp_factory*
>(fEffectFactory));
715static custom_llvm_dsp_poly_factory* createCustomPolyDSPFactoryFromString(
716 const std::string& name_app,
const std::string& dsp_content,
int argc,
717 const char* argv[],
const std::string& target, std::string& error_msg,
722 return new custom_llvm_dsp_poly_factory(
723 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