Guitarix
ladspaplugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Andreas Degert, Hermann Meyer
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <dlfcn.h>
20 #include <ladspa.h>
21 
22 #include "engine.h"
23 
27 using Glib::ustring;
28 
29 namespace gx_engine {
30 
31 /****************************************************************
32  ** class LadspaDsp
33  */
34 
35 class LadspaDsp: public PluginDef {
36 private:
37  static void init(unsigned int samplingFreq, PluginDef *plugin);
38  static void mono_process(int count, float *input, float *output, PluginDef *plugin);
39  static void stereo_process(int count, float *input1, float *input2, float *output1, float *output2, PluginDef *plugin);
40  static int activate(bool start, PluginDef *plugin);
41  static int registerparam(const ParamReg& reg);
42  static int uiloader(const UiBuilder& builder, int form);
43  static void del_instance(PluginDef *plugin);
44  //
45  const LADSPA_Descriptor *desc;
46  void *handle;
47  LADSPA_Handle instance;
48  LADSPA_Data *ports;
49  Glib::ustring name_str;
50  const plugdesc *pd;
51  bool is_activated;
52  void connect(int tp, int i, float *v);
53  inline void cleanup();
54  void set_shortname();
55  float dry_wet;
56  std::string idd;
57  inline void mono_dry_wet(int count, float *input0, float *input1, float *output0);
58  inline void stereo_dry_wet(int count, float *input0, float *input1, float *input2, float *input3, float *output0, float *output1);
59  std::string make_id(const paradesc& p);
60  LadspaDsp(const plugdesc *plug, void *handle_, const LADSPA_Descriptor *desc_, bool mono);
61  ~LadspaDsp();
62 public:
63  static LadspaDsp *create(const plugdesc *plug);
64  void set_plugdesc(const plugdesc* pd_);
65 };
66 
68  void *handle;
69  handle = dlopen(plug->path.c_str(), RTLD_LOCAL|RTLD_NOW);
70  if (!handle) {
71  gx_print_error("ladspaloader",ustring::compose(_("Cannot open plugin: %1 [%2]"), plug->path, dlerror()));
72  return NULL;
73  }
74  LADSPA_Descriptor_Function ladspa_descriptor = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
75  const char *dlsym_error = dlerror();
76  if (dlsym_error) {
77  gx_print_error("ladspaloader",ustring::compose(_("Cannot load symbol 'ladspa_descriptor': %1"), dlsym_error));
78  dlclose(handle);
79  handle = 0;
80  return NULL;
81  }
82  const LADSPA_Descriptor *desc = ladspa_descriptor(plug->index);
83  if (!desc || desc->UniqueID != plug->UniqueID) {
84  for (int i = 0; ; i++) {
85  desc = ladspa_descriptor(i);
86  if (!desc) {
87  break;
88  }
89  if (desc->UniqueID == plug->UniqueID) {
90  break;
91  }
92  }
93  }
94  if (!desc) {
95  gx_print_error("ladspaloader",ustring::compose(_("Cannot load ladspa descriptor #%1 from %2"), plug->index, plug->path));
96  dlclose(handle);
97  handle = 0;
98  return NULL;
99  }
100  if (desc->UniqueID == 4069 || desc->UniqueID == 4070) {
101  gx_print_error("ladspaloader",_("ladspa_guitarix not loaded"));
102  dlclose(handle);
103  handle = 0;
104  return NULL;
105  }
106  int num_inputs = 0;
107  int num_outputs = 0;
108  for (unsigned int i = 0; i < desc->PortCount; ++i) {
109  if (LADSPA_IS_PORT_AUDIO(desc->PortDescriptors[i])) {
110  if (LADSPA_IS_PORT_INPUT(desc->PortDescriptors[i])) {
111  num_inputs += 1;
112  } else { // LADSPA_IS_PORT_OUTPUT(desc->PortDescriptors[i])
113  num_outputs += 1;
114  }
115  }
116  }
117  bool mono;
118  if (num_inputs == 1 && num_outputs == 1) {
119  mono = true;
120  } else if (num_inputs == 2 && num_outputs == 2) {
121  mono = false;
122  } else {
124  "ladspaloader",ustring::compose(
125  _("cannot use ladspa plugin %1 with %2 inputs and %3 outputs"),
126  desc->Label, num_inputs, num_outputs));
127  dlclose(handle);
128  handle = 0;
129  return NULL;
130  }
131  return new LadspaDsp(plug, handle, desc, mono);
132 }
133 
134 LadspaDsp::LadspaDsp(const plugdesc *plug, void *handle_, const LADSPA_Descriptor *desc_, bool mono)
135  : PluginDef(), desc(desc_), handle(handle_), instance(),
136  ports(new LADSPA_Data[desc->PortCount]), name_str(), pd(plug), is_activated(false) {
138  id = pd->id_str.c_str();
139  category = pd->category.c_str();
140  description = desc->Name;
141  name = desc->Name;
142  set_shortname();
143  set_samplerate = init;
144  if (mono) {
145  mono_audio = mono_process;
146  } else {
147  stereo_audio = stereo_process;
148  }
149  activate_plugin = activate;
150  register_params = registerparam;
151  load_ui = uiloader;
152  delete_instance = del_instance;
153 }
154 
155 inline void LadspaDsp::cleanup() {
156  if (instance) {
157  if (pd->quirks & need_activate) {
158  activate(true, this);
159  }
160  activate(false, this);
161  if (!(pd->quirks & no_cleanup)) {
162  desc->cleanup(instance);
163  }
164  instance = 0;
165  }
166 }
167 
170  while (jp.peek() != gx_system::JsonParser::end_object) {
172  if (jp.read_kv("index", index) ||
173  jp.read_kv("name", name) ||
174  jp.read_kv("dflt", dflt) ||
175  jp.read_kv("low", low) ||
176  jp.read_kv("up", up) ||
177  jp.read_kv("step", step) ||
178  jp.read_kv("tp", tp) ||
179  jp.read_kv("newrow", newrow) ||
180  jp.read_kv("has_caption", has_caption)) {
181  } else if (jp.current_value() == "values") {
182  std::vector<std::string> v;
184  while (jp.peek() != gx_system::JsonParser::end_array) {
186  v.push_back(jp.current_value());
187  }
189  set_valuelist(v);
190  } else {
191  assert(false);
192  }
193  }
195 }
196 
198  jw.begin_object();
199  jw.write_kv("index", index);
200  jw.write_kv("name", name);
201  jw.write_kv("dflt", dflt);
202  jw.write_kv("low", low);
203  jw.write_kv("up", up);
204  jw.write_kv("step", step);
205  jw.write_kv("tp", tp);
206  jw.write_kv("newrow", newrow);
207  jw.write_kv("has_caption", has_caption);
208  if (values) {
209  jw.write_key("values");
210  jw.begin_array();
211  for (value_pair *p = values; p->value_id; p++) {
212  jw.begin_array();
213  jw.write(p->value_id);
214  jw.write(p->value_label);
215  jw.end_array();
216  }
217  jw.end_array();
218  }
219  jw.end_object();
220 }
221 
224  while (jp.peek() != gx_system::JsonParser::end_object) {
226  if (jp.read_kv("path", path) ||
227  jp.read_kv("index", index) ||
228  jp.read_kv("UniqueID", UniqueID) ||
229  jp.read_kv("Label", Label) ||
230  jp.read_kv("shortname", shortname) ||
231  jp.read_kv("category", category) ||
232  jp.read_kv("quirks", quirks) ||
233  jp.read_kv("add_wet_dry", add_wet_dry) ||
234  jp.read_kv("master_idx", master_idx) ||
235  jp.read_kv("master_label", master_label) ||
236  jp.read_kv("id_str", id_str)) {
237  } else if (jp.current_value() == "names") {
239  while (jp.peek() != gx_system::JsonParser::end_array) {
240  paradesc *p = new paradesc();
241  p->readJSON(jp);
242  names.push_back(p);
243  }
245  } else {
246  assert(false);
247  }
248  }
250 }
251 
253  jw.begin_object();
254  jw.write_kv("path", path);
255  jw.write_kv("index", index);
256  jw.write_kv("UniqueID", static_cast<unsigned int>(UniqueID));
257  jw.write_kv("Label", Label);
258  jw.write_kv("shortname", shortname);
259  jw.write_kv("category", category);
260  jw.write_kv("quirks", quirks);
261  jw.write_kv("add_wet_dry", add_wet_dry);
262  jw.write_kv("master_idx", master_idx);
263  jw.write_kv("master_label", master_label);
264  jw.write_kv("id_str", id_str);
265  jw.write_key("names");
266  jw.begin_array();
267  for (std::vector<paradesc*>::iterator i = names.begin(); i != names.end(); ++i) {
268  (*i)->writeJSON(jw);
269  }
270  jw.end_array();
271  jw.end_object();
272 }
273 
274 plugdesc::~plugdesc() {
275  for (std::vector<paradesc*>::const_iterator it = names.begin(); it != names.end(); ++it) {
276  delete *it;
277  }
278 }
279 
280 LadspaDsp::~LadspaDsp() {
281  cleanup();
282  if (handle && !(pd->quirks & no_cleanup)) {
283  dlclose(handle);
284  }
285  delete[] ports;
286 }
287 
288 int LadspaDsp::activate(bool start, PluginDef *plugin) {
289  LadspaDsp& self = *static_cast<LadspaDsp*>(plugin);
290  if (start == self.is_activated) {
291  return 0;
292  }
293  self.is_activated = start;
294  if (start) {
295  if (self.desc->activate) {
296  self.desc->activate(self.instance);
297  }
298  } else {
299  if (self.desc->deactivate) {
300  self.desc->deactivate(self.instance);
301  }
302  }
303  return 0;
304 }
305 
306 void LadspaDsp::connect(int tp, int i, float *v) {
307  for (unsigned int n = 0; n < desc->PortCount; ++n) {
308  if (!LADSPA_IS_PORT_AUDIO(desc->PortDescriptors[n])) {
309  continue;
310  }
311  if (desc->PortDescriptors[n] & tp) {
312  if (i == 0) {
313  desc->connect_port(instance, n, v);
314  return;
315  }
316  i -= 1;
317  }
318  }
319  gx_print_error("ladspaloader", _("audio port not found"));
320 }
321 
323  pd = pd_;
324  id = pd->id_str.c_str();
325  category = pd->category.c_str();
326  set_shortname();
327 }
328 
329 void LadspaDsp::set_shortname() {
330  if (!pd->shortname.empty()) {
331  shortname = pd->shortname.c_str();
332  } else {
333  name_str = desc->Name;
334  if (name_str.size() > 15) {
335  name_str.erase(15);
336  }
337  shortname = name_str.c_str();
338  }
339 }
340 
341 void LadspaDsp::init(unsigned int samplingFreq, PluginDef *plugin) {
342  LadspaDsp& self = *static_cast<LadspaDsp*>(plugin);
343  self.cleanup();
344  if (samplingFreq == 0) {
345  return;
346  }
347  self.instance = self.desc->instantiate(self.desc, samplingFreq);
348  int n = 0;
349  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
350  self.desc->connect_port(self.instance, (*it)->index, &self.ports[(*it)->index]);
351  }
352 }
353 
354 inline void LadspaDsp::mono_dry_wet(int count, float *input0, float *input1, float *output0)
355 {
356  double fSlow0 = (0.01 * dry_wet);
357  double fSlow1 = (1 - fSlow0);
358  for (int i=0; i<count; i++) {
359  output0[i] = ((fSlow0 * (double)input1[i]) + (fSlow1 * (double)input0[i]));
360  }
361 }
362 
363 void LadspaDsp::mono_process(int count, float *input, float *output, PluginDef *plugin) {
364  LadspaDsp& self = *static_cast<LadspaDsp*>(plugin);
365  assert(self.is_activated);
366  if (self.pd->add_wet_dry) {
367  float wet_out[count];
368  self.connect(LADSPA_PORT_INPUT, 0, input);
369  self.connect(LADSPA_PORT_OUTPUT, 0, wet_out);
370  self.desc->run(self.instance, count);
371  self.mono_dry_wet(count, input, wet_out, output);
372  } else {
373  self.connect(LADSPA_PORT_INPUT, 0, input);
374  self.connect(LADSPA_PORT_OUTPUT, 0, output);
375  self.desc->run(self.instance, count);
376  }
377 }
378 
379 inline void LadspaDsp::stereo_dry_wet(int count, float *input0, float *input1, float *input2, float *input3, float *output0, float *output1)
380 {
381  double fSlow0 = (0.01 * dry_wet);
382  double fSlow1 = (1 - fSlow0);
383  for (int i=0; i<count; i++) {
384  output0[i] = ((fSlow0 * (double)input2[i]) + (fSlow1 * (double)input0[i]));
385  output1[i] = ((fSlow0 * (double)input3[i]) + (fSlow1 * (double)input1[i]));
386  }
387 }
388 
389 void LadspaDsp::stereo_process(int count, float *input1, float *input2, float *output1, float *output2, PluginDef *plugin) {
390  LadspaDsp& self = *static_cast<LadspaDsp*>(plugin);
391  assert(self.is_activated);
392  if (self.pd->add_wet_dry) {
393  float wet_out1[count];
394  float wet_out2[count];
395  self.connect(LADSPA_PORT_INPUT, 0, input1);
396  self.connect(LADSPA_PORT_INPUT, 1, input2);
397  self.connect(LADSPA_PORT_OUTPUT, 0, wet_out1);
398  self.connect(LADSPA_PORT_OUTPUT, 1, wet_out2);
399  self.desc->run(self.instance, count);
400  self.stereo_dry_wet(count, input1, input2, wet_out1, wet_out2, output1, output2);
401  } else {
402  self.connect(LADSPA_PORT_INPUT, 0, input1);
403  self.connect(LADSPA_PORT_INPUT, 1, input2);
404  self.connect(LADSPA_PORT_OUTPUT, 0, output1);
405  self.connect(LADSPA_PORT_OUTPUT, 1, output2);
406  self.desc->run(self.instance, count);
407  }
408 }
409 
410 static Glib::ustring TrimLabel(const char *label, int cnt_in_row) {
411  const size_t minlen = 60 / cnt_in_row - 1;
412  const size_t maxlen = minlen + 10;
413  const size_t cutlen = (maxlen + minlen) / 2;
414  Glib::ustring pn(label);
415  size_t rem = pn.find_first_of("([");
416  if(rem != Glib::ustring::npos) {
417  pn.erase(rem);
418  }
419  while ((rem = pn.find_last_of(" ")) == pn.size()-1) {
420  pn.erase(rem);
421  }
422  rem = 0;
423  size_t rem1 = 0;
424  size_t lastpos = 0;
425  while (true) {
426  rem1 = pn.find_first_of(" ", rem1);
427  if (rem1 == Glib::ustring::npos) {
428  rem1 = pn.size();
429  }
430  while (rem1 > rem + minlen) {
431  if (lastpos > rem) {
432  rem = lastpos;
433  pn.replace(lastpos, 1, 1, '\n');
434  } else if (rem1 < rem + maxlen) {
435  if (rem1 == pn.size()) {
436  break;
437  }
438  rem = rem1;
439  pn.replace(rem1, 1, 1, '\n');
440  } else {
441  rem += cutlen;
442  pn.insert(rem, "\n");
443  }
444  rem += 1;
445  }
446  lastpos = rem1;
447  rem1 += 1;
448  if (rem1 >= pn.size()) {
449  break;
450  }
451  }
452  return pn;
453 }
454 
455 static Glib::ustring TrimEffectLabel(const char *label, int cnt_in_row) {
456  const size_t minlen = 60 / cnt_in_row - 1;
457  const size_t maxlen = minlen + 10;
458  const size_t cutlen = (maxlen + minlen) / 2;
459  Glib::ustring pn(label);
460  size_t rem = 0;
461  size_t rem1 = 0;
462  size_t lastpos = 0;
463  while (true) {
464  rem1 = pn.find_first_of(" ", rem1);
465  if (rem1 == Glib::ustring::npos) {
466  rem1 = pn.size();
467  }
468  while (rem1 > rem + minlen) {
469  if (lastpos > rem) {
470  rem = lastpos;
471  pn.replace(lastpos, 1, 1, '\n');
472  } else if (rem1 < rem + maxlen) {
473  if (rem1 == pn.size()) {
474  break;
475  }
476  rem = rem1;
477  pn.replace(rem1, 1, 1, '\n');
478  } else {
479  rem += cutlen;
480  pn.insert(rem, "\n");
481  }
482  rem += 1;
483  }
484  lastpos = rem1;
485  rem1 += 1;
486  if (rem1 >= pn.size()) {
487  break;
488  }
489  }
490  return pn;
491 }
492 
493 std::string LadspaDsp::make_id(const paradesc& p) {
494  return pd->id_str + "." + to_string(p.index);
495 }
496 
497 int LadspaDsp::registerparam(const ParamReg& reg) {
498  LadspaDsp& self = *static_cast<LadspaDsp*>(reg.plugin);
499  int n = 0;
500  int cnt_in_row = 0;
501  int left = 0;
502  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
503  paradesc *d = *it;
504  if (d->tp != tp_none) {
505  left -= 1;
506  if (left < 0) {
507  cnt_in_row = 1;
508  std::vector<paradesc*>::const_iterator it2 = it+1;
509  while (it2 != self.pd->names.end() && !(*it2)->newrow) {
510  if ((*it2)->tp != tp_none) {
511  ++cnt_in_row;
512  }
513  ++it2;
514  }
515  left = cnt_in_row;
516  }
517  }
518  const char *nm = self.desc->PortNames[d->index];
519  Glib::ustring snm(d->name);
520  if (snm.empty() && d->tp != tp_none) {
521  snm = TrimLabel(nm, cnt_in_row);
522  }
523  if (d->tp == tp_enum) {
524  reg.registerEnumVar(self.make_id(*d).c_str(), snm.c_str(), "S", nm, d->values, &self.ports[d->index],
525  d->dflt, d->low, d->up, d->step);
526  } else {
527  const char *tp = 0;
528  switch (d->tp) {
529  case tp_none: tp = "S"; break;
530  case tp_int: tp = "S"; break;
531  case tp_scale: tp = "S"; break;
532  case tp_scale_log: tp = "SL"; break;
533  case tp_toggle: tp = "B"; break;
534  case tp_display: tp = "SO"; break;
535  case tp_display_toggle: tp = "BO"; break;
536  default: assert(false);
537  }
538  reg.registerVar(self.make_id(*d).c_str(), snm.c_str(), tp, nm, &self.ports[d->index],
539  d->dflt, d->low, d->up, d->step);
540  }
541  }
542  self.idd = self.pd->id_str + ".dry_wet";
543  reg.registerVar(self.idd.c_str(),"","S","dry/wet",&self.dry_wet, 100, 0, 100, 1);
544  return 0;
545 }
546 
547 int LadspaDsp::uiloader(const UiBuilder& b, int form) {
548  if (!(form & UI_FORM_STACK)) {
549  return -1;
550  }
551  LadspaDsp& self = *static_cast<LadspaDsp*>(b.plugin);
552  b.openHorizontalhideBox("");
553  if (self.pd->master_idx >= 0) {
554  int n = 0;
555  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
556  if ((n)==self.pd->master_idx) {
557  switch ((*it)->tp) {
558  case tp_enum:
559  b.create_selector_no_caption(self.make_id(*self.pd->names[self.pd->master_idx]).c_str());
560  break;
561  default:
562  const char *p = self.pd->master_label.c_str();
563  if (!*p) {
564  p = "";
565  }
566  b.create_master_slider(self.make_id(*self.pd->names[self.pd->master_idx]).c_str(), p);
567  break;
568  }
569  }
570  }
571  }
572  int rows = 0;
573  int n = 0;
574  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
575  if ((*it)->newrow) {
576  rows +=1;
577  }
578  }
579  b.closeBox();
580  b.openVerticalBox("");
581  if (rows > 0) {
582  b.insertSpacer();
583  b.insertSpacer();
584  }
585  b.openHorizontalBox("");
586  n = 0;
587  int row = 0;
588  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
589  if ((*it)->newrow) {
590  b.closeBox();
591  if ( (rows == 1) || ( rows > 1 && row > 0 )) {
592  b.insertSpacer();
593  b.insertSpacer();
594  b.insertSpacer();
595  }
596  b.openHorizontalBox("");
597  row +=1;
598  }
599  const char *p1 = self.desc->PortNames[(*it)->index];
600  Glib::ustring trim = TrimEffectLabel(p1, 4);
601  const char *p = trim.c_str();
602  std::string id = self.make_id(**it);
603  if ((row == 1 && rows == 1 ) || (row >1 && rows >1 )) {
605  }
606  switch ((*it)->tp) {
607  case tp_scale:
608  case tp_scale_log:
609  if (!(*it)->has_caption) {
610  p = "";
611  }
612  b.create_small_rackknobr(id.c_str(), p);
613  break;
614  case tp_toggle:
615  if ((*it)->has_caption) {
616  b.create_switch("switch",id.c_str(), p);
617  } else {
618  b.create_switch_no_caption("switchit",id.c_str());
619  }
620  break;
621  case tp_display:
622  if (!(*it)->has_caption) {
623  p = "";
624  }
625  b.create_port_display(id.c_str(), p);
626  break;
627  case tp_display_toggle:
628  if ((*it)->has_caption) {
629  b.create_switch("led",id.c_str(), p);
630  } else {
631  b.create_switch_no_caption("led",id.c_str());
632  }
633  break;
634  case tp_int:
635  if (!(*it)->has_caption) {
636  p = "";
637  }
638  if (((*it)->up - (*it)->low)<200) {
639  b.create_small_rackknob(id.c_str(), p);
640  } else {
641  b.create_spin_value(id.c_str(), p);
642  }
643  break;
644  case tp_enum:
645  if ((*it)->has_caption) {
646  b.create_selector(id.c_str(), p);
647  } else {
648  b.create_selector_no_caption(id.c_str());
649  }
650  break;
651  case tp_none:
652  break;
653  default:
654  assert(false);
655  }
656  }
657  if (self.pd->add_wet_dry) {
658  b.create_small_rackknobr(self.idd.c_str(), "dry/wet");
659  }
660  b.closeBox();
661  b.closeBox();
662  return 0;
663 }
664 
665 void LadspaDsp::del_instance(PluginDef *plugin) {
666  delete static_cast<LadspaDsp*>(plugin);
667 }
668 
669 
670 /****************************************************************
671  ** class Lv2Dsp
672  */
673 
674 class Lv2Dsp: public PluginDef {
675 private:
676  static void init(unsigned int samplingFreq, PluginDef *plugin);
677  static void mono_process(int count, float *input, float *output, PluginDef *plugin);
678  static void stereo_process(int count, float *input1, float *input2, float *output1, float *output2, PluginDef *plugin);
679  static int activate(bool start, PluginDef *plugin);
680  static int registerparam(const ParamReg& reg);
681  static int uiloader(const UiBuilder& builder, int form);
682  static void del_instance(PluginDef *plugin);
683  //
684  const LadspaLoader& loader;
685  const LilvPlugin* plugin;
686  LilvNode* name_node;
687  LilvInstance* instance;
688  LADSPA_Data *ports;
689  Glib::ustring name_str;
690  const plugdesc *pd;
691  bool is_activated;
692  void connect(const LilvNode* tp, int i, float *v);
693  inline void cleanup();
694  void set_shortname();
695  float dry_wet;
696  std::string idd;
697  inline void mono_dry_wet(int count, float *input0, float *input1, float *output0);
698  inline void stereo_dry_wet(int count, float *input0, float *input1, float *input2, float *input3, float *output0, float *output1);
699  std::string make_id(const paradesc& p);
700  Lv2Dsp(const plugdesc *plug, const LilvPlugin* plugin_, const LadspaLoader& loader_, bool mono);
701  ~Lv2Dsp();
702 public:
703  static Lv2Dsp *create(const plugdesc *plug, const LadspaLoader& loader);
704  void set_plugdesc(const plugdesc* pd_);
705 };
706 
707 Lv2Dsp *Lv2Dsp::create(const plugdesc *plug, const LadspaLoader& loader) {
708  LilvNode* plugin_uri = lilv_new_uri(loader.world, plug->path.c_str());
709  const LilvPlugin* plugin = lilv_plugins_get_by_uri(loader.lv2_plugins, plugin_uri);
710  lilv_node_free(plugin_uri);
711  if (!plugin) {
712  gx_print_error("lv2loader",ustring::compose(_("Cannot open LV2 plugin: %1"), plug->path));
713  return NULL;
714  }
715 
716  int num_inputs = lilv_plugin_get_num_ports_of_class(plugin, loader.lv2_AudioPort, loader.lv2_InputPort, 0);
717  int num_outputs = lilv_plugin_get_num_ports_of_class(plugin, loader.lv2_AudioPort, loader.lv2_OutputPort, 0);
718  int num_controls = lilv_plugin_get_num_ports_of_class(plugin, loader.lv2_ControlPort, 0);
719 
720  bool mono;
721  if (num_inputs == 1 && num_outputs == 1) {
722  mono = true;
723  } else if (num_inputs == 2 && num_outputs == 2) {
724  mono = false;
725  } else {
726  LilvNode *nm = lilv_plugin_get_name(plugin);
728  "lv2loader",ustring::compose(
729  _("cannot use LV2 plugin %1 with %2 inputs and %3 outputs"),
730  lilv_node_as_string(nm), num_inputs, num_outputs));
731  lilv_node_free(nm);
732  return NULL;
733  }
734  Lv2Dsp* self = new Lv2Dsp(plug, plugin, loader, mono);
735  int desk_controls = 0;
736  for (std::vector<paradesc*>::const_iterator it = self->pd->names.begin(); it != self->pd->names.end(); ++it, ++desk_controls) ;
737  if (num_controls != desk_controls) {
738  LilvNode *nm = lilv_plugin_get_name(plugin);
740  "lv2loader",ustring::compose(
741  _("LV2 plugin %1 has changed it's ports, this may result in errors!!\nPlease go to the LADSPA/LV2 loader and select %1\nSelect 'Show Details' and press 'Restore Defaults'\nUn-load %1 (un-tick the box) and press 'save'.\nAfter this you could re-load %1 with it's new ports"),
742  lilv_node_as_string(nm)));
743  lilv_node_free(nm);
744  PluginDef& pl = *static_cast<PluginDef*>(self);
745  pl.flags |=PGNI_NEED_UPDATE;
746  }
747  return self;
748 }
749 
750 Lv2Dsp::Lv2Dsp(const plugdesc *plug, const LilvPlugin* plugin_, const LadspaLoader& loader_, bool mono)
751  : PluginDef(), loader(loader_), plugin(plugin_), name_node(lilv_plugin_get_name(plugin_)), instance(),
752  ports(new LADSPA_Data[lilv_plugin_get_num_ports(plugin_)]), name_str(), pd(plug), is_activated(false) {
754  id = pd->id_str.c_str();
755  category = pd->category.c_str();
756  description = lilv_node_as_string(name_node);
757  name = lilv_node_as_string(name_node);
758  set_shortname();
759  set_samplerate = init;
760  if (mono) {
761  mono_audio = mono_process;
762  } else {
763  stereo_audio = stereo_process;
764  }
765  activate_plugin = activate;
766  register_params = registerparam;
767  load_ui = uiloader;
768  delete_instance = del_instance;
769 }
770 
771 inline void Lv2Dsp::cleanup() {
772  if (instance) {
773  if (pd->quirks & need_activate) {
774  activate(true, this);
775  }
776  activate(false, this);
777  if (!(pd->quirks & no_cleanup)) {
778  lilv_instance_free(instance);
779  }
780  instance = 0;
781  }
782 }
783 
784 Lv2Dsp::~Lv2Dsp() {
785  cleanup();
786  delete[] ports;
787  lilv_node_free(name_node);
788 }
789 
790 int Lv2Dsp::activate(bool start, PluginDef *plugin) {
791  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
792  if (start == self.is_activated) {
793  return 0;
794  }
795  if (!self.instance) {
796  gx_print_warning("Lv2Dsp", ustring::compose("cant activate plugin %1", self.name));
797  return 1;
798  }
799  self.is_activated = start;
800  if (start) {
801  lilv_instance_activate(self.instance);
802  } else {
803  lilv_instance_deactivate(self.instance);
804  }
805  return 0;
806 }
807 
808 void Lv2Dsp::connect(const LilvNode* tp, int i, float *v) {
809  unsigned int num_ports = lilv_plugin_get_num_ports(plugin);
810  for (unsigned int n = 0; n < num_ports; ++n) {
811  const LilvPort* port = lilv_plugin_get_port_by_index(plugin, n);
812  if (!lilv_port_is_a(plugin, port, loader.lv2_AudioPort)) {
813  continue;
814  }
815  if (lilv_port_is_a(plugin, port, tp)) {
816  if (i == 0) {
817  lilv_instance_connect_port(instance, n, v);
818  return;
819  }
820  i -= 1;
821  }
822  }
823  gx_print_error("lv2loader", _("audio port not found"));
824 }
825 
826 void Lv2Dsp::set_plugdesc(const plugdesc* pd_) {
827  pd = pd_;
828  id = pd->id_str.c_str();
829  category = pd->category.c_str();
830  set_shortname();
831 }
832 
833 void Lv2Dsp::set_shortname() {
834  if (!pd->shortname.empty()) {
835  shortname = pd->shortname.c_str();
836  } else {
837  name_str = lilv_node_as_string(name_node);
838  if (name_str.size() > 15) {
839  name_str.erase(15);
840  }
841  shortname = name_str.c_str();
842  }
843 }
844 
845 void Lv2Dsp::init(unsigned int samplingFreq, PluginDef *pldef) {
846  Lv2Dsp& self = *static_cast<Lv2Dsp*>(pldef);
847  self.cleanup();
848  if (samplingFreq == 0) {
849  return;
850  }
851  self.instance = lilv_plugin_instantiate(self.plugin, samplingFreq, 0);
852  if (!self.instance) {
853  gx_print_error("Lv2Dsp", ustring::compose("cant init plugin: %1 \n uri: %2", self.name, self.pd->path));
854  return;
855  }
856  int n = 0;
857  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
858  lilv_instance_connect_port(self.instance, (*it)->index, &self.ports[(*it)->index]);
859  }
860 }
861 
862 inline void Lv2Dsp::mono_dry_wet(int count, float *input0, float *input1, float *output0)
863 {
864  double fSlow0 = (0.01 * dry_wet);
865  double fSlow1 = (1 - fSlow0);
866  for (int i=0; i<count; i++) {
867  output0[i] = ((fSlow0 * (double)input1[i]) + (fSlow1 * (double)input0[i]));
868  }
869 }
870 
871 void Lv2Dsp::mono_process(int count, float *input, float *output, PluginDef *plugin) {
872  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
873  assert(self.is_activated);
874  if (self.pd->add_wet_dry) {
875  float wet_out[count];
876  self.connect(self.loader.lv2_InputPort, 0, input);
877  self.connect(self.loader.lv2_OutputPort, 0, wet_out);
878  lilv_instance_run(self.instance, count);
879  self.mono_dry_wet(count, input, wet_out, output);
880  } else {
881  self.connect(self.loader.lv2_InputPort, 0, input);
882  self.connect(self.loader.lv2_OutputPort, 0, output);
883  lilv_instance_run(self.instance, count);
884  }
885 }
886 
887 inline void Lv2Dsp::stereo_dry_wet(int count, float *input0, float *input1, float *input2, float *input3, float *output0, float *output1)
888 {
889  double fSlow0 = (0.01 * dry_wet);
890  double fSlow1 = (1 - fSlow0);
891  for (int i=0; i<count; i++) {
892  output0[i] = ((fSlow0 * (double)input2[i]) + (fSlow1 * (double)input0[i]));
893  output1[i] = ((fSlow0 * (double)input3[i]) + (fSlow1 * (double)input1[i]));
894  }
895 }
896 
897 void Lv2Dsp::stereo_process(int count, float *input1, float *input2, float *output1, float *output2, PluginDef *plugin) {
898  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
899  assert(self.is_activated);
900  if (self.pd->add_wet_dry) {
901  float wet_out1[count];
902  float wet_out2[count];
903  self.connect(self.loader.lv2_InputPort, 0, input1);
904  self.connect(self.loader.lv2_InputPort, 1, input2);
905  self.connect(self.loader.lv2_OutputPort, 0, wet_out1);
906  self.connect(self.loader.lv2_OutputPort, 1, wet_out2);
907  lilv_instance_run(self.instance, count);
908  self.stereo_dry_wet(count, input1, input2, wet_out1, wet_out2, output1, output2);
909  } else {
910  self.connect(self.loader.lv2_InputPort, 0, input1);
911  self.connect(self.loader.lv2_InputPort, 1, input2);
912  self.connect(self.loader.lv2_OutputPort, 0, output1);
913  self.connect(self.loader.lv2_OutputPort, 1, output2);
914  lilv_instance_run(self.instance, count);
915  }
916 }
917 
918 std::string Lv2Dsp::make_id(const paradesc& p) {
919  return pd->id_str + "." + to_string(p.index);
920 }
921 
922 int Lv2Dsp::registerparam(const ParamReg& reg) {
923  Lv2Dsp& self = *static_cast<Lv2Dsp*>(reg.plugin);
924  int n = 0;
925  int cnt_in_row = 0;
926  int left = 0;
927  int num_controls = lilv_plugin_get_num_ports_of_class(self.plugin, self.loader.lv2_ControlPort, 0);
928  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
929  if (n>=num_controls) break;
930  paradesc *d = *it;
931  if (d->tp != tp_none) {
932  left -= 1;
933  if (left < 0) {
934  cnt_in_row = 1;
935  std::vector<paradesc*>::const_iterator it2 = it+1;
936  while (it2 != self.pd->names.end() && !(*it2)->newrow) {
937  if ((*it2)->tp != tp_none) {
938  ++cnt_in_row;
939  }
940  ++it2;
941  }
942  left = cnt_in_row;
943  }
944  }
945  const LilvPort* port = lilv_plugin_get_port_by_index(self.plugin, d->index);
946  LilvNode* nm_node = lilv_port_get_name(self.plugin, port);
947  const char *nm = lilv_node_as_string(nm_node);
948  Glib::ustring snm(d->name);
949  if (snm.empty() && d->tp != tp_none) {
950  snm = TrimLabel(nm, cnt_in_row);
951  }
952  if (d->tp == tp_enum) {
953  reg.registerEnumVar(self.make_id(*d).c_str(), snm.c_str(), "S", nm, d->values, &self.ports[d->index],
954  d->dflt, d->low, d->up, d->step);
955  } else {
956  const char *tp = 0;
957  switch (d->tp) {
958  case tp_none: tp = "S"; break;
959  case tp_int: tp = "S"; break;
960  case tp_scale: tp = "S"; break;
961  case tp_scale_log: tp = "SL"; break;
962  case tp_toggle: tp = "B"; break;
963  case tp_display: tp = "SO"; break;
964  case tp_display_toggle: tp = "BO"; break;
965  default: assert(false);
966  }
967  reg.registerVar(self.make_id(*d).c_str(), snm.c_str(), tp, nm, &self.ports[d->index],
968  d->dflt, d->low, d->up, d->step);
969  }
970  lilv_node_free(nm_node);
971  }
972  self.idd = self.pd->id_str + ".dry_wet";
973  reg.registerVar(self.idd.c_str(),"","S","dry/wet",&self.dry_wet, 100, 0, 100, 1);
974  return 0;
975 }
976 
977 int Lv2Dsp::uiloader(const UiBuilder& b, int form) {
978  if (!(form & UI_FORM_STACK)) {
979  return -1;
980  }
981  Lv2Dsp& self = *static_cast<Lv2Dsp*>(b.plugin);
982  b.openHorizontalhideBox("");
983  if (self.pd->master_idx >= 0) {
984  int n = 0;
985  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
986  if ((n)==self.pd->master_idx) {
987  switch ((*it)->tp) {
988  case tp_enum:
989  b.create_selector_no_caption(self.make_id(*self.pd->names[self.pd->master_idx]).c_str());
990  break;
991  default:
992  const char *p = self.pd->master_label.c_str();
993  if (!*p) {
994  p = "";
995  }
996  b.create_master_slider(self.make_id(*self.pd->names[self.pd->master_idx]).c_str(), p);
997  break;
998  }
999  }
1000  }
1001  }
1002  b.closeBox();
1003  b.openVerticalBox("");
1004  b.openHorizontalBox("");
1005  int rows = 0;
1006  int n = 0;
1007  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
1008  if ((*it)->newrow) {
1009  rows +=1;
1010  }
1011  }
1012  n = 0;
1013  int row = 0;
1014  int num_controls = lilv_plugin_get_num_ports_of_class(self.plugin, self.loader.lv2_ControlPort, 0);
1015  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
1016  if (n>=num_controls) break;
1017  if ((*it)->newrow) {
1018  b.closeBox();
1019  if ( (rows == 1) || ( rows > 1 && row > 0 )) {
1020  b.insertSpacer();
1021  b.insertSpacer();
1022  b.insertSpacer();
1023  }
1024  b.openHorizontalBox("");
1025  row +=1;
1026  }
1027  const LilvPort* port = lilv_plugin_get_port_by_index(self.plugin, (*it)->index);
1028  LilvNode* nm_node = lilv_port_get_name(self.plugin, port);
1029  const char *p = lilv_node_as_string(nm_node);
1030  std::string id = self.make_id(**it);
1031  if ((row == 1 && rows == 1 ) || (row >1 && rows >1 )) {
1033  }
1034  switch ((*it)->tp) {
1035  case tp_scale:
1036  case tp_scale_log:
1037  if (!(*it)->has_caption) {
1038  p = "";
1039  }
1040  b.create_small_rackknobr(id.c_str(), p);
1041  break;
1042  case tp_toggle:
1043  if ((*it)->has_caption) {
1044  b.create_switch("switch_mid",id.c_str(), p);
1045  } else {
1046  b.create_switch_no_caption("switchit",id.c_str());
1047  }
1048  break;
1049  case tp_display:
1050  if (!(*it)->has_caption) {
1051  p = "";
1052  }
1053  b.create_port_display(id.c_str(), p);
1054  break;
1055  case tp_display_toggle:
1056  if ((*it)->has_caption) {
1057  b.create_switch("led",id.c_str(), p);
1058  } else {
1059  b.create_switch_no_caption("led",id.c_str());
1060  }
1061  break;
1062  case tp_int:
1063  if (!(*it)->has_caption) {
1064  p = "";
1065  }
1066  if (((*it)->up - (*it)->low)<200) {
1067  b.create_small_rackknob(id.c_str(), p);
1068  } else {
1069  b.create_spin_value(id.c_str(), p);
1070  }
1071  break;
1072  case tp_enum:
1073  if ((*it)->has_caption) {
1074  b.create_selector(id.c_str(), p);
1075  } else {
1076  b.create_selector_no_caption(id.c_str());
1077  }
1078  break;
1079  case tp_none:
1080  break;
1081  default:
1082  assert(false);
1083  }
1084  lilv_node_free(nm_node);
1085  }
1086  if (self.pd->add_wet_dry) {
1087  b.create_small_rackknobr(self.idd.c_str(), "dry/wet");
1088  }
1089  b.closeBox();
1090  b.closeBox();
1091  return 0;
1092 }
1093 
1094 void Lv2Dsp::del_instance(PluginDef *plugin) {
1095  delete static_cast<Lv2Dsp*>(plugin);
1096 }
1097 
1098 
1099 /****************************************************************
1100  ** class LadspaLoader
1101  */
1102 
1104  if (p->quirks & is_lv2) {
1105  return Lv2Dsp::create(p, *this);
1106  } else {
1107  return LadspaDsp::create(p);
1108  }
1109 }
1110 
1112  : options(options_),
1113  plugins(),
1114  world(lilv_world_new()),
1115  lv2_plugins(),
1116  lv2_AudioPort(lilv_new_uri(world, LV2_CORE__AudioPort)),
1117  lv2_ControlPort(lilv_new_uri(world, LV2_CORE__ControlPort)),
1118  lv2_InputPort(lilv_new_uri(world, LV2_CORE__InputPort)),
1119  lv2_OutputPort(lilv_new_uri(world, LV2_CORE__OutputPort)) {
1120  lilv_world_load_all(world);
1121  lv2_plugins = lilv_world_get_all_plugins(world);
1122  load(plugins);
1123 }
1124 
1126  for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1127  delete *i;
1128  }
1129  lilv_node_free(lv2_OutputPort);
1130  lilv_node_free(lv2_InputPort);
1131  lilv_node_free(lv2_ControlPort);
1132  lilv_node_free(lv2_AudioPort);
1133  lilv_world_free(world);
1134 }
1135 
1137  try {
1138  read_module_list(ml);
1139  } catch (JsonException &e) {
1140  gx_print_error("ladspaloader",ustring::compose(_("Exception in LADSPA list reader: %1"), e.what()));
1141  return false;
1142  }
1143  return true;
1144 }
1145 
1147  for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1148  delete *i;
1149  }
1150  plugins = new_plugins;
1151 }
1152 
1154  //for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1155  //delete *i;
1156  //}
1157  plugins = new_plugins;
1158 }
1159 
1160 LadspaLoader::pluginarray::iterator LadspaLoader::find(plugdesc *desc) {
1161  for (pluginarray::iterator i = begin(); i != end(); ++i) {
1162  if (desc->quirks & is_lv2) {
1163  if ((*i)->path == desc->path) {
1164  return i;
1165  }
1166  } else {
1167  if ((*i)->UniqueID == desc->UniqueID) {
1168  return i;
1169  }
1170  }
1171  }
1172  return end();
1173 }
1174 
1176  if (pdesc->quirks & is_lv2) {
1177  static_cast<Lv2Dsp*>(pdef)->set_plugdesc(pdesc);
1178  } else {
1179  static_cast<LadspaDsp*>(pdef)->set_plugdesc(pdesc);
1180  }
1181 }
1182 
1184  for (value_pair *p = values; p->value_id; ++p) {
1185  g_free(const_cast<char*>(p->value_id));
1186  }
1187  delete[] values;
1188 }
1189 
1190 void paradesc::set_valuelist(const std::vector<std::string>& v) {
1191  values = new value_pair[v.size()+1];
1192  int n = 0;
1193  for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i, ++n) {
1194  const char *p = g_strdup(i->c_str());
1195  values[n].value_id = p;
1196  values[n].value_label = p;
1197  }
1198  values[n].value_id = 0;
1199  values[n].value_label = 0;
1200 }
1201 
1202 void LadspaLoader::read_module_config(const std::string& filename, plugdesc *p) {
1203  std::ifstream ifs(filename.c_str());
1204  if (ifs.fail()) {
1205  gx_print_error("ladspaloader", ustring::compose(_("can't open %1"), filename));
1206  return;
1207  }
1208  gx_system::JsonParser jp(&ifs);
1211  jp.current_value_int(); // int version
1213  p->shortname = jp.current_value();
1215  p->category = jp.current_value();
1217  p->master_idx = jp.current_value_int();
1219  p->master_label = jp.current_value();
1221  p->quirks = jp.current_value_int();
1223  p->add_wet_dry= jp.current_value_int();
1225  while (jp.peek() != gx_system::JsonParser::end_array) {
1226  paradesc *para = new paradesc;
1229  para->index = jp.current_value_int();
1230  jp.skip_object(); // meta data
1232  para->name = jp.current_value();
1235  para->dflt = jp.current_value_float();
1237  para->low = jp.current_value_float();
1239  para->up = jp.current_value_float();
1241  para->step = jp.current_value_float();
1243  para->tp = static_cast<widget_type>(jp.current_value_int()); //FIXME (check valid)
1245  para->newrow = jp.current_value_int();
1247  para->has_caption = jp.current_value_int();
1249  std::vector<std::string> v;
1250  while (jp.peek() != gx_system::JsonParser::end_array) {
1252  v.push_back(jp.current_value());
1253  }
1255  para->set_valuelist(v);
1257  p->names.push_back(para);
1258  }
1260  jp.close();
1261  ifs.close();
1262 }
1263 
1264 void LadspaLoader::read_module_list(pluginarray& ml) {
1265  std::ifstream ifs(options.get_user_filepath("ladspa_defs.js").c_str());
1266  if (ifs.fail()) {
1267  return;
1268  }
1269  gx_system::JsonParser jp(&ifs);
1271  while (jp.peek() != gx_system::JsonParser::end_array) {
1274  plugdesc *p = new plugdesc;
1275  p->path = jp.current_value();
1277  int idx = jp.current_value_int();
1278  if (idx < 0) {
1279  p->quirks |= is_lv2;
1280  }
1281  p->index = idx;
1283  p->UniqueID = jp.current_value_int();
1285  p->Label = jp.current_value();
1287  std::string s;
1288  if (idx < 0) {
1289  s = gx_system::encode_filename(p->path) + ".js";
1290  } else {
1291  s = get_ladspa_filename(p->UniqueID);
1292  }
1293  std::string fname = options.get_plugin_filepath(s);
1294  if (access(fname.c_str(), F_OK) != 0) {
1295  fname = options.get_factory_filepath(s);
1296  if (access(fname.c_str(), F_OK) != 0) {
1297  fname = "";
1298  }
1299  }
1300  if (!fname.empty()) {
1301  try {
1302  read_module_config(fname, p);
1303  } catch (JsonException &e) {
1304  gx_print_error("ladspaloader",ustring::compose(_("read error in file %1: %2"), s, e.what()));
1305  }
1306  }
1307  if (p->quirks & is_lv2) {
1308  p->id_str = "lv2_" + gx_system::encode_filename(p->path);
1309  } else {
1310  p->id_str = "ladspa_" + to_string(p->UniqueID);
1311  }
1312  ml.push_back(p);
1313  }
1314  jp.close();
1315  ifs.close();
1316 }
1317 
1318 } // namespace gx_engine
void write_kv(const char *key, float v)
Definition: gx_json.h:81
CmdConnection::msg_type start
Definition: jsonrpc.cpp:255
void begin_array(bool nl=false)
Definition: gx_json.cpp:184
pluginarray::iterator end()
void(* insertSpacer)()
Definition: gx_plugin.h:78
std::string get_factory_filepath(const std::string &basename) const
Definition: gx_system.h:465
PluginDef * plugin
Definition: gx_plugin.h:64
void end_array(bool nl=false)
Definition: gx_json.cpp:192
void writeJSON(gx_system::JsonWriter &jw)
int(* uiloader)(const UiBuilder &builder, int format)
Definition: gx_plugin.h:156
const char * value_id
Definition: gx_plugin.h:118
void set_plugins(pluginarray &new_plugins)
PluginDef * plugin
Definition: gx_plugin.h:123
void set_plugdesc(const plugdesc *pd_)
LadspaLoader(const gx_system::CmdlineOptions &options)
virtual void close()
Definition: gx_json.cpp:277
const char * name
Definition: gx_plugin.h:186
std::vector< plugdesc * > pluginarray
void set_plugdesc(const plugdesc *pd_)
#define UI_LABEL_INVERSE
Definition: gx_plugin.h:45
float *(* registerVar)(const char *id, const char *name, const char *tp, const char *tooltip, float *var, float val, float low, float up, float step)
Definition: gx_plugin.h:124
void(* create_switch_no_caption)(const char *sw_type, const char *id)
Definition: gx_plugin.h:89
void(* registerEnumVar)(const char *id, const char *name, const char *tp, const char *tooltip, const value_pair *values, float *var, float val, float low, float up, float step)
Definition: gx_plugin.h:132
const char * description
Definition: gx_plugin.h:189
void(* closeBox)()
Definition: gx_plugin.h:77
pluginarray::iterator find(plugdesc *desc)
void write_key(const char *p, bool nl=false)
Definition: gx_json.cpp:200
const char * shortname
Definition: gx_plugin.h:191
bool load(pluginarray &p)
const char * category
Definition: gx_plugin.h:190
void readJSON(gx_system::JsonParser &jp)
deletefunc delete_instance
Definition: gx_plugin.h:204
static LadspaDsp * create(const plugdesc *plug)
static Lv2Dsp * create(const plugdesc *plug, const LadspaLoader &loader)
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
bool read_kv(const char *key, float &v)
Definition: gx_json.cpp:511
void(* create_selector)(const char *id, const char *label)
Definition: gx_plugin.h:95
PluginDef * create(unsigned int idx)
#define PLUGINDEF_VERSION
Definition: gx_plugin.h:179
void(* openHorizontalBox)(const char *label)
Definition: gx_plugin.h:71
registerfunc register_params
Definition: gx_plugin.h:200
void(* create_port_display)(const char *id, const char *label)
Definition: gx_plugin.h:92
std::string get_plugin_filepath(const std::string &basename) const
Definition: gx_system.h:464
void begin_object(bool nl=false)
Definition: gx_json.cpp:168
void(* create_small_rackknobr)(const char *id, const char *label)
Definition: gx_plugin.h:98
int flags
Definition: gx_plugin.h:183
std::string to_string(const T &t)
Definition: gx_system.h:523
virtual const char * what() const
Definition: gx_json.h:46
void(* create_small_rackknob)(const char *id, const char *label)
Definition: gx_plugin.h:86
#define UI_FORM_STACK
Definition: gx_plugin.h:60
std::vector< paradesc * > names
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
void(* openHorizontalhideBox)(const char *label)
Definition: gx_plugin.h:72
activatefunc activate_plugin
Definition: gx_plugin.h:199
void(* create_spin_value)(const char *id, const char *label)
Definition: gx_plugin.h:91
process_stereo_audio stereo_audio
Definition: gx_plugin.h:196
std::string get_user_filepath(const std::string &basename) const
Definition: gx_system.h:371
void update_instance(PluginDef *pdef, plugdesc *pdesc)
pluginarray::iterator begin()
string current_value() const
Definition: gx_json.h:143
void readJSON(gx_system::JsonParser &jp)
void(* set_next_flags)(int flags)
Definition: gx_plugin.h:79
inifunc set_samplerate
Definition: gx_plugin.h:198
void writeJSON(gx_system::JsonWriter &jw)
process_mono_audio mono_audio
Definition: gx_plugin.h:195
void set_valuelist(const std::vector< std::string > &v)
static std::string get_ladspa_filename(unsigned long uid)
float current_value_float()
Definition: gx_json.h:146
token next(token expect=no_token)
Definition: gx_json.cpp:496
void write(float v, bool nl=false)
Definition: gx_json.cpp:116
int version
Definition: gx_plugin.h:182
void(* create_switch)(const char *sw_type, const char *id, const char *label)
Definition: gx_plugin.h:94
uiloader load_ui
Definition: gx_plugin.h:201
void change_plugins(pluginarray &new_plugins)
void(* create_master_slider)(const char *id, const char *label)
Definition: gx_plugin.h:84
void end_object(bool nl=false)
Definition: gx_json.cpp:176
void(* create_selector_no_caption)(const char *id)
Definition: gx_plugin.h:88
void(* openVerticalBox)(const char *label)
Definition: gx_plugin.h:68
std::string encode_filename(const std::string &s)
Definition: gx_system.cpp:999