Guitarix
gx_engine_audio.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 the Guitarix Audio Engine
22  *
23  *
24  * --------------------------------------------------------------------------
25  */
26 
27 #include "engine.h" // NOLINT
28 
29 namespace gx_engine {
30 
31 /****************************************************************
32  ** class ProcessingChainBase
33  */
34 
36  sync_sem(),
37  to_release(),
38  ramp_value(0),
39  ramp_mode(ramp_mode_down_dead),
40  stopped(true),
41  steps_up(),
42  steps_up_dead(),
43  steps_down(),
44  modules(),
45  next_commit_needs_ramp() {
46  sem_init(&sync_sem, 0, 0);
47 }
48 
50  steps_down = 8 * (256 * samplerate) / 48000;
52  //steps_down = (64 * samplerate) / 48000;
53  //steps_up = 4 * steps_down;
54  steps_up_dead = 0;
55 }
56 
58  stopped = v;
59  if (v) {
60  post_rt_finished(); // in case someone is already waiting
61  }
62 }
63 
65  if (stopped) {
66  return true;
67  }
68  timespec ts;
69  clock_gettime(CLOCK_REALTIME, &ts);
70  const long ns_in_sec = 1000000000;
71  ts.tv_nsec += ns_in_sec / 10;
72  if (ts.tv_nsec >= ns_in_sec) {
73  ts.tv_nsec -= ns_in_sec;
74  ts.tv_sec += 1;
75  }
76  while (sem_timedwait(&sync_sem, &ts) == -1) {
77  if (errno == EINTR) {
78  continue;
79  }
80  if (errno == ETIMEDOUT) {
81  gx_print_warning("sem_timedwait", "timeout");
82  return false;
83  }
84  gx_print_error("sem_timedwait", "unknown error");
85  break;
86  }
87  return true;
88 }
89 
91  int val;
92  sem_getvalue(&sync_sem, &val);
93  if (val > 0) {
94  sem_wait(&sync_sem);
95  }
96  assert(sem_getvalue(&sync_sem, &val) == 0 && val == 0);
97 }
98 
100  if (stopped) {
101  return;
102  }
103  while (ramp_mode == ramp_mode_down) {
104  if (!wait_rt_finished()) {
105  break;
106  }
107  }
108 }
109 
111  RampMode rm = get_ramp_mode();
112  if (!stopped) {
113  if (rm != ramp_mode_down_dead && rm != ramp_mode_down) {
114  return;
115  }
116  set_ramp_value(0);
118  }
119 }
120 
122  RampMode rm = get_ramp_mode();
123  if (rm == ramp_mode_down_dead || rm == ramp_mode_down) {
124  return;
125  }
126  int rv = min(steps_down,get_ramp_value());
127  if (rv == 0) {
129  } else {
130  set_ramp_value(rv);
132  }
133 }
134 
135 void __rt_func ProcessingChainBase::try_set_ramp_mode(RampMode oldmode, RampMode newmode, int oldrv, int newrv) {
136  if (oldmode != newmode) {
137  if (!gx_system::atomic_compare_and_exchange(&ramp_mode, oldmode, newmode)) {
138  return;
139  }
140  }
141  if (oldrv != newrv) {
142  if (!gx_system::atomic_compare_and_exchange(&ramp_value, oldrv, newrv)) {
143  return;
144  }
145  }
146 }
147 
148 bool lists_equal(const list<Plugin*>& p1, const list<Plugin*>& p2, bool *need_ramp)
149 {
150  list<Plugin*>::const_iterator i1 = p1.begin();
151  list<Plugin*>::const_iterator i2 = p2.begin();
152  bool ret = true;
153  bool nr = false;
154  while (true) {
155  if (i1 == p1.end()) {
156  if (i2 != p2.end()) {
157  ret = false;
158  nr = true;
159  }
160  break;
161  }
162  if (i2 == p2.end()) {
163  ret = false;
164  nr = true;
165  break;
166  }
167  if (*i1 != *i2) {
168  ret = false;
169  while ((*i1)->get_pdef()->flags & PGN_SNOOP) {
170  ++i1;
171  if (i1 == p1.end()) {
172  break;
173  }
174  }
175  while ((*i2)->get_pdef()->flags & PGN_SNOOP) {
176  ++i2;
177  if (i2 == p2.end()) {
178  break;
179  }
180  }
181  if (*i1 != *i2) {
182  nr = true;
183  break;
184  }
185  }
186  ++i1;
187  ++i2;
188  }
189  if (ret) {
190  nr = false;
191  }
192  *need_ramp = nr;
193  return ret;
194 }
195 
196 bool ProcessingChainBase::set_plugin_list(const list<Plugin*> &p) {
198  return false;
199  }
200  wait_latch();
201  if (check_release()) {
202  release();
203  }
204  typedef set<const char*, stringcomp> pchar_set;
205  pchar_set new_ids;
206  for (list<Plugin*>::const_iterator i = p.begin(); i != p.end(); ++i) {
207  new_ids.insert((*i)->get_pdef()->id);
208  }
209  for (list<Plugin*>::const_iterator i = modules.begin(); i != modules.end(); ++i) {
210  if (!(*i)->get_pdef()->activate_plugin) {
211  continue;
212  }
213  pchar_set::iterator r = new_ids.find((*i)->get_pdef()->id);
214  if (r == new_ids.end()) {
215  to_release.push_back(*i);
216  }
217  }
218  modules = p;
219  return true;
220 }
221 
223  for (list<Plugin*>::const_iterator p = modules.begin(); p != modules.end(); ++p) {
224  PluginDef* pd = (*p)->get_pdef();
225  if (pd->activate_plugin) {
226  pd->activate_plugin(true, pd);
227  } else if (pd->clear_state) {
228  pd->clear_state(pd);
229  }
230  }
231 }
232 
234  wait_latch();
235  for (list<Plugin*>::const_iterator p = to_release.begin(); p != to_release.end(); ++p) {
236  (*p)->get_pdef()->activate_plugin(false, (*p)->get_pdef());
237  }
238  to_release.clear();
239 }
240 
241 #ifndef NDEBUG
242 void ProcessingChainBase::print_chain_state(const char *title) {
243  int val;
244  sem_getvalue(&sync_sem, &val);
245  printf("%s sync_sem = %d, stopped = %d, ramp_mode = %d\n",
246  title, val, stopped, ramp_mode);
247 }
248 #endif
249 
250 
251 /****************************************************************
252  ** MonoModuleChain, StereoModuleChain
253  */
254 
255 void __rt_func MonoModuleChain::process(int count, float *input, float *output) {
256  RampMode rm = get_ramp_mode();
257  if (rm == ramp_mode_down_dead) {
258  memset(output, 0, count*sizeof(float));
259  return;
260  }
261  memcpy(output, input, count*sizeof(float));
262  for (monochain_data *p = get_rt_chain(); p->func; ++p) {
263  p->func(count, output, output, p->plugin);
264  }
265  if (rm == ramp_mode_off) {
266  return;
267  }
268  int rv = get_ramp_value();
269  int rv1 = rv;
270  RampMode rm1 = get_ramp_mode();
271  if (rm != rm1) {
272  // ramp_mode has changed while processing
273  if (rm1 != ramp_mode_up && rm1 != ramp_mode_down) {
274  return;
275  }
276  rv1 = rv = get_ramp_value();
277  // assume ramp_mode doesn't change too fast
278  rm = rm1;
279  }
280  int i = 0;
281  if (rm1 == ramp_mode_up_dead) {
282  for ( ; i < count; ++i) {
283  if (++rv1 > steps_up_dead) {
284  rm1 = ramp_mode_up;
285  rv1 = 0;
286  break;
287  }
288  output[i] = 0.0;
289  }
290  }
291  if (rm1 == ramp_mode_up) {
292  for ( ; i < count; ++i) {
293  if (++rv1 >= steps_up) {
294  rm1 = ramp_mode_off;
295  break;
296  }
297  output[i] = (output[i] * rv1) / steps_up;
298  }
299  }
300  else if (rm1 == ramp_mode_down) {
301  for (i = 0; i < count; ++i) {
302  if (--rv1 == 0) {
303  rm1 = ramp_mode_down_dead;
304  break;
305  }
306  output[i] = (output[i] * rv1) / steps_down;
307  }
308  for ( ; i < count; ++i) {
309  output[i] = 0.0;
310  }
311  }
312  try_set_ramp_mode(rm, rm1, rv, rv1);
313 }
314 
315 void __rt_func StereoModuleChain::process(int count, float *input1, float *input2, float *output1, float *output2) {
316  // run stereo rack
317  RampMode rm = get_ramp_mode();
318  if (rm == ramp_mode_down_dead) {
319  memset(output1, 0, count*sizeof(float));
320  memset(output2, 0, count*sizeof(float));
321  return;
322  }
323  memcpy(output1, input1, count*sizeof(float));
324  memcpy(output2, input2, count*sizeof(float));
325  for (stereochain_data *p = get_rt_chain(); p->func; ++p) {
326  (p->func)(count, output1, output2, output1, output2, p->plugin);
327  }
328  if (rm == ramp_mode_off) {
329  return;
330  }
331  int rv = get_ramp_value();
332  int rv1 = rv;
333  RampMode rm1 = get_ramp_mode();
334  if (rm != rm1) {
335  // ramp_mode has changed while processing
336  if (rm1 != ramp_mode_up && rm1 != ramp_mode_down) {
337  return;
338  }
339  rv1 = rv = get_ramp_value();
340  // assume ramp_mode doesn't change too fast
341  rm = rm1;
342  }
343  int i = 0;
344  if (rm1 == ramp_mode_up_dead) {
345  for ( ; i < count; ++i) {
346  if (++rv1 > steps_up_dead) {
347  rm1 = ramp_mode_up;
348  rv1 = 0;
349  break;
350  }
351  output1[i] = 0.0;
352  output2[i] = 0.0;
353  }
354  }
355  if (rm1 == ramp_mode_up) {
356  for ( ; i < count; ++i) {
357  if (++rv1 >= steps_up) {
358  rm1 = ramp_mode_off;
359  break;
360  }
361  output1[i] = (output1[i] * rv1) / steps_up;
362  output2[i] = (output2[i] * rv1) / steps_up;
363  }
364  }
365  else if (rm1 == ramp_mode_down) {
366  for (i = 0; i < count; ++i) {
367  if (--rv1 == 0) {
368  rm1 = ramp_mode_down_dead;
369  break;
370  }
371  output1[i] = (output1[i] * rv1) / steps_down;
372  output2[i] = (output2[i] * rv1) / steps_down;
373  }
374  for ( ; i < count; ++i) {
375  output1[i] = 0.0;
376  output2[i] = 0.0;
377  }
378  }
379  try_set_ramp_mode(rm, rm1, rv, rv1);
380 }
381 
382 
383 /****************************************************************
384  ** ModuleSelectorFromList
385  */
386 
388  EngineControl& seq_, const char* id_, const char* name_,
389  const char* category_, plugindef_creator plugins[], const char* select_id_,
390  const char* select_name_, uiloader loader, const char** groups_, int flags_)
391  : ModuleSelector(seq_),
392  PluginDef(),
393  selector(0),
394  select_id(select_id_),
395  select_name(select_name_),
396  current_plugin(0),
397  modules(),
398  size(),
399  plugin() {
401  register_params = static_register;
402  plugindef_creator *p = plugins;
403  for (size = 0; *p; ++p, ++size);
404  modules = new PluginDef*[size];
405  for (unsigned int i = 0; i < size; ++i) {
406  modules[i] = plugins[i]();
407  }
408  id = id_;
409  name = name_;
410  category = category_;
411  groups = groups_;
412  flags = flags_;
413  load_ui = loader;
414  plugin = this;
415 }
416 
418  delete[] modules;
419 }
420 
421 int ModuleSelectorFromList::register_parameter(const ParamReg &param) {
422  value_pair *p = new value_pair[size+1];
423  for (unsigned int i = 0; i < size; ++i) {
424  p[i].value_id = modules[i]->id;
425  p[i].value_label = modules[i]->name;
426  }
427  p[size].value_id = 0;
428  p[size].value_label = 0;
429  param.registerIEnumVar(select_id, select_name, "S", "", p, &selector, 0);
430  seq.get_param()[select_id].signal_changed_int().connect(
431  sigc::hide(sigc::mem_fun(seq, &EngineControl::set_rack_changed)));
432  return 0;
433 }
434 
435 int ModuleSelectorFromList::static_register(const ParamReg &param) {
436  return static_cast<ModuleSelectorFromList*>(param.plugin)
437  ->register_parameter(param);
438 }
439 
441  if (plugin.get_on_off()) {
442  Plugin *old = current_plugin;
443  current_plugin = seq.pluginlist.lookup_plugin(modules[selector]->id);
444  if (old && old != current_plugin) {
445  old->set_on_off(false);
446  }
447  current_plugin->set_on_off(true);
448  current_plugin->copy_position(plugin);
449  } else if (current_plugin) {
450  current_plugin->set_on_off(false);
451  current_plugin = 0;
452  }
453 }
454 
455 
456 /****************************************************************
457  ** class EngineControl
458  */
459 
461  : selectors(),
462  rack_changed(),
463  pmap(),
464  policy(),
465  priority(),
466  buffersize_change(),
467  samplerate_change(),
468  buffersize(0),
469  samplerate(0),
470  pluginlist(*this) {
471 }
472 
474 }
475 
477  selectors.push_back(&sel);
478 }
479 
481 {
483 }
484 
485 void EngineControl::get_sched_priority(int &policy_, int &priority_, int prio_dim) {
486  policy_ = policy;
487  priority_ = priority;
488  if (!prio_dim) {
489  return;
490  }
491  int min, max;
492  min = sched_get_priority_min(policy);
493  max = sched_get_priority_max(policy);
494  priority_ = priority - prio_dim;
495  if (priority_ > max) {
496  priority_ = max;
497  }
498  if (priority_ < min) {
499  priority_ = min;
500  }
501 }
502 
503 void EngineControl::set_samplerate(unsigned int samplerate_) {
504  if (samplerate == samplerate_) {
505  return;
506  }
507  samplerate = samplerate_;
510 }
511 
512 void EngineControl::set_buffersize(unsigned int buffersize_) {
513  if (buffersize == buffersize_) {
514  return;
515  }
516  buffersize = buffersize_;
518 }
519 
520 void EngineControl::init(unsigned int samplerate_, unsigned int buffersize_,
521  int policy_, int priority_) {
522  if (policy_ != policy || priority_ != priority) {
523  policy = policy_;
524  priority = priority_;
525  set_buffersize(buffersize_);
526  set_samplerate(samplerate_);
527  return;
528  }
529  if (buffersize_ != buffersize) {
530  set_buffersize(buffersize_);
531  }
532  if (samplerate_ != samplerate) {
533  set_samplerate(samplerate_);
534  }
535 }
536 
538  rack_changed.disconnect();
539 }
540 
542  return rack_changed.connected();
543 }
544 
545 
546 /****************************************************************
547  ** ModuleSequencer
548  */
549 
551  : EngineControl(),
552  audio_mode(PGN_MODE_NORMAL),
553  stateflags_mutex(),
554  stateflags(SF_INITIALIZING),
555  state_change(),
556  overload_detected(),
557  overload_reason(),
558  ov_disabled(0),
559  mono_chain(),
560  stereo_chain() {
561  overload_detected.connect(
562  sigc::mem_fun(this, &ModuleSequencer::check_overload));
563 }
564 
566  start_ramp_down();
569 }
570 
574 }
575 
579 }
580 
584 }
585 
587  if (!get_buffersize() || !get_samplerate()) {
588  return false;
589  }
590  if (prepare_module_lists()) {
592  if (stateflags & SF_OVERLOAD) {
593  // hack: jackd need some time for new load statistic
594  Glib::signal_timeout().connect_once(
595  sigc::bind(
596  sigc::mem_fun(this,&ModuleSequencer::clear_stateflag),
597  SF_OVERLOAD), 1000);
598  }
599  return true;
600  }
601  return false;
602 }
603 
605  mono_chain.set_samplerate(samplerate);
606  stereo_chain.set_samplerate(samplerate);
607  EngineControl::set_samplerate(samplerate);
608 }
609 
611  if (mono_chain.check_release()) {
613  }
614  if (stereo_chain.check_release()) {
616  }
617  if (get_rack_changed()) {
620  }
621  return false;
622 }
623 
625  if (rack_changed.connected()) {
626  return;
627  }
628  rack_changed = Glib::signal_idle().connect(
629  sigc::mem_fun(this, &ModuleSequencer::check_module_lists));
630 }
631 
633  for (list<ModuleSelector*>::iterator i = selectors.begin(); i != selectors.end(); ++i) {
634  (*i)->set_module();
635  }
636  list<Plugin*> modules;
638  bool ret_mono = mono_chain.set_plugin_list(modules);
640  bool ret_stereo = stereo_chain.set_plugin_list(modules);
641  if (ret_mono || ret_stereo) {
642  mono_chain.print();
644  }
645  return ret_mono || ret_stereo;
646 }
647 
650  bool monoramp = mono_chain.next_commit_needs_ramp && !already_down;
651  if (monoramp) {
654  }
657  bool stereoramp = stereo_chain.next_commit_needs_ramp && !already_down;
658  if (stereoramp) {
661  }
663  if (monoramp) {
666  }
667  if (stereoramp) {
670  }
671 }
672 
674 
675 void __rt_func ModuleSequencer::overload(OverloadType tp, const char *reason) {
676  if (!(audio_mode & PGN_MODE_NORMAL)) {
677  return; // no overload message in mute/bypass modes
678  }
679  if ((tp & ov_disabled) == ov_XRun) {
680  return; // the xrun should show up in the log anyhow
681  }
682  bool ignore = false;
683  if ((tp & ov_disabled) == ov_Convolver) {
684  ignore = true;
685  }
686  if (sporadic_interval > 0 && !ignore && (tp & (ov_Convolver|ov_XRun))) {
687  static float last = -sporadic_interval;
688  timespec ts;
689  clock_gettime(CLOCK_MONOTONIC, &ts);
690  float now = ts.tv_sec + ts.tv_nsec * 1e-9;
691  if (now - last < sporadic_interval) { // max. 1 event every sporadic_interval seconds
692  last = now;
693  ignore = true;
694  }
695  }
696  if (!ignore) {
698  }
701 }
702 
704  if (stateflags & flag) {
705  return;
706  }
707  boost::mutex::scoped_lock lock(stateflags_mutex);
708  mono_chain.set_stopped(true);
710  if (!stateflags) {
711  set_down_dead();
712  }
713  stateflags |= flag;
714 }
715 
717  if (!(stateflags & flag)) {
718  return;
719  }
720  boost::mutex::scoped_lock lock(stateflags_mutex);
721  stateflags &= ~flag;
722  if (!stateflags) {
723  mono_chain.set_stopped(false);
724  stereo_chain.set_stopped(false);
725  start_ramp_up();
726  }
727 }
728 
730  if (stateflags & SF_OVERLOAD) {
734  "watchdog",
735  boost::format(_("Overload (%s)")) % gx_system::atomic_get(overload_reason));
736  } else {
738  "watchdog",
739  boost::format(_("Overload ignored (%s)")) % gx_system::atomic_get(overload_reason));
740  }
741 }
742 
744  int newmode = PGN_MODE_MUTE;
745  switch( state ) {
746  case kEngineOn: newmode = PGN_MODE_NORMAL; break;
747  case kEngineBypass: newmode = PGN_MODE_BYPASS; break;
748  case kEngineOff: newmode = PGN_MODE_MUTE; break;
749  }
750  if (audio_mode == newmode) {
751  return;
752  }
753  audio_mode = newmode;
755  state_change(state);
756 }
757 
758 #ifndef NDEBUG
760  printf("stateflags = %d, audio_mode = %d\n", stateflags, audio_mode);
761  mono_chain.print_chain_state("mono :");
762  stereo_chain.print_chain_state("stereo:");
763 }
764 #endif
765 
767  if (audio_mode & PGN_MODE_NORMAL) {
768  return kEngineOn;
769  } else if (audio_mode & PGN_MODE_BYPASS) {
770  return kEngineBypass;
771  } else if (audio_mode & PGN_MODE_MUTE) {
772  return kEngineOff;
773  } else {
774  assert(false);
775  return kEngineOff;
776  }
777 }
778 
779 } // end namespace gx_engine
void set_samplerate(int samplerate)
void process(int count, float *input1, float *input2, float *output1, float *output2)
void print_chain_state(const char *title)
void get_sched_priority(int &policy, int &priority, int prio_dim=0)
clearstatefunc clear_state
Definition: gx_plugin.h:204
bool set_plugin_list(const list< Plugin *> &p)
void registerParameter(ParameterGroups &groups)
virtual void wait_ramp_down_finished()
void set_buffersize(unsigned int buffersize_)
int(* uiloader)(const UiBuilder &builder, int format)
Definition: gx_plugin.h:158
const char * value_id
Definition: gx_plugin.h:118
PluginDef * plugin
Definition: gx_plugin.h:123
const char * name
Definition: gx_plugin.h:188
bool lists_equal(const list< Plugin *> &p1, const list< Plugin *> &p2, bool *need_ramp)
void init(unsigned int samplerate, unsigned int buffersize, int policy, int priority)
#define __rt_func
Definition: gx_compiler.h:4
bool get_on_off() const
sigc::signal< void, GxEngineState > state_change
virtual void set_samplerate(unsigned int samplerate)
const char ** groups
Definition: gx_plugin.h:189
int atomic_get(volatile int &p)
Definition: gx_system.h:98
void process(int count, float *input, float *output)
list< ModuleSelector * > selectors
const char * category
Definition: gx_plugin.h:192
sigc::signal< void, unsigned int > samplerate_change
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
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
void copy_position(const Plugin &plugin)
sigc::signal< void, unsigned int > buffersize_change
#define PLUGINDEF_VERSION
Definition: gx_plugin.h:181
registerfunc register_params
Definition: gx_plugin.h:202
#define min(x, y)
void add_selector(ModuleSelector &sel)
const char * id
Definition: gx_plugin.h:187
void try_set_ramp_mode(RampMode oldmode, RampMode newmode, int oldrv, int newrv)
virtual void overload(OverloadType tp, const char *reason)
#define max(x, y)
const char * value_label
Definition: gx_plugin.h:119
int flags
Definition: gx_plugin.h:185
Plugin * lookup_plugin(const std::string &id) const
PluginDef *(* plugindef_creator)()
Glib::Dispatcher overload_detected
void set_state(GxEngineState state)
void set_samplerate(int samplerate)
void set_samplerate(unsigned int samplerate_)
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
activatefunc activate_plugin
Definition: gx_plugin.h:201
void atomic_set(volatile int *p, int v)
Definition: gx_system.h:90
ModuleSelectorFromList(EngineControl &seq, const char *id, const char *name, const char *category, plugindef_creator module_ids[], const char *select_id, const char *select_name, uiloader loader, const char **groups=0, int flags=0)
void set_stateflag(StateFlag flag)
bool atomic_compare_and_exchange(volatile int *p, int oldv, int newv)
Definition: gx_system.h:114
virtual void set_rack_changed()=0
void set_on_off(bool v) const
int flag
Definition: ladspaback.cpp:55
void clear_stateflag(StateFlag flag)
void ordered_mono_list(list< Plugin *> &mono, int mode)
void ordered_stereo_list(list< Plugin *> &stereo, int mode)
void registerAllPlugins(ParamMap &param, ParameterGroups &groups)
void commit(bool clear, ParamMap &pmap)
int version
Definition: gx_plugin.h:184
uiloader load_ui
Definition: gx_plugin.h:203