Ardour  9.0-pre0-582-g084a23a80d
zita-convolver.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2006-2018 Fons Adriaensen <fons@linuxaudio.org>
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 3 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, see <http://www.gnu.org/licenses/>.
17 //
18 // ----------------------------------------------------------------------------
19 
20 #ifndef ARDOUR_ZITA_CONVOLVER_H
21 #define ARDOUR_ZITA_CONVOLVER_H
22 
23 
24 #include <fftw3.h>
25 #include <pthread.h>
26 #include <stdint.h>
27 
29 
30 #if defined(__linux__) || defined(__GNU__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(PTW32_VERSION) || defined(__WINPTHREADS_VERSION)
31 #include <semaphore.h>
32 #endif
33 
34 namespace ArdourZita {
35 
36 #ifdef ZCSEMA_IS_IMPLEMENTED
37 #undef ZCSEMA_IS_IMPLEMENTED
38 #endif
39 
40 /* note: mingw and msvc actually use PTW32's implementation of semaphores */
41 #if defined(__linux__) || defined(__GNU__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(PTW32_VERSION) || defined (__WINPTHREADS_VERSION)
42 
43 class LIBZCONVOLVER_API ZCsema
44 {
45 public:
46  ZCsema (void)
47  {
48  init (0, 0);
49  }
50 
51  ~ZCsema (void)
52  {
53  sem_destroy (&_sema);
54  }
55 
56  int init (int s, int v)
57  {
58  return sem_init (&_sema, s, v);
59  }
60 
61  int post (void)
62  {
63  return sem_post (&_sema);
64  }
65 
66  int wait (void)
67  {
68  return sem_wait (&_sema);
69  }
70 
71  int trywait (void)
72  {
73  return sem_trywait (&_sema);
74  }
75 
76 private:
77  ZCsema (const ZCsema&); // disabled
78  ZCsema& operator= (const ZCsema&); // disabled
79 
80  sem_t _sema;
81 };
82 
83 #define ZCSEMA_IS_IMPLEMENTED
84 
85 #elif defined (__APPLE__)
86 
87 // NOTE: ***** I DO NOT REPEAT NOT PROVIDE SUPPORT FOR OSX *****
88 //
89 // The following code partially emulates the POSIX sem_t for which
90 // OSX has only a crippled implementation. It may or may not compile,
91 // and if it compiles it may or may not work correctly. Blame APPLE
92 // for not following POSIX standards.
93 
94 class LIBZCONVOLVER_API ZCsema
95 {
96 public:
97  ZCsema (void) : _count (0)
98  {
99  init (0, 0);
100  }
101 
102  ~ZCsema (void)
103  {
104  pthread_mutex_destroy (&_mutex);
105  pthread_cond_destroy (&_cond);
106  }
107 
108  ZCsema (const ZCsema&); // disabled
109  ZCsema& operator= (const ZCsema&); // disabled
110 
111  int init (int s, int v)
112  {
113  _count = v;
114  return pthread_mutex_init (&_mutex, 0) || pthread_cond_init (&_cond, 0);
115  }
116 
117  int post (void)
118  {
119  pthread_mutex_lock (&_mutex);
120  _count++;
121  if (_count == 1) {
122  pthread_cond_signal (&_cond);
123  }
124  pthread_mutex_unlock (&_mutex);
125  return 0;
126  }
127 
128  int wait (void)
129  {
130  pthread_mutex_lock (&_mutex);
131  while (_count < 1) {
132  pthread_cond_wait (&_cond, &_mutex);
133  }
134  _count--;
135  pthread_mutex_unlock (&_mutex);
136  return 0;
137  }
138 
139  int trywait (void)
140  {
141  if (pthread_mutex_trylock (&_mutex)) {
142  return -1;
143  }
144  if (_count < 1) {
145  pthread_mutex_unlock (&_mutex);
146  return -1;
147  }
148  _count--;
149  pthread_mutex_unlock (&_mutex);
150  return 0;
151  }
152 
153 private:
154  int _count;
155  pthread_mutex_t _mutex;
156  pthread_cond_t _cond;
157 };
158 
159 #define ZCSEMA_IS_IMPLEMENTED
160 #endif
161 
162 #ifndef ZCSEMA_IS_IMPLEMENTED
163 #error "The ZCsema class is not implemented."
164 #endif
165 
166 // ----------------------------------------------------------------------------
167 
169 {
170 private:
171  friend class Convlevel;
172 
173  Inpnode (uint16_t inp);
174  ~Inpnode (void);
175  void alloc_ffta (uint16_t npar, int32_t size);
176  void free_ffta (void);
177 
179  fftwf_complex** _ffta;
180  uint16_t _npar;
181  uint16_t _inp;
182 };
183 
185 {
186 private:
187  friend class Convlevel;
188 
189  Macnode (Inpnode* inpn);
190  ~Macnode (void);
191  void alloc_fftb (uint16_t npar);
192  void free_fftb (void);
193 
197  fftwf_complex** _fftb;
198  uint16_t _npar;
199 };
200 
202 {
203 private:
204  friend class Convlevel;
205 
206  Outnode (uint16_t out, int32_t size);
207  ~Outnode (void);
208 
211  float* _buff[3];
212  uint16_t _out;
213 };
214 
216 {
217 public:
218  enum {
219  BAD_STATE = -1,
220  BAD_PARAM = -2,
221  MEM_ALLOC = -3
222  };
223 
224  Converror (int error) : _error (error) {}
225 
226 private:
227  int _error;
228 };
229 
231 {
232 private:
233  friend class Convproc;
234 
235  enum {
236  OPT_FFTW_MEASURE = 1,
237  OPT_VECTOR_MODE = 2,
238  OPT_LATE_CONTIN = 4
239  };
240 
241  enum {
244  ST_PROC
245  };
246 
247  Convlevel (void);
248  ~Convlevel (void);
249 
250  void configure (int prio,
251  uint32_t offs,
252  uint32_t npar,
253  uint32_t parsize,
254  uint32_t options);
255 
256  void impdata_write (uint32_t inp,
257  uint32_t out,
258  int32_t step,
259  float* data,
260  int32_t ind0,
261  int32_t ind1,
262  bool create);
263 
264  void impdata_clear (uint32_t inp,
265  uint32_t out);
266 
267  void reset (uint32_t inpsize,
268  uint32_t outsize,
269  float** inpbuff,
270  float** outbuff);
271 
272  void start (int absprio, int policy);
273 
274  void process ();
275 
276  int readout ();
277  int readtail (uint32_t n_samples);
278 
279  void stop (void);
280 
281  void cleanup (void);
282 
283  void fftswap (fftwf_complex* p);
284 
285  void print (FILE* F);
286 
287  static void* static_main (void* arg);
288 
289  void main (void);
290 
291  Macnode* findmacnode (uint32_t inp, uint32_t out, bool create);
292 
293  volatile uint32_t _stat; // current processing state
294  int _prio; // relative priority
295  uint32_t _offs; // offset from start of impulse response
296  uint32_t _npar; // number of partitions
297  uint32_t _parsize; // partition and outbut buffer size
298  uint32_t _outsize; // step size for output buffer
299  uint32_t _outoffs; // offset into output buffer
300  uint32_t _inpsize; // size of shared input buffer
301  uint32_t _inpoffs; // offset into input buffer
302  uint32_t _options; // various options
303  uint32_t _ptind; // rotating partition index
304  uint32_t _opind; // rotating output buffer index
305  int _bits; // bit identifiying this level
306  int _wait; // number of unfinished cycles
307  pthread_t _pthr; // posix thread executing this level
308  ZCsema _trig; // sema used to trigger a cycle
309  ZCsema _done; // sema used to wait for a cycle
310  Inpnode* _inp_list; // linked list of active inputs
311  Outnode* _out_list; // linked list of active outputs
312  fftwf_plan _plan_r2c; // FFTW plan, forward FFT
313  fftwf_plan _plan_c2r; // FFTW plan, inverse FFT
314  float* _time_data; // workspace
315  float* _prep_data; // workspace
316  fftwf_complex* _freq_data; // workspace
317  float** _inpbuff; // array of shared input buffers
318  float** _outbuff; // array of shared output buffers
319 };
320 
321 // ----------------------------------------------------------------------------
322 
324 {
325 public:
326  Convproc (void);
327  ~Convproc (void);
328 
329  enum {
333  ST_PROC
334  };
335 
336  enum {
337  FL_LATE = 0x0000FFFF,
338  FL_LOAD = 0x01000000
339  };
340 
341  enum {
342  OPT_FFTW_MEASURE = Convlevel::OPT_FFTW_MEASURE,
343  OPT_VECTOR_MODE = Convlevel::OPT_VECTOR_MODE,
344  OPT_LATE_CONTIN = Convlevel::OPT_LATE_CONTIN
345  };
346 
347  enum {
348  MAXINP = 64,
349  MAXOUT = 64,
350  MAXLEV = 8,
351  MINPART = 64,
352  MAXPART = 8192,
353  MAXDIVIS = 16,
354  MINQUANT = 16,
355  MAXQUANT = 8192
356  };
357 
358  uint32_t state (void) const
359  {
360  return _state;
361  }
362 
363  float* inpdata (uint32_t inp) const
364  {
365  return _inpbuff[inp] + _inpoffs;
366  }
367 
368  float* outdata (uint32_t out) const
369  {
370  return _outbuff[out] + _outoffs;
371  }
372 
373  int configure (uint32_t ninp,
374  uint32_t nout,
375  uint32_t maxsize,
376  uint32_t quantum,
377  uint32_t minpart,
378  uint32_t maxpart,
379  float density);
380 
381  int impdata_create (uint32_t inp,
382  uint32_t out,
383  int32_t step,
384  float* data,
385  int32_t ind0,
386  int32_t ind1);
387 
388  int impdata_clear (uint32_t inp,
389  uint32_t out);
390 
391  void set_options (uint32_t options);
392 
393  int reset (void);
394 
395  int start_process (int abspri, int policy);
396 
397  int process ();
398  int tailonly (uint32_t n_samples);
399 
400  int stop_process (void);
401 
402  bool check_started (uint32_t);
403  bool check_stop (void);
404 
405  int cleanup (void);
406 
407  void print (FILE* F = stdout);
408 
409 private:
410  uint32_t _state; // current state
411  float* _inpbuff[MAXINP]; // input buffers
412  float* _outbuff[MAXOUT]; // output buffers
413  uint32_t _inpoffs; // current offset in input buffers
414  uint32_t _outoffs; // current offset in output buffers
415  uint32_t _options; // option bits
416  uint32_t _ninp; // number of inputs
417  uint32_t _nout; // number of outputs
418  uint32_t _quantum; // processing block size
419  uint32_t _minpart; // smallest partition size
420  uint32_t _maxpart; // largest allowed partition size
421  uint32_t _nlevels; // number of partition sizes
422  uint32_t _inpsize; // size of input buffers
423  uint32_t _latecnt; // count of cycles ending too late
424  Convlevel* _convlev[MAXLEV]; // array of processors
425  void* _dummy[64];
426 
427  static float _mac_cost;
428  static float _fft_cost;
429 };
430 
431 // ----------------------------------------------------------------------------
432 
433 } /* end namespace */
434 
435 #endif
volatile uint32_t _stat
void start(int absprio, int policy)
fftwf_complex * _freq_data
void configure(int prio, uint32_t offs, uint32_t npar, uint32_t parsize, uint32_t options)
void print(FILE *F)
void impdata_write(uint32_t inp, uint32_t out, int32_t step, float *data, int32_t ind0, int32_t ind1, bool create)
Macnode * findmacnode(uint32_t inp, uint32_t out, bool create)
int readtail(uint32_t n_samples)
void fftswap(fftwf_complex *p)
void impdata_clear(uint32_t inp, uint32_t out)
static void * static_main(void *arg)
void reset(uint32_t inpsize, uint32_t outsize, float **inpbuff, float **outbuff)
float * inpdata(uint32_t inp) const
bool check_started(uint32_t)
void set_options(uint32_t options)
int start_process(int abspri, int policy)
float * outdata(uint32_t out) const
static float _mac_cost
int configure(uint32_t ninp, uint32_t nout, uint32_t maxsize, uint32_t quantum, uint32_t minpart, uint32_t maxpart, float density)
int impdata_create(uint32_t inp, uint32_t out, int32_t step, float *data, int32_t ind0, int32_t ind1)
void print(FILE *F=stdout)
int tailonly(uint32_t n_samples)
uint32_t state(void) const
int impdata_clear(uint32_t inp, uint32_t out)
static float _fft_cost
void alloc_ffta(uint16_t npar, int32_t size)
void free_ffta(void)
fftwf_complex ** _ffta
Inpnode(uint16_t inp)
Macnode(Inpnode *inpn)
void free_fftb(void)
fftwf_complex ** _fftb
void alloc_fftb(uint16_t npar)
Outnode(uint16_t out, int32_t size)
bool init(bool try_optimization, const char *localedir, bool with_gui=false)
GTKMM_API const Gtk::BuiltinStockID FILE
Transmitter error
#define LIBZCONVOLVER_API