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