Guitarix
gx_convolver.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 convolver, part of gx_engine_audio ------- */
22 
23 #include "engine.h"
24 
25 /****************************************************************
26  ** some pieces in this file are copied from jconvolver
27  */
28 
29 /****************************************************************
30  ** AudioFile
31  */
32 
33 namespace gx_engine {
34 
36  reset();
37 }
38 
39 
41  close();
42 }
43 
44 
45 void Audiofile::reset(void) {
46  _sndfile = 0;
47  _type = TYPE_OTHER;
48  _form = FORM_OTHER;
49  _rate = 0;
50  _chan = 0;
51  _size = 0;
52 }
53 
54 
55 int Audiofile::open_read(string name) {
56  SF_INFO I;
57 
58  reset();
59 
60  if ((_sndfile = sf_open(name.c_str(), SFM_READ, &I)) == 0) return ERR_OPEN;
61 
62  switch (I.format & SF_FORMAT_TYPEMASK) {
63  case SF_FORMAT_CAF:
64  _type = TYPE_CAF;
65  break;
66  case SF_FORMAT_WAV:
67  _type = TYPE_WAV;
68  break;
69  case SF_FORMAT_WAVEX:
70 #ifdef SFC_WAVEX_GET_AMBISONIC
71  if (sf_command(_sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
72  _type = TYPE_AMB;
73  else
74 #endif
75  _type = TYPE_WAV;
76  }
77 
78  switch (I.format & SF_FORMAT_SUBMASK) {
79  case SF_FORMAT_PCM_16:
80  _form = FORM_16BIT;
81  break;
82  case SF_FORMAT_PCM_24:
83  _form = FORM_24BIT;
84  break;
85  case SF_FORMAT_PCM_32:
86  _form = FORM_32BIT;
87  break;
88  case SF_FORMAT_FLOAT:
89  _form = FORM_FLOAT;
90  break;
91  }
92 
93  _rate = I.samplerate;
94  _chan = I.channels;
95  _size = I.frames;
96 
97  return 0;
98 }
99 
100 
101 int Audiofile::close(void) {
102  if (_sndfile) sf_close(_sndfile);
103  reset();
104  return 0;
105 }
106 
107 
108 int Audiofile::seek(uint32_t posit) {
109  if (!_sndfile) return ERR_MODE;
110  if (sf_seek(_sndfile, posit, SEEK_SET) != posit) return ERR_SEEK;
111  return 0;
112 }
113 
114 
115 int Audiofile::read(float *data, uint32_t frames) {
116  return sf_readf_float(_sndfile, data, frames);
117 }
118 
119 bool read_audio(const std::string& filename, unsigned int *audio_size, int *audio_chan,
120  int *audio_type, int *audio_form, int *audio_rate, float **buffer) {
121  Audiofile audio;
122  if (audio.open_read(filename)) {
123  gx_print_error("jconvolver", "Unable to open '" + filename + "'");
124  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
125  *buffer = 0;
126  return false;
127  }
128  *audio_size = audio.size();
129  *audio_chan = audio.chan();
130  *audio_type = audio.type();
131  *audio_form = audio.form();
132  *audio_rate = audio.rate();
133  const unsigned int limit = 2000000; // arbitrary size limit
134  if (*audio_size > limit) {
136  "jconvolver", (boost::format(_("too many samples (%1%), truncated to %2%"))
137  % *audio_size % limit).str());
138  *audio_size = limit;
139  }
140  if (*audio_size * *audio_chan == 0) {
141  gx_print_error("jconvolver", "No samples found");
142  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
143  *buffer = 0;
144  return false;
145  }
146  *buffer = new float[*audio_size * *audio_chan];
147  if (audio.read(*buffer, *audio_size) != static_cast<int>(*audio_size)) {
148  delete[] *buffer;
149  gx_print_error("jconvolver", "Error reading file");
150  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
151  *buffer = 0;
152  return false;
153  }
154  return true;
155 }
156 
157 /****************************************************************
158  ** GxConvolverBase
159  */
160 
162  if (is_runnable()) {
163  stop_process();
164  }
165 }
166 
168  unsigned int audio_size, unsigned int& count, unsigned int& offset,
169  unsigned int& delay, unsigned int& ldelay, unsigned int& length,
170  unsigned int& size, unsigned int& bufsize) {
171 
172  if (bufsize < count) {
173  bufsize = count;
174  }
175  if (bufsize < Convproc::MINPART) {
176  bufsize = Convproc::MINPART;
177  }
178  if (offset > audio_size) {
179  offset = audio_size;
180  }
181  if (!size) {
182  if (offset + length > audio_size) {
184  "convolver",
185  (boost::format("length adjusted (%1% + %2% > %3%")
186  % offset % length % audio_size).str());
187  length = audio_size - offset;
188  }
189  if (!length) {
190  length = audio_size - offset;
191  }
192  size = max(delay, ldelay) + offset + length;
193  } else {
194  if (delay > size) {
195  delay = size;
196  }
197  if (ldelay > size) {
198  ldelay = size;
199  }
200  if (offset > size - max(delay, ldelay)) {
201  offset = size - max(delay, ldelay);
202  }
203  if (length > size - max(delay, ldelay) - offset) {
204  length = size - max(delay, ldelay) - offset;
205  gx_print_warning("convolver", "data truncated");
206  }
207  if (!length) {
208  length = size - max(delay, ldelay) - offset;
209  }
210  }
211 }
212 
213 bool GxConvolverBase::start(int policy, int priority) {
214  int rc = start_process(priority, policy);
215  if (rc != 0) {
216  gx_print_error("convolver", "can't start convolver");
217  return false;
218  }
219  ready = true;
220  return true;
221 }
222 
224  if (state() == Convproc::ST_WAIT) {
225  if (check_stop()) {
226  ready = false;
227  } else {
228  return false;
229  }
230  } else if (state() == ST_STOP) {
231  ready = false;
232  }
233  return true;
234 }
235 
236 /****************************************************************
237  ** GxConvolver
238  */
239 
240 /*
241 ** GxConvolver::read_sndfile()
242 **
243 ** read samples from soundfile into convolver
244 ** the convolver is working at rate samplerate, the audio file has audio.rate
245 **
246 ** offset, length, points are based on audio.rate, delay and the count of
247 ** samples written into the convolver are based on samplerate.
248 **
249 ** Arguments:
250 ** Audiofile& audio already opened, will be converted to samplerate
251 ** on the fly
252 ** int nchan channel count for convolver (can be less
253 ** or more than audio.chan())
254 ** int samplerate current engine samplerate
255 ** const float *gain array[nchan] of gains to be applied
256 ** unsigned int *delay array[nchan], starting sample index for values
257 ** stored into convolver
258 ** unsigned int offset offset into audio file
259 ** unsigned int length number of samples to be read from audio
260 ** const Gainline& points gain line to be applied
261 **
262 ** returns false if some error occurred, else true
263 */
264 bool GxConvolver::read_sndfile(
265  Audiofile& audio, int nchan, int samplerate, const float *gain,
266  unsigned int *delay, unsigned int offset, unsigned int length,
267  const Gainline& points) {
268  int nfram;
269  float *buff;
270  float *rbuff = 0;
271  float *bufp;
272  // keep BSIZE big enough so that resamp.flush() doesn't cause overflow
273  // (> 100 should be enough, and should be kept bigger anyhow)
274  const unsigned int BSIZE = 0x8000; // 0x4000;
275 
276 
277  if (offset && audio.seek(offset)) {
278  gx_print_error("convolver", "Can't seek to offset");
279  audio.close();
280  return false;
281  }
282  try {
283  buff = new float[BSIZE * audio.chan()];
284  } catch(...) {
285  audio.close();
286  gx_print_error("convolver", "out of memory");
287  return false;
288  }
289  if (samplerate != audio.rate()) {
291  "convolver", Glib::ustring::compose(
292  _("resampling from %1 to %2"), audio.rate(), samplerate));
293  if (!resamp.setup(audio.rate(), samplerate, audio.chan())) {
294  gx_print_error("convolver", "resample failure");
295  assert(false);
296  return false;
297  }
298  try {
299  rbuff = new float[resamp.get_max_out_size(BSIZE)*audio.chan()];
300  } catch(...) {
301  audio.close();
302  gx_print_error("convolver", "out of memory");
303  return false;
304  }
305  bufp = rbuff;
306  } else {
307  bufp = buff;
308  }
309  bool done = false;
310  unsigned int idx = 0; // current index in gainline point array
311  double gp = 0.0, fct = 0.0; // calculated parameter of interpolation line
312  if (points.size()) {
313  while ((unsigned int)points[idx].i < offset) {
314  idx++;
315  assert(idx < points.size());
316  }
317  if ((unsigned int)points[idx].i > offset) {
318  idx--;
319  compute_interpolation(fct, gp, idx, points, offset);
320  }
321  }
322 
323  while (!done) {
324  unsigned int cnt;
325  nfram = (length > BSIZE) ? BSIZE : length;
326  if (length) {
327  nfram = audio.read(buff, nfram);
328  if (nfram < 0) {
329  gx_print_error("convolver", "Error reading file");
330  audio.close();
331  delete[] buff;
332  delete[] rbuff;
333  return false;
334  }
335  for (int ix = 0; ix < nfram; ix++) {
336  if (idx+1 < points.size() && (unsigned int)points[idx].i == offset + ix) {
337  compute_interpolation(fct, gp, idx, points, offset);
338  }
339 
340  for (int ichan = 0; ichan < min(audio.chan(), nchan); ichan++) {
341  buff[ix*audio.chan()+ichan] *= pow(10, gp + ix*fct) * gain[ichan];
342  }
343  }
344  offset += nfram;
345  gp += nfram*fct;
346  cnt = nfram;
347  if (rbuff) {
348  cnt = resamp.process(nfram, buff, rbuff);
349  }
350  } else {
351  if (rbuff) {
352  cnt = resamp.flush(rbuff);
353  done = true;
354  } else {
355  break;
356  }
357  }
358  if (cnt) {
359 
360  for (int ichan = 0; ichan < nchan; ichan++) {
361  int rc;
362  if (ichan >= audio.chan()) {
363  rc = impdata_copy(0, 0, ichan, ichan);
364  } else {
365  rc = impdata_create(ichan, ichan, audio.chan(), bufp + ichan,
366  delay[ichan], delay[ichan] + cnt);
367  }
368  if (rc) {
369  audio.close();
370  delete[] buff;
371  delete[] rbuff;
372  gx_print_error("convolver", "out of memory");
373  return false;
374  }
375  delay[ichan] += cnt;
376  }
377  length -= nfram;
378  }
379  }
380 
381  audio.close();
382  delete[] buff;
383  delete[] rbuff;
384 
385  return true;
386 }
387 
389  string fname, float gain, float lgain,
390  unsigned int delay, unsigned int ldelay, unsigned int offset,
391  unsigned int length, unsigned int size, unsigned int bufsize,
392  const Gainline& points) {
393  Audiofile audio;
394  cleanup();
395  if (fname.empty()) {
396  return false;
397  }
398  if (audio.open_read(fname)) {
399  gx_print_error("convolver", Glib::ustring::compose("Unable to open '%1'", fname));
400  return false;
401  }
402  if (audio.chan() > 2) {
404  "convolver",
405  Glib::ustring::compose("only taking first 2 of %1 channels in impulse response", audio.chan()));
406  return false;
407  }
408  adjust_values(audio.size(), buffersize, offset, delay, ldelay, length, size, bufsize);
409 
410  if (samplerate != static_cast<unsigned int>(audio.rate())) {
411  float f = float(samplerate) / audio.rate();
412  size = round(size * f) + 2; // 2 is safety margin for rounding differences
413  delay = round(delay * f);
414  ldelay = round(ldelay * f);
415  }
416  if (Convproc::configure(2, 2, size, buffersize, bufsize, Convproc::MAXPART)) {
417  gx_print_error("convolver", "error in Convproc::configure ");
418  return false;
419  }
420 
421  float gain_a[2] = {gain, lgain};
422  unsigned int delay_a[2] = {delay, ldelay};
423  return read_sndfile(audio, 2, samplerate, gain_a, delay_a, offset, length, points);
424 }
425 
426 bool __rt_func GxConvolver::compute(int count, float* input1, float *input2,
427  float *output1, float *output2) {
428  if (state() != Convproc::ST_PROC) {
429  if (input1 != output1) {
430  memcpy(output1, input1, count * sizeof(float));
431  }
432  if (input2 != output2) {
433  memcpy(output2, input2, count * sizeof(float));
434  }
435  if (state() == Convproc::ST_WAIT) {
436  check_stop();
437  }
438  if (state() == ST_STOP) {
439  ready = false;
440  }
441  return true;
442  }
443  memcpy(inpdata(0), input1, count * sizeof(float));
444  memcpy(inpdata(1), input2, count * sizeof(float));
445 
446  int flags = process(sync);
447 
448  memcpy(output1, outdata(0), count * sizeof(float));
449  memcpy(output2, outdata(1), count * sizeof(float));
450  return flags == 0;
451 }
452 
453 bool GxConvolver::configure(string fname, float gain, unsigned int delay, unsigned int offset,
454  unsigned int length, unsigned int size, unsigned int bufsize,
455  const Gainline& points) {
456  Audiofile audio;
457  cleanup();
458  if (fname.empty()) {
459  return false;
460  }
461  if (audio.open_read(fname)) {
462  gx_print_error("convolver", Glib::ustring::compose("Unable to open '%1'", fname));
463  return false;
464  }
465  if (audio.chan() > 1) {
467  "convolver",
468  Glib::ustring::compose("only taking first channel of %1 channels in impulse response", audio.chan()));
469  return false;
470  }
471  unsigned int ldelay = delay;
472  adjust_values(audio.size(), buffersize, offset, delay, ldelay, length, size, bufsize);
473 
474  if (samplerate != static_cast<unsigned int>(audio.rate())) {
475  float f = float(samplerate) / audio.rate();
476  size = round(size * f) + 2; // 2 is safety margin for rounding differences
477  delay = round(delay * f);
478  }
479  if (Convproc::configure(1, 1, size, buffersize, bufsize, Convproc::MAXPART)) {
480  gx_print_error("convolver", "error in Convproc::configure ");
481  return false;
482  }
483 
484  float gain_a[1] = {gain};
485  unsigned int delay_a[1] = {delay};
486  return read_sndfile(audio, 1, samplerate, gain_a, delay_a, offset, length, points);
487 }
488 
489 bool __rt_func GxConvolver::compute(int count, float* input, float *output) {
490  if (state() != Convproc::ST_PROC) {
491  if (input != output) {
492  memcpy(output, input, count * sizeof(float));
493  }
494  if (state() == Convproc::ST_WAIT) {
495  check_stop();
496  }
497  if (state() == ST_STOP) {
498  ready = false;
499  }
500  return true;
501  }
502  memcpy(inpdata(0), input, count * sizeof(float));
503 
504  int flags = process(sync);
505 
506  memcpy(output, outdata(0), count * sizeof(float));
507  return flags == 0;
508 }
509 
510 
511 /****************************************************************
512  ** GxSimpleConvolver
513  */
514 
516 private:
517  float *vec;
519 public:
520  CheckResample(gx_resample::BufferResampler& resamp_): vec(0), resamp(resamp_) {}
521  float *resample(int *count, float *impresp, unsigned int imprate, unsigned int samplerate) {
522  if (imprate != samplerate) {
523  vec = resamp.process(imprate, *count, impresp, samplerate, count);
524  if (!vec) {
525  boost::format msg = boost::format("failed to resample %1% -> %2%") % imprate % samplerate;
526  if (samplerate) {
527  gx_print_error("convolver", msg);
528  } else {
529  // not need for extra error when no samplerate (probably not connected to jack)
530  gx_print_warning("convolver", msg);
531  }
532  return 0;
533  }
534  return vec;
535  }
536  return impresp;
537  }
539  if (vec) {
540  delete vec;
541  }
542  }
543 };
544 
545 bool GxSimpleConvolver::configure(int count, float *impresp, unsigned int imprate) {
546  CheckResample r(resamp);
547  impresp = r.resample(&count, impresp, imprate, samplerate);
548  if (!impresp) {
549  return false;
550  }
551  cleanup();
552  unsigned int bufsize = buffersize;
553  if (bufsize < Convproc::MINPART) {
554  bufsize = Convproc::MINPART;
555  }
556  if (Convproc::configure(1, 1, count, buffersize,
557  bufsize, Convproc::MAXPART)) {
558  gx_print_error("convolver", "error in Convproc::configure");
559  return false;
560  }
561  if (impdata_create(0, 0, 1, impresp, 0, count)) {
562  gx_print_error("convolver", "out of memory");
563  return false;
564  }
565  return true;
566 }
567 
568 bool GxSimpleConvolver::update(int count, float *impresp, unsigned int imprate) {
569  CheckResample r(resamp);
570  impresp = r.resample(&count, impresp, imprate, samplerate);
571  if (!impresp) {
572  return false;
573  }
574  if (impdata_update(0, 0, 1, impresp, 0, count)) {
575  gx_print_error("convolver", "update: internal error");
576  return false;
577  }
578  return true;
579 }
580 
581 bool __rt_func GxSimpleConvolver::compute(int count, float* input, float *output) {
582  if (state() != Convproc::ST_PROC) {
583  if (input != output) {
584  memcpy(output, input, count * sizeof(float));
585  }
586  if (state() == Convproc::ST_WAIT) {
587  check_stop();
588  }
589  if (state() == ST_STOP) {
590  ready = false;
591  }
592  return true;
593  }
594  memcpy(inpdata(0), input, count * sizeof(float));
595 
596  int flags = process(sync);
597 
598  memcpy(output, outdata(0), count * sizeof(float));
599  return flags == 0;
600 }
601 
602 }
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
int rate(void) const
Definition: gx_convolver.h:72
bool start(int policy, int priority)
bool configure(int count, float *impresp, unsigned int imprate)
#define __rt_func
Definition: gx_compiler.h:4
bool compute(int count, float *input, float *output)
int open_read(string name)
bool read_audio(const std::string &filename, unsigned int *audio_size, int *audio_chan, int *audio_type, int *audio_form, int *audio_rate, float **buffer)
float * process(int fs_inp, int ilen, float *input, int fs_outp, int *olen)
void adjust_values(unsigned int audio_size, unsigned int &count, unsigned int &offset, unsigned int &delay, unsigned int &ldelay, unsigned int &length, unsigned int &size, unsigned int &bufsize)
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
int seek(unsigned int posit)
#define min(x, y)
bool compute(int count, float *input1, float *input2, float *output1, float *output2)
bool update(int count, float *impresp, unsigned int imprate)
#define max(x, y)
int type(void) const
Definition: gx_convolver.h:70
bool configure(string fname, float gain, float lgain, unsigned int delay, unsigned int ldelay, unsigned int offset, unsigned int length, unsigned int size, unsigned int bufsize, const Gainline &gainline)
unsigned int size(void) const
Definition: gx_convolver.h:74
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
int form(void) const
Definition: gx_convolver.h:71
float * resample(int *count, float *impresp, unsigned int imprate, unsigned int samplerate)
CheckResample(gx_resample::BufferResampler &resamp_)
int read(float *data, unsigned int frames)
int chan(void) const
Definition: gx_convolver.h:73