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