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  bool mono;
719  if (num_inputs == 1 && num_outputs == 1) {
720  mono = true;
721  } else if (num_inputs == 2 && num_outputs == 2) {
722  mono = false;
723  } else {
724  LilvNode *nm = lilv_plugin_get_name(plugin);
726  "lv2loader",ustring::compose(
727  _("cannot use LV2 plugin %1 with %2 inputs and %3 outputs"),
728  lilv_node_as_string(nm), num_inputs, num_outputs));
729  lilv_node_free(nm);
730  return NULL;
731  }
732  return new Lv2Dsp(plug, plugin, loader, mono);
733 }
734 
735 Lv2Dsp::Lv2Dsp(const plugdesc *plug, const LilvPlugin* plugin_, const LadspaLoader& loader_, bool mono)
736  : PluginDef(), loader(loader_), plugin(plugin_), name_node(lilv_plugin_get_name(plugin_)), instance(),
737  ports(new LADSPA_Data[lilv_plugin_get_num_ports(plugin_)]), name_str(), pd(plug), is_activated(false) {
739  id = pd->id_str.c_str();
740  category = pd->category.c_str();
741  description = lilv_node_as_string(name_node);
742  name = lilv_node_as_string(name_node);
743  set_shortname();
744  set_samplerate = init;
745  if (mono) {
746  mono_audio = mono_process;
747  } else {
748  stereo_audio = stereo_process;
749  }
750  activate_plugin = activate;
751  register_params = registerparam;
752  load_ui = uiloader;
753  delete_instance = del_instance;
754 }
755 
756 inline void Lv2Dsp::cleanup() {
757  if (instance) {
758  if (pd->quirks & need_activate) {
759  activate(true, this);
760  }
761  activate(false, this);
762  if (!(pd->quirks & no_cleanup)) {
763  lilv_instance_free(instance);
764  }
765  instance = 0;
766  }
767 }
768 
769 Lv2Dsp::~Lv2Dsp() {
770  cleanup();
771  delete[] ports;
772  lilv_node_free(name_node);
773 }
774 
775 int Lv2Dsp::activate(bool start, PluginDef *plugin) {
776  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
777  if (start == self.is_activated) {
778  return 0;
779  }
780  if (!self.instance) {
781  gx_print_warning("Lv2Dsp", ustring::compose("cant activate plugin %1", self.name));
782  return 1;
783  }
784  self.is_activated = start;
785  if (start) {
786  lilv_instance_activate(self.instance);
787  } else {
788  lilv_instance_deactivate(self.instance);
789  }
790  return 0;
791 }
792 
793 void Lv2Dsp::connect(const LilvNode* tp, int i, float *v) {
794  unsigned int num_ports = lilv_plugin_get_num_ports(plugin);
795  for (unsigned int n = 0; n < num_ports; ++n) {
796  const LilvPort* port = lilv_plugin_get_port_by_index(plugin, n);
797  if (!lilv_port_is_a(plugin, port, loader.lv2_AudioPort)) {
798  continue;
799  }
800  if (lilv_port_is_a(plugin, port, tp)) {
801  if (i == 0) {
802  lilv_instance_connect_port(instance, n, v);
803  return;
804  }
805  i -= 1;
806  }
807  }
808  gx_print_error("lv2loader", _("audio port not found"));
809 }
810 
811 void Lv2Dsp::set_plugdesc(const plugdesc* pd_) {
812  pd = pd_;
813  id = pd->id_str.c_str();
814  category = pd->category.c_str();
815  set_shortname();
816 }
817 
818 void Lv2Dsp::set_shortname() {
819  if (!pd->shortname.empty()) {
820  shortname = pd->shortname.c_str();
821  } else {
822  name_str = lilv_node_as_string(name_node);
823  if (name_str.size() > 15) {
824  name_str.erase(15);
825  }
826  shortname = name_str.c_str();
827  }
828 }
829 
830 void Lv2Dsp::init(unsigned int samplingFreq, PluginDef *pldef) {
831  Lv2Dsp& self = *static_cast<Lv2Dsp*>(pldef);
832  self.cleanup();
833  if (samplingFreq == 0) {
834  return;
835  }
836  self.instance = lilv_plugin_instantiate(self.plugin, samplingFreq, 0);
837  if (!self.instance) {
838  gx_print_error("Lv2Dsp", ustring::compose("cant init plugin: %1 \n uri: %2", self.name, self.pd->path));
839  return;
840  }
841  int n = 0;
842  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
843  lilv_instance_connect_port(self.instance, (*it)->index, &self.ports[(*it)->index]);
844  }
845 }
846 
847 inline void Lv2Dsp::mono_dry_wet(int count, float *input0, float *input1, float *output0)
848 {
849  double fSlow0 = (0.01 * dry_wet);
850  double fSlow1 = (1 - fSlow0);
851  for (int i=0; i<count; i++) {
852  output0[i] = ((fSlow0 * (double)input1[i]) + (fSlow1 * (double)input0[i]));
853  }
854 }
855 
856 void Lv2Dsp::mono_process(int count, float *input, float *output, PluginDef *plugin) {
857  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
858  assert(self.is_activated);
859  if (self.pd->add_wet_dry) {
860  float wet_out[count];
861  self.connect(self.loader.lv2_InputPort, 0, input);
862  self.connect(self.loader.lv2_OutputPort, 0, wet_out);
863  lilv_instance_run(self.instance, count);
864  self.mono_dry_wet(count, input, wet_out, output);
865  } else {
866  self.connect(self.loader.lv2_InputPort, 0, input);
867  self.connect(self.loader.lv2_OutputPort, 0, output);
868  lilv_instance_run(self.instance, count);
869  }
870 }
871 
872 inline void Lv2Dsp::stereo_dry_wet(int count, float *input0, float *input1, float *input2, float *input3, float *output0, float *output1)
873 {
874  double fSlow0 = (0.01 * dry_wet);
875  double fSlow1 = (1 - fSlow0);
876  for (int i=0; i<count; i++) {
877  output0[i] = ((fSlow0 * (double)input2[i]) + (fSlow1 * (double)input0[i]));
878  output1[i] = ((fSlow0 * (double)input3[i]) + (fSlow1 * (double)input1[i]));
879  }
880 }
881 
882 void Lv2Dsp::stereo_process(int count, float *input1, float *input2, float *output1, float *output2, PluginDef *plugin) {
883  Lv2Dsp& self = *static_cast<Lv2Dsp*>(plugin);
884  assert(self.is_activated);
885  if (self.pd->add_wet_dry) {
886  float wet_out1[count];
887  float wet_out2[count];
888  self.connect(self.loader.lv2_InputPort, 0, input1);
889  self.connect(self.loader.lv2_InputPort, 1, input2);
890  self.connect(self.loader.lv2_OutputPort, 0, wet_out1);
891  self.connect(self.loader.lv2_OutputPort, 1, wet_out2);
892  lilv_instance_run(self.instance, count);
893  self.stereo_dry_wet(count, input1, input2, wet_out1, wet_out2, output1, output2);
894  } else {
895  self.connect(self.loader.lv2_InputPort, 0, input1);
896  self.connect(self.loader.lv2_InputPort, 1, input2);
897  self.connect(self.loader.lv2_OutputPort, 0, output1);
898  self.connect(self.loader.lv2_OutputPort, 1, output2);
899  lilv_instance_run(self.instance, count);
900  }
901 }
902 
903 std::string Lv2Dsp::make_id(const paradesc& p) {
904  return pd->id_str + "." + to_string(p.index);
905 }
906 
907 int Lv2Dsp::registerparam(const ParamReg& reg) {
908  Lv2Dsp& self = *static_cast<Lv2Dsp*>(reg.plugin);
909  int n = 0;
910  int cnt_in_row = 0;
911  int left = 0;
912  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
913  paradesc *d = *it;
914  if (d->tp != tp_none) {
915  left -= 1;
916  if (left < 0) {
917  cnt_in_row = 1;
918  std::vector<paradesc*>::const_iterator it2 = it+1;
919  while (it2 != self.pd->names.end() && !(*it2)->newrow) {
920  if ((*it2)->tp != tp_none) {
921  ++cnt_in_row;
922  }
923  ++it2;
924  }
925  left = cnt_in_row;
926  }
927  }
928  const LilvPort* port = lilv_plugin_get_port_by_index(self.plugin, d->index);
929  LilvNode* nm_node = lilv_port_get_name(self.plugin, port);
930  const char *nm = lilv_node_as_string(nm_node);
931  Glib::ustring snm(d->name);
932  if (snm.empty() && d->tp != tp_none) {
933  snm = TrimLabel(nm, cnt_in_row);
934  }
935  if (d->tp == tp_enum) {
936  reg.registerEnumVar(self.make_id(*d).c_str(), snm.c_str(), "S", nm, d->values, &self.ports[d->index],
937  d->dflt, d->low, d->up, d->step);
938  } else {
939  const char *tp = 0;
940  switch (d->tp) {
941  case tp_none: tp = "S"; break;
942  case tp_int: tp = "S"; break;
943  case tp_scale: tp = "S"; break;
944  case tp_scale_log: tp = "SL"; break;
945  case tp_toggle: tp = "B"; break;
946  case tp_display: tp = "SO"; break;
947  case tp_display_toggle: tp = "BO"; break;
948  default: assert(false);
949  }
950  reg.registerVar(self.make_id(*d).c_str(), snm.c_str(), tp, nm, &self.ports[d->index],
951  d->dflt, d->low, d->up, d->step);
952  }
953  lilv_node_free(nm_node);
954  }
955  self.idd = self.pd->id_str + ".dry_wet";
956  reg.registerVar(self.idd.c_str(),"","S","dry/wet",&self.dry_wet, 100, 0, 100, 1);
957  return 0;
958 }
959 
960 int Lv2Dsp::uiloader(const UiBuilder& b, int form) {
961  if (!(form & UI_FORM_STACK)) {
962  return -1;
963  }
964  Lv2Dsp& self = *static_cast<Lv2Dsp*>(b.plugin);
965  b.openHorizontalhideBox("");
966  if (self.pd->master_idx >= 0) {
967  int n = 0;
968  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
969  if ((n)==self.pd->master_idx) {
970  switch ((*it)->tp) {
971  case tp_enum:
972  b.create_selector_no_caption(self.make_id(*self.pd->names[self.pd->master_idx]).c_str());
973  break;
974  default:
975  const char *p = self.pd->master_label.c_str();
976  if (!*p) {
977  p = "";
978  }
979  b.create_master_slider(self.make_id(*self.pd->names[self.pd->master_idx]).c_str(), p);
980  break;
981  }
982  }
983  }
984  }
985  b.closeBox();
986  b.openVerticalBox("");
987  b.openHorizontalBox("");
988  int rows = 0;
989  int n = 0;
990  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
991  if ((*it)->newrow) {
992  rows +=1;
993  }
994  }
995  n = 0;
996  int row = 0;
997  for (std::vector<paradesc*>::const_iterator it = self.pd->names.begin(); it != self.pd->names.end(); ++it, ++n) {
998  if ((*it)->newrow) {
999  b.closeBox();
1000  if ( (rows == 1) || ( rows > 1 && row > 0 )) {
1001  b.insertSpacer();
1002  b.insertSpacer();
1003  b.insertSpacer();
1004  }
1005  b.openHorizontalBox("");
1006  row +=1;
1007  }
1008  const LilvPort* port = lilv_plugin_get_port_by_index(self.plugin, (*it)->index);
1009  LilvNode* nm_node = lilv_port_get_name(self.plugin, port);
1010  const char *p = lilv_node_as_string(nm_node);
1011  std::string id = self.make_id(**it);
1012  if ((row == 1 && rows == 1 ) || (row >1 && rows >1 )) {
1014  }
1015  switch ((*it)->tp) {
1016  case tp_scale:
1017  case tp_scale_log:
1018  if (!(*it)->has_caption) {
1019  p = "";
1020  }
1021  b.create_small_rackknobr(id.c_str(), p);
1022  break;
1023  case tp_toggle:
1024  if ((*it)->has_caption) {
1025  b.create_switch("switch_mid",id.c_str(), p);
1026  } else {
1027  b.create_switch_no_caption("switchit",id.c_str());
1028  }
1029  break;
1030  case tp_display:
1031  if (!(*it)->has_caption) {
1032  p = "";
1033  }
1034  b.create_port_display(id.c_str(), p);
1035  break;
1036  case tp_display_toggle:
1037  if ((*it)->has_caption) {
1038  b.create_switch("led",id.c_str(), p);
1039  } else {
1040  b.create_switch_no_caption("led",id.c_str());
1041  }
1042  break;
1043  case tp_int:
1044  if (!(*it)->has_caption) {
1045  p = "";
1046  }
1047  if (((*it)->up - (*it)->low)<200) {
1048  b.create_small_rackknob(id.c_str(), p);
1049  } else {
1050  b.create_spin_value(id.c_str(), p);
1051  }
1052  break;
1053  case tp_enum:
1054  if ((*it)->has_caption) {
1055  b.create_selector(id.c_str(), p);
1056  } else {
1057  b.create_selector_no_caption(id.c_str());
1058  }
1059  break;
1060  case tp_none:
1061  break;
1062  default:
1063  assert(false);
1064  }
1065  lilv_node_free(nm_node);
1066  }
1067  if (self.pd->add_wet_dry) {
1068  b.create_small_rackknobr(self.idd.c_str(), "dry/wet");
1069  }
1070  b.closeBox();
1071  b.closeBox();
1072  return 0;
1073 }
1074 
1075 void Lv2Dsp::del_instance(PluginDef *plugin) {
1076  delete static_cast<Lv2Dsp*>(plugin);
1077 }
1078 
1079 
1080 /****************************************************************
1081  ** class LadspaLoader
1082  */
1083 
1085  if (p->quirks & is_lv2) {
1086  return Lv2Dsp::create(p, *this);
1087  } else {
1088  return LadspaDsp::create(p);
1089  }
1090 }
1091 
1093  : options(options_),
1094  plugins(),
1095  world(lilv_world_new()),
1096  lv2_plugins(),
1097  lv2_AudioPort(lilv_new_uri(world, LV2_CORE__AudioPort)),
1098  lv2_ControlPort(lilv_new_uri(world, LV2_CORE__ControlPort)),
1099  lv2_InputPort(lilv_new_uri(world, LV2_CORE__InputPort)),
1100  lv2_OutputPort(lilv_new_uri(world, LV2_CORE__OutputPort)) {
1101  lilv_world_load_all(world);
1102  lv2_plugins = lilv_world_get_all_plugins(world);
1103  load(plugins);
1104 }
1105 
1107  for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1108  delete *i;
1109  }
1110  lilv_node_free(lv2_OutputPort);
1111  lilv_node_free(lv2_InputPort);
1112  lilv_node_free(lv2_ControlPort);
1113  lilv_node_free(lv2_AudioPort);
1114  lilv_world_free(world);
1115 }
1116 
1118  try {
1119  read_module_list(ml);
1120  } catch (JsonException &e) {
1121  gx_print_error("ladspaloader",ustring::compose(_("Exception in LADSPA list reader: %1"), e.what()));
1122  return false;
1123  }
1124  return true;
1125 }
1126 
1128  for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1129  delete *i;
1130  }
1131  plugins = new_plugins;
1132 }
1133 
1135  //for (pluginarray::iterator i = plugins.begin(); i != plugins.end(); ++i) {
1136  //delete *i;
1137  //}
1138  plugins = new_plugins;
1139 }
1140 
1141 LadspaLoader::pluginarray::iterator LadspaLoader::find(plugdesc *desc) {
1142  for (pluginarray::iterator i = begin(); i != end(); ++i) {
1143  if (desc->quirks & is_lv2) {
1144  if ((*i)->path == desc->path) {
1145  return i;
1146  }
1147  } else {
1148  if ((*i)->UniqueID == desc->UniqueID) {
1149  return i;
1150  }
1151  }
1152  }
1153  return end();
1154 }
1155 
1157  if (pdesc->quirks & is_lv2) {
1158  static_cast<Lv2Dsp*>(pdef)->set_plugdesc(pdesc);
1159  } else {
1160  static_cast<LadspaDsp*>(pdef)->set_plugdesc(pdesc);
1161  }
1162 }
1163 
1165  for (value_pair *p = values; p->value_id; ++p) {
1166  g_free(const_cast<char*>(p->value_id));
1167  }
1168  delete[] values;
1169 }
1170 
1171 void paradesc::set_valuelist(const std::vector<std::string>& v) {
1172  values = new value_pair[v.size()+1];
1173  int n = 0;
1174  for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i, ++n) {
1175  const char *p = g_strdup(i->c_str());
1176  values[n].value_id = p;
1177  values[n].value_label = p;
1178  }
1179  values[n].value_id = 0;
1180  values[n].value_label = 0;
1181 }
1182 
1183 void LadspaLoader::read_module_config(const std::string& filename, plugdesc *p) {
1184  std::ifstream ifs(filename.c_str());
1185  if (ifs.fail()) {
1186  gx_print_error("ladspaloader", ustring::compose(_("can't open %1"), filename));
1187  return;
1188  }
1189  gx_system::JsonParser jp(&ifs);
1192  jp.current_value_int(); // int version
1194  p->shortname = jp.current_value();
1196  p->category = jp.current_value();
1198  p->master_idx = jp.current_value_int();
1200  p->master_label = jp.current_value();
1202  p->quirks = jp.current_value_int();
1204  p->add_wet_dry= jp.current_value_int();
1206  while (jp.peek() != gx_system::JsonParser::end_array) {
1207  paradesc *para = new paradesc;
1210  para->index = jp.current_value_int();
1211  jp.skip_object(); // meta data
1213  para->name = jp.current_value();
1216  para->dflt = jp.current_value_float();
1218  para->low = jp.current_value_float();
1220  para->up = jp.current_value_float();
1222  para->step = jp.current_value_float();
1224  para->tp = static_cast<widget_type>(jp.current_value_int()); //FIXME (check valid)
1226  para->newrow = jp.current_value_int();
1228  para->has_caption = jp.current_value_int();
1230  std::vector<std::string> v;
1231  while (jp.peek() != gx_system::JsonParser::end_array) {
1233  v.push_back(jp.current_value());
1234  }
1236  para->set_valuelist(v);
1238  p->names.push_back(para);
1239  }
1241  jp.close();
1242  ifs.close();
1243 }
1244 
1245 void LadspaLoader::read_module_list(pluginarray& ml) {
1246  std::ifstream ifs(options.get_user_filepath("ladspa_defs.js").c_str());
1247  if (ifs.fail()) {
1248  return;
1249  }
1250  gx_system::JsonParser jp(&ifs);
1252  while (jp.peek() != gx_system::JsonParser::end_array) {
1255  plugdesc *p = new plugdesc;
1256  p->path = jp.current_value();
1258  int idx = jp.current_value_int();
1259  if (idx < 0) {
1260  p->quirks |= is_lv2;
1261  }
1262  p->index = idx;
1264  p->UniqueID = jp.current_value_int();
1266  p->Label = jp.current_value();
1268  std::string s;
1269  if (idx < 0) {
1270  s = gx_system::encode_filename(p->path) + ".js";
1271  } else {
1272  s = get_ladspa_filename(p->UniqueID);
1273  }
1274  std::string fname = options.get_plugin_filepath(s);
1275  if (access(fname.c_str(), F_OK) != 0) {
1276  fname = options.get_factory_filepath(s);
1277  if (access(fname.c_str(), F_OK) != 0) {
1278  fname = "";
1279  }
1280  }
1281  if (!fname.empty()) {
1282  try {
1283  read_module_config(fname, p);
1284  } catch (JsonException &e) {
1285  gx_print_error("ladspaloader",ustring::compose(_("read error in file %1: %2"), s, e.what()));
1286  }
1287  }
1288  if (p->quirks & is_lv2) {
1289  p->id_str = "lv2_" + gx_system::encode_filename(p->path);
1290  } else {
1291  p->id_str = "ladspa_" + to_string(p->UniqueID);
1292  }
1293  ml.push_back(p);
1294  }
1295  jp.close();
1296  ifs.close();
1297 }
1298 
1299 } // 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
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
virtual const char * what() const
Definition: gx_json.h:46
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
std::string get_user_filepath(const std::string &basename) const
Definition: gx_system.h:371
void(* create_port_display)(const char *id, const char *label)
Definition: gx_plugin.h:92
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
std::string to_string(const T &t)
Definition: gx_system.h:523
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::string get_factory_filepath(const std::string &basename) const
Definition: gx_system.h:465
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
std::string get_plugin_filepath(const std::string &basename) const
Definition: gx_system.h:464
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
void update_instance(PluginDef *pdef, plugdesc *pdesc)
pluginarray::iterator begin()
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)
string current_value() const
Definition: gx_json.h:143
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