Guitarix
gx_modulesequencer.h
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 #pragma once
22 
23 namespace gx_engine {
24 
25 /****************************************************************
26  ** class ModuleSelector
27  */
28 
30 protected:
32 public:
34  : seq(seq_) {}
35  virtual ~ModuleSelector() {}
36  virtual void set_module() = 0;
37 };
38 
39 
40 /****************************************************************
41  ** class ProcessingChainBase
42  ** members and methods accessed by the rt thread are marked RT
43  */
44 
46 public:
47  enum RampMode { ramp_mode_down_dead, ramp_mode_down, ramp_mode_up_dead, ramp_mode_up, ramp_mode_off };
48 private:
49  sem_t sync_sem; // RT
50  list<Plugin*> to_release;
51  int ramp_value; // RT
52  int ramp_mode; // RT should be RampMode, but gcc 4.5 doesn't accept it for g_atomic_int_compare_and_exchange
53  volatile bool stopped;
54 protected:
55  int steps_up; // RT; >= 1
56  int steps_up_dead; // RT; >= 0
57  int steps_down; // RT; >= 1
58  list<Plugin*> modules;
59  inline void set_ramp_value(int n) { gx_system::atomic_set(&ramp_value, n); } // RT
60  inline void set_ramp_mode(RampMode n) { gx_system::atomic_set(&ramp_mode, n); } // RT
61  void try_set_ramp_mode(RampMode oldmode, RampMode newmode, int oldrv, int newrv); // RT
62 public:
66  return static_cast<RampMode>(gx_system::atomic_get(ramp_mode)); // RT
67  }
68  inline int get_ramp_value() { return gx_system::atomic_get(ramp_value); } // RT
69  void set_samplerate(int samplerate);
70  bool set_plugin_list(const list<Plugin*> &p);
71  void clear_module_states();
72  inline void post_rt_finished() { // RT
73  int val;
74  sem_getvalue(&sync_sem, &val);
75  if (val == 0) {
76  sem_post(&sync_sem);
77  }
78  }
79  bool wait_rt_finished();
80  void set_latch();
81  void wait_latch() { wait_rt_finished(); }
82  void sync() { set_latch(); wait_latch(); }
83  inline bool check_release() { return !to_release.empty(); }
84  void release();
85  void wait_ramp_down_finished();
86  void start_ramp_up();
87  void start_ramp_down();
88  inline void set_down_dead() { set_ramp_mode(ramp_mode_down_dead); }
89  inline bool is_down_dead() { return get_ramp_mode() == ramp_mode_down_dead; }
90  void set_stopped(bool v);
91  bool is_stopped() { return stopped; }
92 #ifndef NDEBUG
93  void print_chain_state(const char *title);
94 #endif
95 };
96 
97 
98 /****************************************************************
99  ** template class ThreadSafeChainPointer
100  ** members and methods accessed by the rt thread are marked RT
101  */
102 
103 template <class F>
105 private:
106  F *rack_order_ptr[2]; // RT
107  int size[2];
108  int current_index;
109  F *current_pointer;
110  void setsize(int n);
111  inline F get_audio(PluginDef *p);
112 protected:
114  inline F* get_rt_chain() { return gx_system::atomic_get(processing_pointer); } // RT
115 public:
118  inline void empty_chain(ParamMap& pmap) {
119  list<Plugin*> p;
120  if (set_plugin_list(p)) {
121  commit(true, pmap);
122  }
123  }
124  void commit(bool clear, ParamMap& pmap);
125 };
126 
127 typedef void (*monochainorder)(int count, float *output, float *output1,
128  PluginDef *plugin);
129 typedef void (*stereochainorder)(int count, float* input, float* input1,
130  float *output, float *output1, PluginDef *plugin);
131 
135  monochain_data(monochainorder func_, PluginDef *plugin_): func(func_), plugin(plugin_) {}
136  monochain_data(): func(), plugin() {}
137 };
138 
142  stereochain_data(stereochainorder func_, PluginDef *plugin_): func(func_), plugin(plugin_) {}
143  stereochain_data(): func(), plugin() {}
144 };
145 
146 template <>
148 {
149  return monochain_data(p->mono_audio, p);
150 }
151 
152 template <>
154 {
155  return stereochain_data(p->stereo_audio, p);
156 }
157 
158 template <class F>
160  rack_order_ptr(),
161  size(),
162  current_index(0),
163  current_pointer(),
164  processing_pointer() {
165  setsize(1);
166  current_pointer[0].func = 0;
167  processing_pointer = current_pointer;
168  current_index = 1;
169  current_pointer = rack_order_ptr[1];
170 }
171 
172 template <class F>
174  delete[] rack_order_ptr[0];
175  delete[] rack_order_ptr[1];
176 }
177 
178 template <class F>
180 {
181  if (n <= size[current_index]) {
182  return;
183  }
184  delete[] rack_order_ptr[current_index];
185  rack_order_ptr[current_index] = new F[n];
186  size[current_index] = n;
187  current_pointer = rack_order_ptr[current_index];
188 }
189 
190 template <class F>
192  setsize(modules.size()+1); // leave one slot for 0 marker
193  int active_counter = 0;
194  for (list<Plugin*>::const_iterator p = modules.begin(); p != modules.end(); p++) {
195  PluginDef* pd = (*p)->get_pdef();
196  if (pd->activate_plugin) {
197  if (pd->activate_plugin(true, pd) != 0) {
198  (*p)->set_on_off(false);
199  continue;
200  }
201  } else if (pd->clear_state && clear) {
202  pd->clear_state(pd);
203  }
204  F f = get_audio(pd);
205  assert(f.func);
206  current_pointer[active_counter++] = f;
207  }
208  current_pointer[active_counter].func = 0;
209  gx_system::atomic_set(&processing_pointer, current_pointer);
210  set_latch();
211  current_index = (current_index+1) % 2;
212  current_pointer = rack_order_ptr[current_index];
213 }
214 
215 /****************************************************************
216  ** class MonoModuleChain, class StereoModuleChain
217  */
218 
219 class MonoModuleChain: public ThreadSafeChainPointer<monochain_data> {
220 public:
222  void process(int count, float *input, float *output);
223  inline void print() { printlist("Mono", modules); }
224 };
225 
226 class StereoModuleChain: public ThreadSafeChainPointer<stereochain_data> {
227 public:
229  void process(int count, float *input1, float *input2, float *output1, float *output2);
230  inline void print() { printlist("Stereo", modules); }
231 };
232 
233 
234 /****************************************************************
235  ** class EngineControl
236  */
237 
239 protected:
240  list<ModuleSelector*> selectors; // selectors that modify the on/off state of
241  // modules at start of reconfiguration
242  sigc::connection rack_changed; // idle signal for reconfiguration of module chains
244  int policy; // jack realtime policy,
245  int priority; // and priority, for internal modules
246  // signal anyone who needs to be synchronously notified
247  // BE CAREFUL: executed by RT thread (though not concurrent with audio
248  // modules, and timing requirements are relaxed)
249  sigc::signal<void, unsigned int> buffersize_change;
250  sigc::signal<void, unsigned int> samplerate_change;
251  unsigned int buffersize;
252  unsigned int samplerate;
253 public:
254  enum OverloadType { // type of overload condition
255  ov_User = 0x1, // idle thread probe starved
256  ov_Convolver = 0x2, // convolver overload
257  ov_XRun = 0x4 // jack audio loop overload
258  };
260  EngineControl();
261  ~EngineControl();
262  void init(unsigned int samplerate, unsigned int buffersize,
263  int policy, int priority);
264  virtual void wait_ramp_down_finished() = 0;
265  virtual bool update_module_lists() = 0;
266  virtual void start_ramp_up() = 0;
267  virtual void start_ramp_down() = 0;
268  virtual void overload(OverloadType tp, const char *reason) = 0; // RT
269  void set_samplerate(unsigned int samplerate_);
270  unsigned int get_samplerate() { return samplerate; }
271  void set_buffersize(unsigned int buffersize_);
272  unsigned int get_buffersize() { return buffersize; }
273  virtual void set_rack_changed() = 0;
274  void clear_rack_changed();
275  bool get_rack_changed();
276  sigc::signal<void, unsigned int>& signal_buffersize_change() { return buffersize_change; }
277  sigc::signal<void, unsigned int>& signal_samplerate_change() { return samplerate_change; }
278  void add_selector(ModuleSelector& sel);
279  void registerParameter(ParameterGroups& groups);
280  void get_sched_priority(int &policy, int &priority, int prio_dim = 0);
281  ParamMap& get_param() { return pmap; }
282 };
283 
284 
285 /****************************************************************
286  ** class ModuleSequencer
287  */
288 
289 enum GxEngineState { // engine states set by user (ModuleSequencer set_state/get_state)
290  kEngineOff = 0, // mute, no output (but tuner or something might run)
291  kEngineOn = 1, // normal operation
292  kEngineBypass = 2 // just some balance or level control
293 };
294 
295 
297 protected:
298  int audio_mode; // GxEngineState coded as PGN_MODE_XX flags
299  boost::mutex stateflags_mutex;
301  sigc::signal<void, GxEngineState> state_change;
302  Glib::Dispatcher overload_detected;
303  const char *overload_reason; // name of unit which detected overload
304  int ov_disabled; // bitmask of OverloadType
305  static int sporadic_interval; // seconds; overload if at least 2 events in the timespan
306 protected:
307  void check_overload();
308 public:
309  MonoModuleChain mono_chain; // active modules (amp chain, input to insert output)
310  StereoModuleChain stereo_chain; // active stereo modules (effect chain, after insert input)
311  enum StateFlag { // engine is off if one of these flags is set
312  SF_NO_CONNECTION = 0x01, // no jack connection at amp input
313  SF_JACK_RECONFIG = 0x02, // jack buffersize reconfiguration in progress
314  SF_INITIALIZING = 0x04, // jack or engine not ready
315  SF_OVERLOAD = 0x08, // engine overload
316  };
317 public:
318  ModuleSequencer();
319  ~ModuleSequencer();
321  mono_chain.clear_module_states();
322  stereo_chain.clear_module_states();
323  }
324  virtual void set_samplerate(unsigned int samplerate);
325  virtual void start_ramp_up();
326  virtual void start_ramp_down();
327  virtual void wait_ramp_down_finished();
328  void ramp_down() {
329  start_ramp_down();
330  wait_ramp_down_finished();
331  }
332  void set_down_dead() {
333  mono_chain.set_down_dead();
334  stereo_chain.set_down_dead();
335  }
336  bool prepare_module_lists();
337  void commit_module_lists();
338  virtual void set_rack_changed();
339  virtual bool update_module_lists();
340  bool check_module_lists();
341  virtual void overload(OverloadType tp, const char *reason); // RT
342  void set_stateflag(StateFlag flag); // RT
343  void clear_stateflag(StateFlag flag); // RT
344  void set_state(GxEngineState state);
345  GxEngineState get_state();
346  sigc::signal<void, GxEngineState>& signal_state_change() { return state_change; }
347  static void set_overload_interval(int i) { sporadic_interval = i; }
348 #ifndef NDEBUG
349  void print_engine_state();
350 #endif
351 };
352 
353 } /* end of gx_engine namespace */
ModuleSelector(EngineControl &seq_)
clearstatefunc clear_state
Definition: gx_plugin.h:204
void init(int samplingFreq)
void printlist(const char *title, const list< Plugin *> &modules, bool header=true)
sigc::signal< void, GxEngineState > state_change
int atomic_get(volatile int &p)
Definition: gx_system.h:98
list< ModuleSelector * > selectors
void(* stereochainorder)(int count, float *input, float *input1, float *output, float *output1, PluginDef *plugin)
virtual void set_module()=0
sigc::signal< void, unsigned int > samplerate_change
sigc::signal< void, unsigned int > buffersize_change
monochain_data(monochainorder func_, PluginDef *plugin_)
stereochain_data(stereochainorder func_, PluginDef *plugin_)
Glib::Dispatcher overload_detected
sigc::signal< void, GxEngineState > & signal_state_change()
activatefunc activate_plugin
Definition: gx_plugin.h:201
process_stereo_audio stereo_audio
Definition: gx_plugin.h:198
void atomic_set(volatile int *p, int v)
Definition: gx_system.h:90
static void set_overload_interval(int i)
process_mono_audio mono_audio
Definition: gx_plugin.h:197
int flag
Definition: ladspaback.cpp:56
void(* monochainorder)(int count, float *output, float *output1, PluginDef *plugin)
sigc::signal< void, unsigned int > & signal_samplerate_change()
sigc::signal< void, unsigned int > & signal_buffersize_change()