Guitarix
gx_internal_plugins.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * --------------------------------------------------------------------------
19  *
20  *
21  * This is part of the Guitarix Audio Engine
22  *
23  *
24  *
25  * --------------------------------------------------------------------------
26  */
27 
28 #include "engine.h"
29 #include "gx_faust_support.h"
30 
31 namespace gx_engine {
32 
33 /****************************************************************
34  ** class NoiseGate
35  */
36 
37 PluginDef NoiseGate::inputdef = PluginDef();
38 float NoiseGate::fnglevel = 0;
39 float NoiseGate::ngate = 1;
40 bool NoiseGate::off = true;
43 
45 
46  inputdef.version = PLUGINDEF_VERSION;
47  inputdef.flags = PGN_SNOOP;
48  inputdef.id = "noise_gate";
49  inputdef.name = N_("Noise Gate");
50  inputdef.mono_audio = inputlevel_compute;
51  inputdef.register_params = noisegate_register;
52 
53  inputlevel.set_pdef(&inputdef);
54 
56  outputgate.id = "noiseshut";
57  outputgate.name = "?noiseshut";
58  outputgate.mono_audio = outputgate_compute;
59  outputgate.activate_plugin = outputgate_activate;
60 
61 }
62 
63 inline float sqrf(float x) {
64  return x * x;
65 }
66 
67 void NoiseGate::inputlevel_compute(int count, float *input, float *output, PluginDef*) {
68  float sumnoise = 0;
69  for (int i = 0; i < count; i++) {
70  sumnoise += sqrf(input[i]);
71  }
72  if (sumnoise/count > sqrf(fnglevel * 0.01)) {
73  ngate = 1; // -75db 0.001 = 65db
74  } else if (ngate > 0.01) {
75  ngate *= 0.996;
76  }
77 }
78 
79 int NoiseGate::noisegate_register(const ParamReg& reg) {
80  reg.registerVar("noise_gate.threshold", N_("Threshold"), "S", "", &fnglevel,
81  0.017f, 0.01f, 0.31f, 0.001f);
82  return 0;
83 }
84 
85 void NoiseGate::outputgate_compute(int count, float *input, float *output, PluginDef*) {
86  if (off) {
87  return;
88  }
89  while (count--) {
90  *output++ = ngate * *input++;
91  }
92 }
93 
94 int NoiseGate::outputgate_activate(bool start, PluginDef *pdef) {
95  if (start) {
96  off = !inputlevel.get_on_off();
97  }
98  return 0;
99 }
100 
101 
102 /****************************************************************
103  ** class GxJConvSettings
104  */
105 
107  : fIRFile(),
108  fIRDir(),
109  fGain(0),
110  fOffset(0),
111  fLength(0),
112  fDelay(0),
113  gainline(),
114  fGainCor(false) {
115 }
118  fIRFile = jcset.fIRFile;
119  fIRDir = jcset.fIRDir;
120  fGain = jcset.fGain;
121  fOffset = jcset.fOffset;
122  fLength = jcset.fLength;
123  fDelay = jcset.fDelay;
124  gainline = jcset.gainline;
125  fGainCor = jcset.fGainCor;
126  return *this;
127 }
128 
129 std::string GxJConvSettings::getFullIRPath() const {
130  if (fIRFile.empty()) {
131  return fIRFile;
132  } else {
133  return Glib::build_filename(fIRDir, fIRFile);
134  }
135 }
136 
138  fIRDir = Glib::path_get_dirname(name);
139  fIRFile= Glib::path_get_basename(name);
140 }
141 
143  w.begin_object(true);
144  w.write_kv("jconv.IRFile", fIRFile);
145  w.write_kv("jconv.IRDir", gx_system::get_options().get_IR_prefixmap().replace_path(fIRDir));
146  w.write_kv("jconv.Gain", fGain);
147  w.write_kv("jconv.GainCor", fGainCor);
148  w.write_kv("jconv.Offset", fOffset);
149  w.write_kv("jconv.Length", fLength);
150  w.write_kv("jconv.Delay", fDelay);
151  w.write_key("jconv.gainline");
152  w.begin_array();
153  for (unsigned int i = 0; i < gainline.size(); i++) {
154  w.begin_array();
155  w.write(gainline[i].i);
156  w.write(gainline[i].g);
157  w.end_array();
158  }
159  w.end_array(true);
160  w.end_object(true);
161 }
162 
164  if (fIRFile != jcset.fIRFile || fIRDir != jcset.fIRDir) {
165  return false;
166  }
167  if (fOffset != jcset.fOffset || fLength != jcset.fLength || fDelay != jcset.fDelay) {
168  return false;
169  }
170  if (fGainCor != jcset.fGainCor) {
171  return false;
172  }
173  if (fGainCor && abs(fGain - jcset.fGain) > 1e-4 * (fGain + jcset.fGain)) {
174  return false;
175  }
176  if (gainline == jcset.gainline) {
177  return false;
178  }
179  return true;
180 }
181 
182 void GxJConvSettings::read_gainline(gx_system::JsonParser& jp) {
183  gainline.clear();
185  while (jp.peek() == gx_system::JsonParser::begin_array) {
186  jp.next();
188  gain_points p;
189  p.i = jp.current_value_int();
191  p.g = jp.current_value_float();
193  gainline.push_back(p);
194  }
196 }
197 
200  do {
202  if (jp.read_kv("jconv.IRFile", fIRFile) ||
203  jp.read_kv("jconv.IRDir", fIRDir) ||
204  jp.read_kv("jconv.Gain", fGain) ||
205  jp.read_kv("jconv.GainCor", fGainCor) ||
206  jp.read_kv("jconv.Offset", fOffset) ||
207  jp.read_kv("jconv.Length", fLength) ||
208  jp.read_kv("jconv.Delay", fDelay)) {
209  } else if (jp.current_value() == "jconv.gainline") {
210  read_gainline(jp);
211  } else if (jp.current_value() == "jconv.favorits") {
212  jp.skip_object();
213  } else {
214  gx_print_warning("jconv settings", "unknown key: " + jp.current_value());
215  jp.skip_object();
216  }
217  } while (jp.peek() == gx_system::JsonParser::value_key);
219  if (!fIRFile.empty()) {
220  if (fIRDir.empty()) {
221  gx_system::get_options().get_IR_pathlist().find_dir(&fIRDir, fIRFile);
222  } else {
224  }
225  }
226 }
227 
228 
229 /****************************************************************
230  ** class JConvParameter
231  */
232 
234  : Parameter(id, "", tp_special, None, true, false),
235  json_value(),
236  value(v),
237  std_value(),
238  value_storage(),
239  changed() {
240  std_value.setFullIRPath(gx_system::get_options().get_IR_prefixmap().replace_symbol("%S/greathall.wav"));
241  std_value.fGainCor = true;
242  std_value.fGain = 0.598717;
243  const int ir_len = 112561;
244  std_value.fLength = ir_len;
245  static gain_points g[2] = {{0, 0}, {ir_len-1, 0}};
246  std_value.gainline = Gainline(g, sizeof(g) / sizeof(g[0]));
247 }
248 
250  ParamMap &pmap, const string& id, ConvolverAdapter &conv, GxJConvSettings *v) {
251  JConvParameter *p = new JConvParameter(id, conv, v);
252  pmap.insert(p);
253  return p;
254 }
255 
257 }
258 
260  : Parameter(jp_next(jp, "Parameter")),
261  searchpath(0),
262  pfx_conv(0),
263  json_value(),
264  value(&value_storage),
265  std_value() {
266  while (jp.peek() != gx_system::JsonParser::end_object) {
268  if (jp.current_value() == "value") {
269  value->readJSON(jp);
270  } else if (jp.current_value() == "std_value") {
271  std_value.readJSON(jp);
272  } else {
274  "JConvParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
275  jp.skip_object();
276  }
277  }
279 }
280 
282  jw.begin_object();
283  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
284  jw.write_key("value"); value->writeJSON(jw);
285  jw.write_key("std_value"); std_value.writeJSON(jw);
286  jw.end_object();
287 }
288 
290  assert(false);
291  return false;
292 }
293 
295  json_value = std_value;
296 }
297 
299  jw.write_key(_id.c_str());
300  value->writeJSON(jw);
301 }
302 
304  json_value.readJSON(jp);
305 }
306 
308  return json_value == *value;
309 }
310 
311 bool JConvParameter::set(const GxJConvSettings& val) const {
312  if (val == *value) {
313  return false;
314  }
315  *value = val;
316  changed(value);
317  return true;
318 }
319 
321  set(json_value);
322 }
323 
324 
325 /****************************************************************
326  ** class ConvolverAdapter
327  */
328 
329 #include "faust/jconv_post.cc"
330 #include "faust/jconv_post_mono.cc"
331 
333  EngineControl& engine_, sigc::slot<void> sync_, ParamMap& param_)
334  : PluginDef(),
335  conv(),
336  activate_mutex(),
337  engine(engine_),
338  sync(sync_),
339  param(param_),
340  activated(false),
341  jcset(),
342  jcp(0),
343  plugin() {
345  category = N_("Reverb");
346  //FIXME: add clear_state
347  plugin = this;
349  sigc::mem_fun(*this, &ConvolverAdapter::change_buffersize));
350 }
351 
353 }
354 
355 void ConvolverAdapter::change_buffersize(unsigned int size) {
356  boost::mutex::scoped_lock lock(activate_mutex);
357  if (activated) {
358  conv.stop_process();
359  while (conv.is_runnable()) {
360  conv.checkstate();
361  }
362  conv.set_buffersize(size);
363  if (size) {
364  conv_start();
365  }
366  } else {
367  conv.set_buffersize(size);
368  }
369 }
370 
372  if (!plugin.get_on_off()) {
373  return;
374  }
375  conv.set_not_runnable();
376  sync();
377  conv.stop_process();
378  while (!conv.checkstate());
379  float gain;
380  if (jcset.getGainCor()) {
381  gain = jcset.getGain();
382  } else {
383  gain = 1.0;
384  }
385  bool rc = conv.configure(
386  jcset.getFullIRPath(), gain, gain, jcset.getDelay(), jcset.getDelay(),
388  int policy, priority;
389  engine.get_sched_priority(policy, priority);
390  if (!rc || !conv.start(policy, priority)) {
391  plugin.set_on_off(false);
392  }
393 }
394 
396  if (!conv.get_buffersize() || !conv.get_samplerate()) {
397  return false;
398  }
399  string path = jcset.getFullIRPath();
400  if (path.empty()) {
401  gx_print_warning(_("convolver"), _("no impulseresponse file"));
402  plugin.set_on_off(false);
403  return false;
404  }
405  while (!conv.checkstate());
406  if (conv.is_runnable()) {
407  return true;
408  }
409  float gain;
410  if (jcset.getGainCor()) {
411  gain = jcset.getGain();
412  } else {
413  gain = 1.0;
414  }
415  if (!conv.configure(
416  path, gain, gain, jcset.getDelay(), jcset.getDelay(),
417  jcset.getOffset(), jcset.getLength(), 0, 0, jcset.getGainline())) {
418  return false;
419  }
420  int policy, priority;
421  engine.get_sched_priority(policy, priority);
422  return conv.start(policy, priority);
423 }
424 
425 
426 /****************************************************************
427  ** class ConvolverStereoAdapter
428  */
429 
431  EngineControl& engine_, sigc::slot<void> sync_, ParamMap& param_)
432  : ConvolverAdapter(engine_, sync_, param_) {
433  id = "jconv";
434  name = N_("Convolver");
435  register_params = convolver_register;
436  set_samplerate = convolver_init;
437  activate_plugin = activate;
438  stereo_audio = convolver;
439 }
440 
442 }
443 
444 void ConvolverStereoAdapter::convolver(int count, float *input0, float *input1,
445  float *output0, float *output1, PluginDef* plugin) {
446  ConvolverStereoAdapter& self = *static_cast<ConvolverStereoAdapter*>(plugin);
447  if (self.conv.is_runnable()) {
448  float conv_out0[count];
449  float conv_out1[count];
450  if (self.conv.compute(count, input0, input1, conv_out0, conv_out1)) {
451  self.jc_post.compute(count, input0, input1,
452  conv_out0, conv_out1, output0, output1);
453  return;
454  }
455  self.engine.overload(EngineControl::ov_Convolver, self.id);
456  }
457  if (input0 != output0) {
458  memcpy(output0, input0, count * sizeof(float));
459  }
460  if (input1 != output1) {
461  memcpy(output1, input1, count * sizeof(float));
462  }
463 }
464 
465 int ConvolverStereoAdapter::convolver_register(const ParamReg& reg) {
466  ConvolverStereoAdapter& self = *static_cast<ConvolverStereoAdapter*>(reg.plugin);
467  self.jcp = JConvParameter::insert_param(self.param, "jconv.convolver", self, &self.jcset);
468  self.jcp->signal_changed().connect(
469  sigc::hide(
470  sigc::mem_fun(self, &ConvolverStereoAdapter::restart)));
471  return self.jc_post.register_par(reg);
472 }
473 
474 void ConvolverStereoAdapter::convolver_init(unsigned int samplingFreq, PluginDef *p) {
475  ConvolverStereoAdapter& self = *static_cast<ConvolverStereoAdapter*>(p);
476  boost::mutex::scoped_lock lock(self.activate_mutex);
477  if (self.activated) {
478  self.conv.stop_process();
479  self.conv.set_samplerate(samplingFreq);
480  self.jc_post.init(samplingFreq);
481  while (self.conv.is_runnable()) {
482  self.conv.checkstate();
483  }
484  self.conv_start();
485  } else {
486  self.conv.set_samplerate(samplingFreq);
487  self.jc_post.init(samplingFreq);
488  }
489 }
490 
491 int ConvolverStereoAdapter::activate(bool start, PluginDef *p) {
492  ConvolverStereoAdapter& self = *static_cast<ConvolverStereoAdapter*>(p);
493  boost::mutex::scoped_lock lock(self.activate_mutex);
494  if (start) {
495  if (self.activated && self.conv.is_runnable()) {
496  return 0;
497  }
498  } else {
499  if (!self.activated) {
500  return 0;
501  }
502  }
503  self.activated = start;
504  if (start) {
505  if (self.jc_post.activate(true) != 0) {
506  gx_print_error(_("convolver"), "jconv post activate error?!");
507  return -1;
508  }
509  if (!self.conv_start()) {
510  return -1;
511  }
512  } else {
513  self.conv.stop_process();
514  self.jc_post.activate(false);
515  }
516  return 0;
517 }
518 
519 
520 /****************************************************************
521  ** class ConvolverMonoAdapter
522  */
523 
525  EngineControl& engine_, sigc::slot<void> sync_, ParamMap& param_)
526  : ConvolverAdapter(engine_, sync_, param_) {
527  id = "jconv_mono";
528  name = N_("Convolver");
529  register_params = convolver_register;
530  set_samplerate = convolver_init;
531  activate_plugin = activate;
532  mono_audio = convolver;
533 }
534 
536 }
537 
538 void ConvolverMonoAdapter::convolver(int count, float *input, float *output, PluginDef* plugin) {
539  ConvolverMonoAdapter& self = *static_cast<ConvolverMonoAdapter*>(plugin);
540  if (self.conv.is_runnable()) {
541  float conv_out[count];
542  if (self.conv.compute(count, input, conv_out)) {
543  self.jc_post_mono.compute(count, output, conv_out, output);
544  return;
545  }
546  self.engine.overload(EngineControl::ov_Convolver, self.id);
547  }
548  if (input != output) {
549  memcpy(output, input, count * sizeof(float));
550  }
551 }
552 
553 int ConvolverMonoAdapter::convolver_register(const ParamReg& reg) {
554  ConvolverMonoAdapter& self = *static_cast<ConvolverMonoAdapter*>(reg.plugin);
555  self.jcp = JConvParameter::insert_param(self.param, "jconv_mono.convolver", self, &self.jcset);
556  self.jcp->signal_changed().connect(
557  sigc::hide(
558  sigc::mem_fun(self, &ConvolverMonoAdapter::restart)));
559  return self.jc_post_mono.register_par(reg);;
560 }
561 
562 void ConvolverMonoAdapter::convolver_init(unsigned int samplingFreq, PluginDef *p) {
563  ConvolverMonoAdapter& self = *static_cast<ConvolverMonoAdapter*>(p);
564  boost::mutex::scoped_lock lock(self.activate_mutex);
565  if (self.activated) {
566  self.conv.stop_process();
567  self.conv.set_samplerate(samplingFreq);
568  while (self.conv.is_runnable()) {
569  self.conv.checkstate();
570  }
571  self.conv_start();
572  } else {
573  self.conv.set_samplerate(samplingFreq);
574  }
575 }
576 
577 int ConvolverMonoAdapter::activate(bool start, PluginDef *p) {
578  ConvolverMonoAdapter& self = *static_cast<ConvolverMonoAdapter*>(p);
579  boost::mutex::scoped_lock lock(self.activate_mutex);
580  if (start) {
581  if (self.activated && self.conv.is_runnable()) {
582  return 0;
583  }
584  } else {
585  if (!self.activated) {
586  return 0;
587  }
588  }
589  self.activated = start;
590  if (start) {
591  if (!self.conv_start()) {
592  return -1;
593  }
594  } else {
595  self.conv.stop_process();
596  }
597  return 0;
598 }
599 
600 /****************************************************************
601  ** class BaseConvolver
602  */
603 
604 
606  : PluginDef(),
607  conv(resamp),
608  activate_mutex(),
609  engine(engine_),
610  sync(sync_),
611  activated(false),
612  plugin() {
616  plugin = this;
618  sigc::mem_fun(*this, &BaseConvolver::change_buffersize));
619 }
620 
622  update_conn.disconnect();
623 }
624 
625 void BaseConvolver::change_buffersize(unsigned int bufsize) {
626  boost::mutex::scoped_lock lock(activate_mutex);
627  conv.set_buffersize(bufsize);
628  if (activated) {
629  if (!bufsize) {
630  conv.stop_process();
631  } else {
632  start(true);
633  }
634  }
635 }
636 
637 void BaseConvolver::init(unsigned int samplingFreq, PluginDef *p) {
638  BaseConvolver& self = *static_cast<BaseConvolver*>(p);
639  boost::mutex::scoped_lock lock(self.activate_mutex);
640  self.conv.set_samplerate(samplingFreq);
641  if (self.activated) {
642  self.start(true);
643  }
644 }
645 
647  if (!activated || !plugin.get_on_off()) {
648  return false;
649  }
650  check_update();
651  return true;
652 }
653 
654 int BaseConvolver::activate(bool start, PluginDef *p) {
655  BaseConvolver& self = *static_cast<BaseConvolver*>(p);
656  boost::mutex::scoped_lock lock(self.activate_mutex);
657  if (start) {
658  if (!self.conv.get_buffersize()) {
659  start = false;
660  }
661  }
662  if (start == self.activated) {
663  return 0;
664  }
665  if (start) {
666  if (!self.start()) {
667  return -1;
668  }
669  self.update_conn = Glib::signal_timeout().connect(
670  sigc::mem_fun(self, &BaseConvolver::check_update_timeout), 200);
671  } else {
672  self.conv.stop_process();
673  }
674  self.activated = start;
675  return 0;
676 }
677 
679  int policy, priority;
680  engine.get_sched_priority(policy, priority);
681  return conv.start(policy, priority);
682 }
683 
684 /****************************************************************
685  ** class CabinetConvolver
686  */
687 
688 struct CabDesc {
689  int ir_count;
690  int ir_sr;
691  float ir_data[];
692 };
693 
694 template <int tab_size>
695 struct CabDesc_imp {
696  int ir_count;
697  int ir_sr;
698  float ir_data[tab_size];
699  operator CabDesc&() { return *(CabDesc*)this; }
700 };
701 
702 #include "gx_cabinet_data.cc"
703 
704 struct CabEntry {
705  const char *value_id;
706  const char *value_label;
708 } cab_table[] = {
709  { "4x12", N_("4x12"), &static_cast<CabDesc&>(cab_data_4x12) },
710  { "2x12", N_("2x12"), &static_cast<CabDesc&>(cab_data_2x12) },
711  { "1x12", N_("1x12"), &static_cast<CabDesc&>(cab_data_1x12) },
712  { "4x10", N_("4x10"), &static_cast<CabDesc&>(cab_data_4x10) },
713  { "2x10", N_("2x10"), &static_cast<CabDesc&>(cab_data_2x10) },
714  { "HighGain", N_("HighGain Style"), &static_cast<CabDesc&>(cab_data_HighGain) },
715  { "Twin", N_("Twin Style"), &static_cast<CabDesc&>(cab_data_Twin) },
716  { "Bassman", N_("Bassman Style"), &static_cast<CabDesc&>(cab_data_Bassman) },
717  { "Marshall", N_("Marshall Style"), &static_cast<CabDesc&>(cab_data_Marshall) },
718  { "AC-30", N_("AC-30 Style"), &static_cast<CabDesc&>(cab_data_AC30) },
719  { "Princeton", N_("Princeton Style"), &static_cast<CabDesc&>(cab_data_Princeton) },
720  { "A2", N_("A2 Style"), &static_cast<CabDesc&>(cab_data_A2) },
721  { "1x15", N_("1x15"), &static_cast<CabDesc&>(cab_data_1x15) },
722  { "Mesa Boogie", N_("Mesa Boogie Style"), &static_cast<CabDesc&>(cab_data_mesa) },
723  { "Briliant", N_("Briliant"), &static_cast<CabDesc&>(cab_data_briliant) },
724  { "Vitalize", N_("Vitalize"), &static_cast<CabDesc&>(cab_data_vitalize) },
725  { "Charisma", N_("Charisma"), &static_cast<CabDesc&>(cab_data_charisma) },
726 };
727 static const unsigned int cab_table_size = sizeof(cab_table) / sizeof(cab_table[0]);
728 
729 static CabEntry& getCabEntry(unsigned int n) {
730  if (n >= cab_table_size) {
731  n = cab_table_size - 1;
732  }
733  return cab_table[n];
734 }
735 
736 static const float no_sum = 1e10;
737 
738 #include "faust/cabinet_impulse_former.cc"
739 
740 static int cab_load_ui(const UiBuilder& builder, int format) {
741  if (format & UI_FORM_GLADE) {
742  builder.load_glade_file("cabinet_ui.glade");
743  return 0;
744  } else if (format & UI_FORM_STACK) {
745  builder.openHorizontalhideBox("");
746  builder.create_selector_no_caption("cab.select");
747  builder.closeBox();
748  builder.openVerticalBox("");
749  {
750  builder.openHorizontalBox("");
751  {
752  builder.insertSpacer();
753  builder.create_selector_no_caption("cab.select");
754  builder.create_small_rackknobr("cab.bass", "Bass");
755  builder.create_small_rackknobr("cab.treble", "Treble");
756  builder.create_mid_rackknob("cab.Level", "Level");
757  }
758  builder.closeBox();
759  }
760  builder.closeBox();
761  return 0;
762  } else {
763  return -1;
764  }
765 
766 }
767 
769  BaseConvolver(engine, sync, resamp),
770  current_cab(-1),
771  level(0),
772  cabinet(0),
773  bass(0),
774  treble(0),
775  sum(no_sum),
776  cab_names(new value_pair[cab_table_size+1]),
777  impf() {
778  for (unsigned int i = 0; i < cab_table_size; ++i) {
779  CabEntry& cab = getCabEntry(i);
780  cab_names[i].value_id = cab.value_id;
781  cab_names[i].value_label = cab.value_label;
782  }
783  cab_names[cab_table_size].value_id = 0;
784  cab_names[cab_table_size].value_label = 0;
785  id = "cab";
786  name = N_("Cabinet");
787  category = N_("Tone Control");
788  load_ui = cab_load_ui;
789  mono_audio = run_cab_conf;
790  register_params = register_cab;
791 }
792 
794  delete[] cab_names;
795 }
796 
797 bool CabinetConvolver::do_update() {
798  bool configure = cabinet_changed();
799  if (conv.is_runnable()) {
800  conv.set_not_runnable();
801  sync();
802  conv.stop_process();
803  }
804  CabDesc& cab = *getCabEntry(cabinet).data;
805  if (current_cab == -1) {
806  impf.init(cab.ir_sr);
807  }
808  float cab_irdata_c[cab.ir_count];
809  impf.clear_state_f();
810  impf.compute(cab.ir_count,cab.ir_data,cab_irdata_c);
811  while (!conv.checkstate());
812  if (configure) {
813  if (!conv.configure(cab.ir_count, cab_irdata_c, cab.ir_sr)) {
814  return false;
815  }
816  } else {
817  if (!conv.update(cab.ir_count, cab_irdata_c, cab.ir_sr)) {
818  return false;
819  }
820  }
821  update_cabinet();
822  update_sum();
823  return conv_start();
824 }
825 
826 bool CabinetConvolver::start(bool force) {
827  if (force) {
828  current_cab = -1;
829  }
830  if (cabinet_changed() || sum_changed()) {
831  return do_update();
832  } else {
833  while (!conv.checkstate());
834  if (!conv.is_runnable()) {
835  return conv_start();
836  }
837  return true;
838  }
839 }
840 
841 void CabinetConvolver::check_update() {
842  if (cabinet_changed() || sum_changed()) {
843  do_update();
844  }
845 }
846 
847 void CabinetConvolver::run_cab_conf(int count, float *input0, float *output0, PluginDef *p) {
848  CabinetConvolver& self = *static_cast<CabinetConvolver*>(p);
849  if (!self.conv.compute(count,output0)) {
851  }
852 }
853 
854 int CabinetConvolver::register_cab(const ParamReg& reg) {
855  CabinetConvolver& cab = *static_cast<CabinetConvolver*>(reg.plugin);
856  reg.registerIEnumVar("cab.select", "select", "B", "", cab.cab_names, &cab.cabinet, 0);
857  reg.registerVar("cab.Level", N_("Level"), "S", N_("Level"), &cab.level, 1.0, 0.5, 5.0, 0.5);
858  reg.registerVar("cab.bass", N_("Bass"), "S", N_("Bass"), &cab.bass, 0.0, -10.0, 10.0, 0.5);
859  reg.registerVar("cab.treble", N_("Treble"), "S", N_("Treble"), &cab.treble, 0.0, -10.0, 10.0, 0.5);
860  cab.impf.register_par(reg);
861  return 0;
862 }
863 
865 
866 static int cab_load_stereo_ui(const UiBuilder& builder, int format) {
867  if (format & UI_FORM_GLADE) {
868  builder.load_glade_file("cabinet_stereo_ui.glade");
869  return 0;
870  } else if (format & UI_FORM_STACK) {
871  builder.openHorizontalhideBox("");
872  builder.create_selector_no_caption("cab_st.select");
873  builder.closeBox();
874  builder.openVerticalBox("");
875  {
876  builder.openHorizontalBox("");
877  {
878  builder.insertSpacer();
879  builder.create_selector_no_caption("cab_st.select");
880  builder.create_small_rackknobr("cab_st.bass", "Bass");
881  builder.create_small_rackknobr("cab_st.treble", "Treble");
882  builder.create_mid_rackknob("cab_st.Level", "Level");
883  }
884  builder.closeBox();
885  }
886  builder.closeBox();
887  return 0;
888  } else {
889  return -1;
890  }
891 
892 }
893 
895  BaseConvolver(engine, sync, resamp),
896  current_cab(-1),
897  level(0),
898  cabinet(0),
899  bass(0),
900  treble(0),
901  sum(no_sum),
902  cab_names(new value_pair[cab_table_size+1]),
903  impf() {
904  for (unsigned int i = 0; i < cab_table_size; ++i) {
905  CabEntry& cab = getCabEntry(i);
906  cab_names[i].value_id = cab.value_id;
907  cab_names[i].value_label = cab.value_label;
908  }
909  cab_names[cab_table_size].value_id = 0;
910  cab_names[cab_table_size].value_label = 0;
911  id = "cab_st";
912  name = N_("Cabinet");
913  category = N_("Tone Control");
914  load_ui = cab_load_stereo_ui;
915  stereo_audio = run_cab_conf;
916  register_params = register_cab;
917 }
918 
920  delete[] cab_names;
921 }
922 
923 bool CabinetStereoConvolver::do_update() {
924  bool configure = cabinet_changed();
925  if (conv.is_runnable()) {
926  conv.set_not_runnable();
927  sync();
928  conv.stop_process();
929  }
930  CabDesc& cab = *getCabEntry(cabinet).data;
931  if (current_cab == -1) {
932  impf.init(cab.ir_sr);
933  }
934  float cab_irdata_c[cab.ir_count];
935  impf.clear_state_f();
936  impf.compute(cab.ir_count,cab.ir_data,cab_irdata_c);
937  while (!conv.checkstate());
938  if (configure) {
939  if (!conv.configure_stereo(cab.ir_count, cab_irdata_c, cab.ir_sr)) {
940  return false;
941  }
942  } else {
943  if (!conv.update_stereo(cab.ir_count, cab_irdata_c, cab.ir_sr)) {
944  return false;
945  }
946  }
947  update_cabinet();
948  update_sum();
949  return conv_start();
950 }
951 
952 bool CabinetStereoConvolver::start(bool force) {
953  if (force) {
954  current_cab = -1;
955  }
956  if (cabinet_changed() || sum_changed()) {
957  return do_update();
958  } else {
959  while (!conv.checkstate());
960  if (!conv.is_runnable()) {
961  return conv_start();
962  }
963  return true;
964  }
965 }
966 
967 void CabinetStereoConvolver::check_update() {
968  if (cabinet_changed() || sum_changed()) {
969  do_update();
970  }
971 }
972 
973 void CabinetStereoConvolver::run_cab_conf(int count, float *input0, float *input1, float *output0, float *output1, PluginDef *p) {
974  CabinetStereoConvolver& self = *static_cast<CabinetStereoConvolver*>(p);
975  if (!self.conv.compute_stereo(count,output0,output1)) {
977  }
978 }
979 
980 int CabinetStereoConvolver::register_cab(const ParamReg& reg) {
981  CabinetStereoConvolver& cab = *static_cast<CabinetStereoConvolver*>(reg.plugin);
982  reg.registerIEnumVar("cab_st.select", "select", "B", "", cab.cab_names, &cab.cabinet, 0);
983  reg.registerVar("cab_st.Level", N_("Level"), "S", N_("Level"), &cab.level, 1.0, 0.5, 5.0, 0.5);
984  reg.registerVar("cab_st.bass", N_("Bass"), "S", N_("Bass"), &cab.bass, 0.0, -10.0, 10.0, 0.5);
985  reg.registerVar("cab_st.treble", N_("Treble"), "S", N_("Treble"), &cab.treble, 0.0, -10.0, 10.0, 0.5);
986  cab.impf.register_par(reg);
987  return 0;
988 }
989 
990 /****************************************************************
991  ** class PreampConvolver
992  */
993 
994 struct PreDesc {
995  int ir_count;
996  int ir_sr;
997  float ir_data[];
998 };
999 
1000 template <int tab_size>
1001 struct PreDesc_imp {
1003  int ir_sr;
1004  float ir_data[tab_size];
1005  operator PreDesc&() { return *(PreDesc*)this; }
1006 };
1007 
1008 #include "gx_preamp_data.cc"
1009 
1010 struct PreEntry {
1011  const char *value_id;
1012  const char *value_label;
1014 } pre_table[] = {
1015  { "AC30", N_("AC30 Style"), &static_cast<PreDesc&>(pre_data_ac30) },
1016  { "Bassman", N_("Bassman Style"), &static_cast<PreDesc&>(pre_data_bassman) },
1017  { "Tube", N_("Tube Style"), &static_cast<PreDesc&>(pre_data_tube) },
1018  { "Fender", N_("Fender Style"), &static_cast<PreDesc&>(pre_data_fender) },
1019  { "JCM800", N_("JCM800 Style"), &static_cast<PreDesc&>(pre_data_jcm800) },
1020  { "JTM45", N_("JTM45 Style"), &static_cast<PreDesc&>(pre_data_jtm45) },
1021  { "Mesa Boogie", N_("Mesa Boogie Style"), &static_cast<PreDesc&>(pre_data_mesaboogie) },
1022  { "Boutique", N_("Boutique Style"), &static_cast<PreDesc&>(pre_data_boutique) },
1023  { "Ampeg", N_("Ampeg Style"), &static_cast<PreDesc&>(pre_data_ampeg) },
1024  { "Rectifier", N_("Rectifier Style"), &static_cast<PreDesc&>(pre_data_rectifier) },
1025 };
1026 static const unsigned int pre_table_size = sizeof(pre_table) / sizeof(pre_table[0]);
1027 
1028 static PreEntry& getPreEntry(unsigned int n) {
1029  if (n >= pre_table_size) {
1030  n = pre_table_size - 1;
1031  }
1032  return pre_table[n];
1033 }
1034 
1035 #include "faust/preamp_impulse_former.cc"
1036 
1037 static int pre_load_ui(const UiBuilder& builder, int format) {
1038  if (format & UI_FORM_GLADE) {
1039  builder.load_glade_file("ampimpulse_ui.glade");
1040  return 0;
1041  } else if (format & UI_FORM_STACK) {
1042  builder.openHorizontalhideBox("");
1043  builder.create_selector_no_caption("pre.select");
1044  builder.closeBox();
1045  builder.openVerticalBox("");
1046  {
1047  builder.openHorizontalBox("");
1048  {
1049  builder.insertSpacer();
1050  builder.create_selector_no_caption("pre.select");
1051  builder.create_small_rackknobr("pre.bass", "Bass");
1052  builder.create_small_rackknobr("pre.treble", "Treble");
1053  builder.create_mid_rackknob("pre.Level", "Level");
1054  }
1055  builder.closeBox();
1056  }
1057  builder.closeBox();
1058  return 0;
1059  } else {
1060  return -1;
1061  }
1062 
1063 }
1064 
1066  BaseConvolver(engine, sync, resamp),
1067  current_pre(-1),
1068  level(0),
1069  preamp(0),
1070  bass(0),
1071  treble(0),
1072  sum(no_sum),
1073  pre_names(new value_pair[pre_table_size+1]),
1074  impf() {
1075  for (unsigned int i = 0; i < pre_table_size; ++i) {
1076  PreEntry& pre = getPreEntry(i);
1077  pre_names[i].value_id = pre.value_id;
1078  pre_names[i].value_label = pre.value_label;
1079  }
1080  pre_names[pre_table_size].value_id = 0;
1081  pre_names[pre_table_size].value_label = 0;
1082  id = "pre";
1083  name = N_("Amp Impulse");
1084  category = N_("Tone Control");
1085  load_ui = pre_load_ui;
1086  mono_audio = run_pre_conf;
1087  register_params = register_pre;
1088 }
1089 
1091  delete[] pre_names;
1092 }
1093 
1094 bool PreampConvolver::do_update() {
1095  bool configure = preamp_changed();
1096  if (conv.is_runnable()) {
1097  conv.set_not_runnable();
1098  sync();
1099  conv.stop_process();
1100  }
1101  PreDesc& pre = *getPreEntry(preamp).data;
1102  if (current_pre == -1) {
1103  impf.init(pre.ir_sr);
1104  }
1105  float pre_irdata_c[pre.ir_count];
1106  impf.clear_state_f();
1107  impf.compute(pre.ir_count,pre.ir_data,pre_irdata_c);
1108  while (!conv.checkstate());
1109  if (configure) {
1110  if (!conv.configure(pre.ir_count, pre_irdata_c, pre.ir_sr)) {
1111  return false;
1112  }
1113  } else {
1114  if (!conv.update(pre.ir_count, pre_irdata_c, pre.ir_sr)) {
1115  return false;
1116  }
1117  }
1118  update_preamp();
1119  update_sum();
1120  return conv_start();
1121 }
1122 
1123 bool PreampConvolver::start(bool force) {
1124  if (force) {
1125  current_pre = -1;
1126  }
1127  if (preamp_changed() || sum_changed()) {
1128  return do_update();
1129  } else {
1130  while (!conv.checkstate());
1131  if (!conv.is_runnable()) {
1132  return conv_start();
1133  }
1134  return true;
1135  }
1136 }
1137 
1138 void PreampConvolver::check_update() {
1139  if (preamp_changed() || sum_changed()) {
1140  do_update();
1141  }
1142 }
1143 
1144 void PreampConvolver::run_pre_conf(int count, float *input0, float *output0, PluginDef *p) {
1145  PreampConvolver& self = *static_cast<PreampConvolver*>(p);
1146  if (!self.conv.compute(count, output0)) {
1148  }
1149 }
1150 
1151 int PreampConvolver::register_pre(const ParamReg& reg) {
1152  PreampConvolver& pre = *static_cast<PreampConvolver*>(reg.plugin);
1153  reg.registerIEnumVar("pre.select", "select", "B", "", pre.pre_names, &pre.preamp, 0);
1154  reg.registerVar("pre.Level", N_("Level"), "S", N_("Level"), &pre.level, 1.0, 0.1, 2.1, 0.1);
1155  reg.registerVar("pre.bass", N_("Bass"), "S", N_("Bass"), &pre.bass, 0.0, -10.0, 10.0, 0.5);
1156  reg.registerVar("pre.treble", N_("Treble"), "S", N_("Treble"), &pre.treble, 0.0, -10.0, 10.0, 0.5);
1157  pre.impf.register_par(reg);
1158  return 0;
1159 }
1160 
1161 /****************************************************************
1162  ** class ContrastConvolver
1163  */
1164 
1165 #include "faust/presence_level.cc"
1166 
1168  BaseConvolver(engine, sync, resamp),
1169  level(0),
1170  sum(no_sum),
1171  presl() {
1172  id = "con";
1173  name = N_("Contrast convolver");
1174  mono_audio = run_contrast;
1175  register_params = register_con;
1176 }
1177 
1179 }
1180 
1181 bool ContrastConvolver::do_update() {
1182  bool configure = (sum == no_sum);
1183  if (conv.is_runnable()) {
1184  conv.set_not_runnable();
1185  sync();
1186  conv.stop_process();
1187  }
1188  if (configure) {
1189  presl.init(contrast_ir_desc.ir_sr);
1190  }
1191  float contrast_irdata_c[contrast_ir_desc.ir_count];
1192  presl.compute(contrast_ir_desc.ir_count,contrast_ir_desc.ir_data,contrast_irdata_c);
1193  while (!conv.checkstate());
1194  if (configure) {
1195  if (!conv.configure(contrast_ir_desc.ir_count, contrast_irdata_c, contrast_ir_desc.ir_sr)) {
1196  return false;
1197  }
1198  } else {
1199  if (!conv.update(contrast_ir_desc.ir_count, contrast_irdata_c, contrast_ir_desc.ir_sr)) {
1200  return false;
1201  }
1202  }
1203  update_sum();
1204  return conv_start();
1205 }
1206 
1207 bool ContrastConvolver::start(bool force) {
1208  if (force) {
1209  sum = no_sum;
1210  }
1211  if (sum_changed()) {
1212  return do_update();
1213  } else {
1214  while (!conv.checkstate());
1215  if (!conv.is_runnable()) {
1216  return conv_start();
1217  }
1218  return true;
1219  }
1220 }
1221 
1222 void ContrastConvolver::check_update() {
1223  if (sum_changed()) {
1224  do_update();
1225  }
1226 }
1227 
1228 int ContrastConvolver::register_con(const ParamReg& reg) {
1229  ContrastConvolver& self = *static_cast<ContrastConvolver*>(reg.plugin);
1230  reg.registerVar("con.Level", "", "S", "", &self.level, 1.0, 0.5, 5.0, 0.5);
1231  self.presl.register_par(reg);
1232  return 0;
1233 }
1234 
1235 void ContrastConvolver::run_contrast(int count, float *input0, float *output0, PluginDef *p) {
1236  ContrastConvolver& self = *static_cast<ContrastConvolver*>(p);
1237  if (!self.conv.compute(count,output0)) {
1238  self.engine.overload(EngineControl::ov_Convolver, "contrast");
1239  }
1240 }
1241 
1242 /****************************************************************
1243  ** class smbPitchShift
1244  */
1245 
1246 #include "gx_livelooper.cc"
1247 
1248 /****************************************************************
1249  ** class SCapture
1250  */
1251 
1252 #include "gx_record.cc"
1253 
1254 
1255 /****************************************************************************
1256 *
1257 * NAME: smbPitchShift.cpp
1258 * VERSION: 1.2
1259 * HOME URL: http://www.dspdimension.com
1260 * KNOWN BUGS: none
1261 *
1262 *
1263 * COPYRIGHT 1999-2009 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
1264 *
1265 * Modified for guitarix by Hermann Meyer 2014
1266 *
1267 * The Wide Open License (WOL)
1268 *
1269 * Permission to use, copy, modify, distribute and sell this software and its
1270 * documentation for any purpose is hereby granted without fee, provided that
1271 * the above copyright notice and this license appear in all source copies.
1272 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
1273 * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
1274 *
1275 *****************************************************************************/
1276 
1277 bool smbPitchShift::setParameters(int sampleRate_)
1278 {
1279  numSampsToProcess = int(engine.get_buffersize());
1280  fftFrameSize = numSampsToProcess/4;
1281  sampleRate = int(sampleRate_);
1282  assert(sampleRate>0);
1283  osamp = 8;
1284  osamp1 = 1./osamp;
1285  osamp2 = 2.*M_PI*osamp1;
1286  mpi = (1./(2.*M_PI)) * osamp;
1287  mpi1 = 1./M_PI;
1288  fpb = 0;
1289  expect = 0;
1290  hanning = 0;
1291  hanningd = 0;
1292  resampin = 0;
1293  resampout = 0;
1294  indata2 = 0;
1295  resamp.setup(sampleRate,4);
1296  gRover = inFifoLatency;
1297  return true;
1298 }
1299 
1300 smbPitchShift::smbPitchShift(ParamMap& param_, EngineControl& engine_, sigc::slot<void> sync_):
1301  PluginDef(),
1302  engine(engine_),
1303  mem_allocated(false),
1304  sync(sync_),
1305  ready(false),
1306  param(param_),
1307  ftPlanForward(0),
1308  ftPlanInverse(0),
1309  plugin() {
1310  memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
1311  memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
1312  memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
1313  memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
1314  memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
1315  memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));
1316  memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));
1318  id = "smbPitchShift";
1319  name = N_("Detune");
1320  groups = 0;
1321  description = N_("detune and pitch shift up"); // description (tooltip)
1322  category = N_("Misc"); // category
1323  mono_audio = compute_static;
1324  stereo_audio = 0;
1325  set_samplerate = init;
1326  activate_plugin = activate_static;
1327  register_params = registerparam;
1328  delete_instance = del_instance;
1329  load_ui = load_ui_f_static;
1330  plugin = this;
1331  engine.signal_buffersize_change().connect(
1332  sigc::mem_fun(*this, &smbPitchShift::change_buffersize));
1333 }
1334 
1335 void smbPitchShift::init(unsigned int samplingFreq, PluginDef *plugin) {
1336  static_cast<smbPitchShift*>(plugin)->setParameters(samplingFreq);
1337 
1338 }
1339 
1340 void smbPitchShift::clear_state()
1341 {
1342  stepSize = fftFrameSize/osamp;
1343  freqPerBin = (double)(sampleRate/4)/(double)fftFrameSize;
1344  freqPerBin1 = (1/freqPerBin)*osamp2;
1345  freqPerBin2 = freqPerBin*mpi;
1346  expct = 2.*M_PI*(double)stepSize/(double)fftFrameSize;
1347  inFifoLatency = fftFrameSize-stepSize;
1348  fftFrameSize3 = 2. * (1./ ((double)(fftFrameSize2)*osamp));
1349  fftFrameSize4 = 1./(double)fftFrameSize;
1350  ai = 0;
1351  aio = 0;
1352  ii = 0;
1353  tone =0;
1354  memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
1355  memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
1356  memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
1357  memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
1358  memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
1359  memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));
1360  memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));
1361  for (k = 0; k < fftFrameSize2;k++) {
1362  fpb[k] = (double)k*freqPerBin;
1363  }
1364  for (k = 0; k < fftFrameSize2;k++) {
1365  expect[k] = (double)k*expct;
1366  }
1367  for (k = 0; k < fftFrameSize;k++) {
1368  hanning[k] = 0.5*(1-cos(2.*M_PI*(double)k/((double)fftFrameSize)));
1369  }
1370  for (k = 0; k < fftFrameSize;k++) {
1371  hanningd[k] = 0.5*(1-cos(2.*M_PI*(double)k * fftFrameSize4)) * fftFrameSize3;
1372  }
1373  for (k = 0; k < fftFrameSize;k++) {
1374  resampin[k] = 0.0;
1375  }
1376  for (k = 0; k < fftFrameSize;k++) {
1377  resampin2[k] = 0.0;
1378  }
1379  for (k = 0; k < fftFrameSize*4;k++) {
1380  resampout[k] = 0.0;
1381  }
1382  for (k = 0; k < fftFrameSize*4;k++) {
1383  indata2[k] = 0.0;
1384  }
1385  gRover = inFifoLatency;
1386  mem_allocated = true;
1387  ready = true;
1388 }
1389 
1390 void smbPitchShift::mem_alloc()
1391 {
1392  numSampsToProcess = int(engine.get_buffersize());
1393  assert(numSampsToProcess>0);
1394  numSampsToResamp = numSampsToProcess/4;
1395  sampleRate = int(engine.get_samplerate());
1396  assert(sampleRate>0);
1397 
1398  switch(latency) {
1399  case(0):
1400  if (numSampsToProcess <= 2048) {
1401  fftFrameSize = 512 ;
1402  } else {
1403  fftFrameSize = numSampsToProcess*0.25 ;
1404  }
1405  break;
1406  case(1):
1407  fftFrameSize = numSampsToProcess;
1408  break;
1409  case(2):
1410  fftFrameSize = numSampsToProcess*0.25;
1411  break;
1412  default:
1413  if (numSampsToProcess <= 2048) {
1414  fftFrameSize = 512 ;
1415  } else {
1416  fftFrameSize = numSampsToProcess*0.25 ;
1417  }
1418  break;
1419  }
1420  fftFrameSize2 = fftFrameSize/2;
1421 
1422  try {
1423  //create FFTW plan
1424  ftPlanForward = fftwf_plan_dft_1d(fftFrameSize, fftw_in, fftw_out, FFTW_FORWARD, FFTW_ESTIMATE);
1425  ftPlanInverse = fftwf_plan_dft_1d(fftFrameSize, fftw_in, fftw_out, FFTW_BACKWARD, FFTW_ESTIMATE);
1426  // alloc buffers
1427  fpb = new float[fftFrameSize2];
1428  expect = new float[fftFrameSize2];
1429  hanning = new float[fftFrameSize];
1430  hanningd = new float[fftFrameSize];
1431  resampin = new float[fftFrameSize];
1432  resampin2 = new float[fftFrameSize];
1433  resampout = new float[fftFrameSize*4];
1434  indata2 = new float[fftFrameSize*4];
1435  } catch(...) {
1436  gx_print_error("detune", "cant allocate memory pool");
1437  return;
1438  }
1439  clear_state();
1440 }
1441 
1442 void smbPitchShift::mem_free()
1443 {
1444  ready = false;
1445  mem_allocated = false;
1446  if (fpb) { delete fpb; fpb = 0; }
1447  if (expect) { delete expect; expect = 0; }
1448  if (hanning) { delete hanning; hanning = 0; }
1449  if (hanningd) { delete hanningd; hanningd = 0; }
1450  if (resampin) { delete resampin; resampin = 0; }
1451  if (resampin2) { delete resampin2; resampin2 = 0; }
1452  if (resampout) { delete resampout; resampout = 0; }
1453  if (indata2) { delete indata2; indata2 = 0; }
1454  if (ftPlanForward)
1455  {fftwf_destroy_plan(ftPlanForward);ftPlanForward = 0; }
1456  if (ftPlanInverse)
1457  { fftwf_destroy_plan(ftPlanInverse);ftPlanInverse = 0; }
1458 }
1459 
1460 int smbPitchShift::activate(bool start)
1461 {
1462  if (start) {
1463  if (!mem_allocated) {
1464  mem_alloc();
1465  }
1466  } else if (mem_allocated) {
1467  mem_free();
1468  }
1469  return 0;
1470 }
1471 
1472 void smbPitchShift::change_buffersize(unsigned int size)
1473 {
1474  sync();
1475  ready = false;
1476  if (mem_allocated) {
1477  mem_free();
1478  mem_alloc();
1479  }
1480 }
1481 
1482 void smbPitchShift::change_latency()
1483 {
1484  sync();
1485  ready = false;
1486  if (mem_allocated) {
1487  mem_free();
1488  mem_alloc();
1489  }
1490 }
1491 
1493 {
1494  if (mem_allocated) {
1495  mem_free();
1496  }
1497 }
1498 
1499 // -----------------------------------------------------------------------------------------------------------------
1500 void __rt_func smbPitchShift::compute_static(int count, float *input0, float *output0, PluginDef *p)
1501 {
1502  static_cast<smbPitchShift*>(p)->PitchShift(count, input0, output0);
1503 }
1504 
1505 
1506 void always_inline smbPitchShift::PitchShift(int count, float *indata, float *outdata)
1507 {
1508 
1509  if (!ready || count != numSampsToProcess) {
1510  if (indata != outdata)
1511  {
1512  memcpy(outdata,indata,count*sizeof(float));
1513  }
1514  return;
1515  }
1516 
1517  resamp.down(numSampsToResamp,indata,resampin);
1518  double fSlow0 = (0.01 * wet);
1519  double fSlow1 = (0.01 * dry);
1520 
1521  // collect data for latency compensation
1522  for (i = 0; i < count; i++){
1523  indata2[ii] = indata[i];
1524  ii++;
1525  }
1526  // collect data for fft
1527  for (i = 0; i < numSampsToResamp; i++){
1528  resampin2[ai] = resampin[i];
1529  ai++;
1530  }
1531  // now we have enough data
1532  if (ai>=fftFrameSize) {
1533  ai = 0;
1534  ii = 0;
1535  switch(octave) {
1536  case(0):
1537  tone =0;
1538  break;
1539  case(1):
1540  tone =12;
1541  break;
1542  case(2):
1543  tone =-12;
1544  break;
1545  default:
1546  tone =0;
1547  break;
1548  }
1549  float pitchShift = pow(2., (semitones+tone)*0.0833333333);
1550  /* main processing loop */
1551  for (i = 0; i < fftFrameSize; i++){
1552 
1553  /* As long as we have not yet collected enough data just read in */
1554  float fTemp = resampin2[i];
1555  gInFIFO[gRover] = fTemp;
1556  resampin2[i] = gOutFIFO[gRover-inFifoLatency];
1557  gRover++;
1558 
1559  /* now we have enough data for processing */
1560  if (gRover >= fftFrameSize) {
1561  gRover = inFifoLatency;
1562 
1563  /* do windowing and re,im interleave */
1564  for (k = 0; k < fftFrameSize;k++) {
1565  fftw_in[k][0] = gInFIFO[k] * hanning[k];
1566  fftw_in[k][1] = 0.0;
1567  }
1568 
1569 
1570  /* ***************** ANALYSIS ******************* */
1571  /* do transform */
1572  fftwf_execute(ftPlanForward);
1573 
1574  /* this is the analysis step */
1575  for (k = 0; k < fftFrameSize2; k++) {
1576 
1577  /* de-interlace FFT buffer */
1578  real = fftw_out[k][0];
1579  imag = fftw_out[k][1];
1580 
1581  /* compute magnitude and phase */
1582  magn = 2.*sqrt(real*real + imag*imag);
1583  phase = atan2(imag,real);
1584 
1585  /* compute phase difference */
1586  tmp = phase - gLastPhase[k];
1587  gLastPhase[k] = phase;
1588 
1589  /* subtract expected phase difference */
1590  tmp -= expect[k];
1591 
1592  /* map delta phase into +/- Pi interval */
1593  qpd = tmp*mpi1;
1594  if (qpd >= 0) qpd += qpd&1;
1595  else qpd -= qpd&1;
1596  tmp -= M_PI*(double)qpd;
1597 
1598  /* get deviation from bin frequency from the +/- Pi interval */
1599  /* compute the k-th partials' true frequency */
1600  tmp = fpb[k] + tmp*freqPerBin2;
1601 
1602  /* store magnitude and true frequency in analysis arrays */
1603  gAnaMagn[k] = magn;
1604  gAnaFreq[k] = tmp;
1605 
1606  }
1607 
1608  /* ***************** PROCESSING ******************* */
1609  /* this does the actual pitch shifting */
1610  memset(gSynMagn, 0, fftFrameSize*sizeof(float));
1611  memset(gSynFreq, 0, fftFrameSize*sizeof(float));
1612  for (k = 1; k < fftFrameSize2-2; k++) {
1613  index = k*pitchShift;
1614  if (index < fftFrameSize2) {
1615  if (index < fftFrameSize2*0.20)
1616  gSynMagn[index] += gAnaMagn[k]*a;
1617  else if (index < fftFrameSize2*0.45)
1618  gSynMagn[index] += gAnaMagn[k]*b;
1619  else if (index < fftFrameSize2*0.667)
1620  gSynMagn[index] += gAnaMagn[k]*c;
1621  else
1622  gSynMagn[index] += gAnaMagn[k]*d;
1623  gSynFreq[index] = gAnaFreq[k] * pitchShift;
1624  }
1625  }
1626 
1627  /* ***************** SYNTHESIS ******************* */
1628  /* this is the synthesis step */
1629  for (k = 0; k < fftFrameSize2; k++) {
1630 
1631  /* get magnitude and true frequency from synthesis arrays */
1632  magn = gSynMagn[k];
1633  //tmp = gSynFreq[k];
1634 
1635  /* subtract bin mid frequency */
1636  /* get bin deviation from freq deviation */
1637  /* take osamp into account */
1638  /* add the overlap phase advance back in */
1639  tmp = ((gSynFreq[k] - fpb[k]) * freqPerBin1) + expect[k];
1640 
1641  /* accumulate delta phase to get bin phase */
1642  gSumPhase[k] += tmp;
1643  phase = gSumPhase[k];
1644  if (magn == 0.0) continue;
1645 
1646  /* get real and imag part and re-interleave */
1647  fftw_in[k][0] = magn * cos (phase);
1648  fftw_in[k][1] = magn * sin (phase);
1649  }
1650 
1651  /* do inverse transform */
1652  fftwf_execute(ftPlanInverse);
1653  /* do windowing and add to output accumulator */
1654  for(k=0; k < fftFrameSize; k++) {
1655  gOutputAccum[k] += hanningd[k] * fftw_out[ k][0] ;
1656  }
1657  for (k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];
1658 
1659  /* shift accumulator */
1660  memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float));
1661 
1662  /* move input FIFO */
1663  for (k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k+stepSize];
1664  }
1665  }
1666  resamp.up(fftFrameSize,resampin2,resampout);
1667  aio = 0;
1668  }
1669  if(l) {
1670  for (i = 0; i < count; i++){
1671  outdata[i] = ((fSlow0 * resampout[aio]) + (fSlow1 *indata2[aio]));
1672  aio++;
1673  }
1674  } else {
1675  for (i = 0; i < count; i++){
1676  outdata[i] = ((fSlow0 * resampout[aio]) + (fSlow1 *indata[i]));
1677  aio++;
1678  }
1679  }
1680 }
1681 
1682 int smbPitchShift::register_par(const ParamReg& reg)
1683 {
1684  reg.registerVar("smbPitchShift.semitone", N_("Detune"), "S", "", &semitones, 0.0, -12., 12., 0.1);
1685  static const value_pair octave_values[] = {{"unison"},{"octave up"},{"octave down"},{0}};
1686  reg.registerIEnumVar("smbPitchShift.octave",N_("add harmonics"),"B",N_("add harmonics"),octave_values,&octave, 0);
1687  static const value_pair latency_values[] = {{"latency "},{"compensate"},{0}};
1688  reg.registerEnumVar("smbPitchShift.l",N_("compensate latency"),"S",N_("compensate latency"),latency_values,&l, 0.0f, 0.0f, 1.0f, 1.0f);
1689  static const value_pair latency_set[] = {{"high quality"},{"low quality"},{"realtime"},{0}};
1690  reg.registerIEnumVar("smbPitchShift.latency",N_("latency settings"),"B",N_("latency settings"),latency_set,&latency, 0);
1691  reg.registerVar("smbPitchShift.wet", N_("Wet"), "S", N_("Wet amount"), &wet, 50.0, 0.0, 100.0, 1);
1692  reg.registerVar("smbPitchShift.dry", N_("Dry"), "S", N_("Dry amount"), &dry, 50.0, 0.0, 100.0, 1);
1693  reg.registerVar("smbPitchShift.a", N_("low"), "S", N_("Sub"), &a, 1.0, 0.0, 2.0, 0.01);
1694  reg.registerVar("smbPitchShift.b", N_("middle low"), "S", N_("Low"), &b, 1.0, 0.0, 2.0, 0.01);
1695  reg.registerVar("smbPitchShift.c", N_("middle treble"), "S", N_("Mid"), &c, 1.0, 0.0, 2.0, 0.01);
1696  reg.registerVar("smbPitchShift.d", N_("treble"), "S", N_("Hi"), &d, 1.0, 0.0, 2.0, 0.01);
1697  param["smbPitchShift.latency"].signal_changed_int().connect(
1698  sigc::hide(sigc::mem_fun(this, &smbPitchShift::change_latency)));
1699  return 0;
1700 }
1701 
1702 int smbPitchShift::registerparam(const ParamReg& reg)
1703 {
1704  return static_cast<smbPitchShift*>(reg.plugin)->register_par(reg);
1705 }
1706 
1707 int smbPitchShift::load_ui_f(const UiBuilder& b, int form)
1708 {
1709  if (form & UI_FORM_GLADE) {
1710  b.load_glade_file("gx_detune_ui.glade");
1711  return 0;
1712  }
1713  if (form & UI_FORM_STACK) {
1714  b.openHorizontalhideBox("");
1715  {
1716  b.create_master_slider("smbPitchShift.semitone",N_("Detune"));
1717  }
1718  b.closeBox();
1719  b.openVerticalBox("");
1720  {
1721  b.openHorizontalBox("");
1722  {
1723  b.openVerticalBox("");
1724  {
1725  b.insertSpacer();
1726  b.create_selector_no_caption("smbPitchShift.octave");
1727  b.create_selector_no_caption("smbPitchShift.l");
1728  b.create_selector_no_caption("smbPitchShift.latency");
1729  b.insertSpacer();
1730  }
1731  b.closeBox();
1732  b.create_mid_rackknob("smbPitchShift.semitone",N_("Detune"));
1733  b.create_small_rackknobr("smbPitchShift.dry",N_("Dry"));
1734  b.create_small_rackknobr("smbPitchShift.wet",N_("Wet"));
1735  }
1736  b.closeBox();
1737  b.insertSpacer();
1738  b.openHorizontalBox("");
1739  {
1741  b.create_small_rackknobr("smbPitchShift.a",N_("Lo"));
1743  b.create_small_rackknobr("smbPitchShift.b",N_("LoMid"));
1745  b.create_small_rackknobr("smbPitchShift.c",N_("HiMid"));
1747  b.create_small_rackknobr("smbPitchShift.d",N_("Hi"));
1748  }
1749  b.closeBox();
1750  }
1751  b.closeBox();
1752  return 0;
1753  }
1754  return -1;
1755 }
1756 
1757 int smbPitchShift::activate_static(bool start, PluginDef *p)
1758 {
1759  return static_cast<smbPitchShift*>(p)->activate(start);
1760 }
1761 
1762 int smbPitchShift::load_ui_f_static(const UiBuilder& b, int form)
1763 {
1764  return static_cast<smbPitchShift*>(b.plugin)->load_ui_f(b, form);
1765 }
1766 
1767 void smbPitchShift::del_instance(PluginDef *p)
1768 {
1769  delete static_cast<smbPitchShift*>(p);
1770 }
1771 
1772 
1773 } // namespace gx_engine
#define always_inline
void write_kv(const char *key, float v)
Definition: gx_json.h:81
static void init(unsigned int samplingFreq, PluginDef *p)
CmdConnection::msg_type start
Definition: jsonrpc.cpp:255
void begin_array(bool nl=false)
Definition: gx_json.cpp:184
void get_sched_priority(int &policy, int &priority, int prio_dim=0)
void up(int count, float *input, float *output)
void(* insertSpacer)()
Definition: gx_plugin.h:78
float sqrf(float x)
BasicOptions & get_options()
Definition: gx_system.h:509
ParameterV< GxJConvSettings > JConvParameter
PluginDef * plugin
Definition: gx_plugin.h:64
const Gainline & getGainline() const
void end_array(bool nl=false)
Definition: gx_json.cpp:192
bool operator==(const GxJConvSettings &jcset) const
static int activate(bool start, PluginDef *pdef)
virtual void overload(OverloadType tp, const char *reason)=0
struct gx_engine::CabEntry cab_table[]
const char * value_id
Definition: gx_plugin.h:118
PluginDef * plugin
Definition: gx_plugin.h:123
void set_pdef(PluginDef *p)
#define N_(String)
const char * name
Definition: gx_plugin.h:186
bool set(const GxJConvSettings &val) const
#define __rt_func
Definition: gx_compiler.h:4
bool get_on_off() const
#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(* 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
#define UI_FORM_GLADE
Definition: gx_plugin.h:61
const char * description
Definition: gx_plugin.h:189
ParameterV(const string &id, ConvolverAdapter &conv, GxJConvSettings *v)
void change_buffersize(unsigned int size)
void(* closeBox)()
Definition: gx_plugin.h:77
void change_buffersize(unsigned int)
void write_key(const char *p, bool nl=false)
Definition: gx_json.cpp:200
#define M_PI
const char ** groups
Definition: gx_plugin.h:187
void(* load_glade_file)(const char *fname)
Definition: gx_plugin.h:66
CabDesc * data
const char * category
Definition: gx_plugin.h:190
virtual void readJSON_value(gx_system::JsonParser &jp)
void(* registerIEnumVar)(const char *id, const char *name, const char *tp, const char *tooltip, const value_pair *values, int *var, int val)
Definition: gx_plugin.h:138
deletefunc delete_instance
Definition: gx_plugin.h:204
virtual bool start(bool force=false)=0
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
ConvolverMonoAdapter(EngineControl &engine, sigc::slot< void > sync, ParamMap &param)
smbPitchShift(ParamMap &param_, EngineControl &engine, sigc::slot< void > sync)
const char * value_id
CabinetConvolver(EngineControl &engine, sigc::slot< void > sync, gx_resample::BufferResampler &resamp)
#define PLUGINDEF_VERSION
Definition: gx_plugin.h:179
void(* openHorizontalBox)(const char *label)
Definition: gx_plugin.h:71
registerfunc register_params
Definition: gx_plugin.h:200
bool find_dir(std::string *d, const std::string &filename) const
Definition: gx_system.cpp:264
PreampConvolver(EngineControl &engine, sigc::slot< void > sync, gx_resample::BufferResampler &resamp)
static PluginDef outputgate
CabinetStereoConvolver(EngineControl &engine, sigc::slot< void > sync, gx_resample::BufferResampler &resamp)
const char * id
Definition: gx_plugin.h:185
virtual void serializeJSON(gx_system::JsonWriter &jw)
const char * value_label
Definition: gx_plugin.h:119
BaseConvolver(EngineControl &engine, sigc::slot< void > sync, gx_resample::BufferResampler &resamp)
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
void down(int count, float *input, float *output)
void(* create_mid_rackknob)(const char *id, const char *label)
Definition: gx_plugin.h:103
int flags
Definition: gx_plugin.h:183
virtual void writeJSON(gx_system::JsonWriter &jw) const
#define MAX_FRAME_LENGTH
const PathList & get_IR_pathlist() const
Definition: gx_system.h:377
ContrastConvolver(EngineControl &engine, sigc::slot< void > sync, gx_resample::BufferResampler &resamp)
#define UI_FORM_STACK
Definition: gx_plugin.h:60
const char * value_id
void writeJSON(gx_system::JsonWriter &w) const
PreDesc * data
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
void(* openHorizontalhideBox)(const char *label)
Definition: gx_plugin.h:72
ConvolverAdapter(EngineControl &engine, sigc::slot< void > sync, ParamMap &param)
activatefunc activate_plugin
Definition: gx_plugin.h:199
const char * value_label
virtual void check_update()=0
process_stereo_audio stereo_audio
Definition: gx_plugin.h:196
std::string replace_symbol(const std::string &dir) const
Definition: gx_system.cpp:287
void readJSON(gx_system::JsonParser &jp)
string current_value() const
Definition: gx_json.h:143
void(* set_next_flags)(int flags)
Definition: gx_plugin.h:79
inifunc set_samplerate
Definition: gx_plugin.h:198
process_mono_audio mono_audio
Definition: gx_plugin.h:195
virtual void serializeJSON(gx_system::JsonWriter &jw)
void set_on_off(bool v) const
GxJConvSettings & operator=(GxJConvSettings const &jcset)
float current_value_float()
Definition: gx_json.h:146
token next(token expect=no_token)
Definition: gx_json.cpp:496
const char * value_label
void write(float v, bool nl=false)
Definition: gx_json.cpp:116
struct gx_engine::PreEntry pre_table[]
int version
Definition: gx_plugin.h:182
const PrefixConverter & get_IR_prefixmap() const
Definition: gx_system.h:378
uiloader load_ui
Definition: gx_plugin.h:201
static ParameterV< GxJConvSettings > * insert_param(ParamMap &pmap, const string &id, ConvolverAdapter &conv, GxJConvSettings *v)
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
ConvolverStereoAdapter(EngineControl &engine, sigc::slot< void > sync, ParamMap &param)
void(* create_selector_no_caption)(const char *id)
Definition: gx_plugin.h:88
void(* openVerticalBox)(const char *label)
Definition: gx_plugin.h:68
sigc::signal< void, unsigned int > & signal_buffersize_change()