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