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_AIFF:
70  _type = TYPE_AIFF;
71  break;
72  case SF_FORMAT_WAVEX:
73 #ifdef SFC_WAVEX_GET_AMBISONIC
74  if (sf_command(_sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
75  _type = TYPE_AMB;
76  else
77 #endif
78  _type = TYPE_WAV;
79  }
80 
81  switch (I.format & SF_FORMAT_SUBMASK) {
82  case SF_FORMAT_PCM_16:
83  _form = FORM_16BIT;
84  break;
85  case SF_FORMAT_PCM_24:
86  _form = FORM_24BIT;
87  break;
88  case SF_FORMAT_PCM_32:
89  _form = FORM_32BIT;
90  break;
91  case SF_FORMAT_FLOAT:
92  _form = FORM_FLOAT;
93  break;
94  }
95 
96  _rate = I.samplerate;
97  _chan = I.channels;
98  _size = I.frames;
99 
100  return 0;
101 }
102 
103 
104 int Audiofile::close(void) {
105  if (_sndfile) sf_close(_sndfile);
106  reset();
107  return 0;
108 }
109 
110 
111 int Audiofile::seek(uint32_t posit) {
112  if (!_sndfile) return ERR_MODE;
113  if (sf_seek(_sndfile, posit, SEEK_SET) != posit) return ERR_SEEK;
114  return 0;
115 }
116 
117 
118 int Audiofile::read(float *data, uint32_t frames) {
119  return sf_readf_float(_sndfile, data, frames);
120 }
121 
122 bool read_audio(const std::string& filename, unsigned int *audio_size, int *audio_chan,
123  int *audio_type, int *audio_form, int *audio_rate, float **buffer) {
124  Audiofile audio;
125  if (audio.open_read(filename)) {
126  gx_print_error("jconvolver", "Unable to open '" + filename + "'");
127  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
128  *buffer = 0;
129  return false;
130  }
131  *audio_size = audio.size();
132  *audio_chan = audio.chan();
133  *audio_type = audio.type();
134  *audio_form = audio.form();
135  *audio_rate = audio.rate();
136  const unsigned int limit = 2000000; // arbitrary size limit
137  if (*audio_size > limit) {
139  "jconvolver", (boost::format(_("too many samples (%1%), truncated to %2%"))
140  % *audio_size % limit).str());
141  *audio_size = limit;
142  }
143  if (*audio_size * *audio_chan == 0) {
144  gx_print_error("jconvolver", "No samples found");
145  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
146  *buffer = 0;
147  return false;
148  }
149  *buffer = new float[*audio_size * *audio_chan];
150  if (audio.read(*buffer, *audio_size) != static_cast<int>(*audio_size)) {
151  delete[] *buffer;
152  gx_print_error("jconvolver", "Error reading file");
153  *audio_size = *audio_chan = *audio_type = *audio_form = *audio_rate = 0;
154  *buffer = 0;
155  return false;
156  }
157  return true;
158 }
159 
160 /****************************************************************
161  ** GxConvolverBase
162  */
163 
165  if (is_runnable()) {
166  stop_process();
167  }
168 }
169 
171  unsigned int audio_size, unsigned int& count, unsigned int& offset,
172  unsigned int& delay, unsigned int& ldelay, unsigned int& length,
173  unsigned int& size, unsigned int& bufsize) {
174 
175  if (bufsize < count) {
176  bufsize = count;
177  }
178  if (bufsize < Convproc::MINPART) {
179  bufsize = Convproc::MINPART;
180  }
181  if (offset > audio_size) {
182  offset = audio_size;
183  }
184  if (!size) {
185  if (offset + length > audio_size) {
187  "convolver",
188  (boost::format("length adjusted (%1% + %2% > %3%")
189  % offset % length % audio_size).str());
190  length = audio_size - offset;
191  }
192  if (!length) {
193  length = audio_size - offset;
194  }
195  size = max(delay, ldelay) + offset + length;
196  } else {
197  if (delay > size) {
198  delay = size;
199  }
200  if (ldelay > size) {
201  ldelay = size;
202  }
203  if (offset > size - max(delay, ldelay)) {
204  offset = size - max(delay, ldelay);
205  }
206  if (length > size - max(delay, ldelay) - offset) {
207  length = size - max(delay, ldelay) - offset;
208  gx_print_warning("convolver", "data truncated");
209  }
210  if (!length) {
211  length = size - max(delay, ldelay) - offset;
212  }
213  }
214 }
215 
216 bool GxConvolverBase::start(int policy, int priority) {
217  int rc = start_process(priority, policy);
218  if (rc != 0) {
219  gx_print_error("convolver", "can't start convolver");
220  return false;
221  }
222  ready = true;
223  return true;
224 }
225 
227  if (state() == Convproc::ST_WAIT) {
228  if (check_stop()) {
229  ready = false;
230  } else {
231  return false;
232  }
233  } else if (state() == ST_STOP) {
234  ready = false;
235  }
236  return true;
237 }
238 
239 /****************************************************************
240  ** GxConvolver
241  */
242 
243 /*
244 ** GxConvolver::read_sndfile()
245 **
246 ** read samples from soundfile into convolver
247 ** the convolver is working at rate samplerate, the audio file has audio.rate
248 **
249 ** offset, length, points are based on audio.rate, delay and the count of
250 ** samples written into the convolver are based on samplerate.
251 **
252 ** Arguments:
253 ** Audiofile& audio already opened, will be converted to samplerate
254 ** on the fly
255 ** int nchan channel count for convolver (can be less
256 ** or more than audio.chan())
257 ** int samplerate current engine samplerate
258 ** const float *gain array[nchan] of gains to be applied
259 ** unsigned int *delay array[nchan], starting sample index for values
260 ** stored into convolver
261 ** unsigned int offset offset into audio file
262 ** unsigned int length number of samples to be read from audio
263 ** const Gainline& points gain line to be applied
264 **
265 ** returns false if some error occurred, else true
266 */
267 bool GxConvolver::read_sndfile(
268  Audiofile& audio, int nchan, int samplerate, const float *gain,
269  unsigned int *delay, unsigned int offset, unsigned int length,
270  const Gainline& points) {
271  int nfram;
272  float *buff;
273  float *rbuff = 0;
274  float *bufp;
275  // keep BSIZE big enough so that resamp.flush() doesn't cause overflow
276  // (> 100 should be enough, and should be kept bigger anyhow)
277  const unsigned int BSIZE = 0x8000; // 0x4000;
278 
279 
280  if (offset && audio.seek(offset)) {
281  gx_print_error("convolver", "Can't seek to offset");
282  audio.close();
283  return false;
284  }
285  try {
286  buff = new float[BSIZE * audio.chan()];
287  } catch(...) {
288  audio.close();
289  gx_print_error("convolver", "out of memory");
290  return false;
291  }
292  if (samplerate != audio.rate()) {
294  "convolver", Glib::ustring::compose(
295  _("resampling from %1 to %2"), audio.rate(), samplerate));
296  if (!resamp.setup(audio.rate(), samplerate, audio.chan())) {
297  gx_print_error("convolver", "resample failure");
298  assert(false);
299  return false;
300  }
301  try {
302  rbuff = new float[resamp.get_max_out_size(BSIZE)*audio.chan()];
303  } catch(...) {
304  audio.close();
305  gx_print_error("convolver", "out of memory");
306  return false;
307  }
308  bufp = rbuff;
309  } else {
310  bufp = buff;
311  }
312  bool done = false;
313  unsigned int idx = 0; // current index in gainline point array
314  double gp = 0.0, fct = 0.0; // calculated parameter of interpolation line
315  if (points.size()) {
316  while ((unsigned int)points[idx].i < offset) {
317  idx++;
318  assert(idx < points.size());
319  }
320  if ((unsigned int)points[idx].i > offset) {
321  idx--;
322  compute_interpolation(fct, gp, idx, points, offset);
323  }
324  }
325 
326  while (!done) {
327  unsigned int cnt;
328  nfram = (length > BSIZE) ? BSIZE : length;
329  if (length) {
330  nfram = audio.read(buff, nfram);
331  if (nfram < 0) {
332  gx_print_error("convolver", "Error reading file");
333  audio.close();
334  delete[] buff;
335  delete[] rbuff;
336  return false;
337  }
338  for (int ix = 0; ix < nfram; ix++) {
339  if (idx+1 < points.size() && (unsigned int)points[idx].i == offset + ix) {
340  compute_interpolation(fct, gp, idx, points, offset);
341  }
342 
343  for (int ichan = 0; ichan < min(audio.chan(), nchan); ichan++) {
344  buff[ix*audio.chan()+ichan] *= pow(10, gp + ix*fct) * gain[ichan];
345  }
346  }
347  offset += nfram;
348  gp += nfram*fct;
349  cnt = nfram;
350  if (rbuff) {
351  cnt = resamp.process(nfram, buff, rbuff);
352  }
353  } else {
354  if (rbuff) {
355  cnt = resamp.flush(rbuff);
356  done = true;
357  } else {
358  break;
359  }
360  }
361  if (cnt) {
362 
363  for (int ichan = 0; ichan < nchan; ichan++) {
364  int rc;
365  if (ichan >= audio.chan()) {
366  rc = impdata_copy(0, 0, ichan, ichan);
367  } else {
368  rc = impdata_create(ichan, ichan, audio.chan(), bufp + ichan,
369  delay[ichan], delay[ichan] + cnt);
370  }
371  if (rc) {
372  audio.close();
373  delete[] buff;
374  delete[] rbuff;
375  gx_print_error("convolver", "out of memory");
376  return false;
377  }
378  delay[ichan] += cnt;
379  }
380  length -= nfram;
381  }
382  }
383 
384  audio.close();
385  delete[] buff;
386  delete[] rbuff;
387 
388  return true;
389 }
390 
392  string fname, float gain, float lgain,
393  unsigned int delay, unsigned int ldelay, unsigned int offset,
394  unsigned int length, unsigned int size, unsigned int bufsize,
395  const Gainline& points) {
396  Audiofile audio;
397  cleanup();
398  if (fname.empty()) {
399  return false;
400  }
401  if (audio.open_read(fname)) {
402  gx_print_error("convolver", Glib::ustring::compose("Unable to open '%1'", fname));
403  return false;
404  }
405  if (audio.chan() > 2) {
407  "convolver",
408  Glib::ustring::compose("only taking first 2 of %1 channels in impulse response", audio.chan()));
409  return false;
410  }
411  adjust_values(audio.size(), buffersize, offset, delay, ldelay, length, size, bufsize);
412 
413  if (samplerate != static_cast<unsigned int>(audio.rate())) {
414  float f = float(samplerate) / audio.rate();
415  size = round(size * f) + 2; // 2 is safety margin for rounding differences
416  delay = round(delay * f);
417  ldelay = round(ldelay * f);
418  }
419  if (Convproc::configure(2, 2, size, buffersize, bufsize, Convproc::MAXPART)) {
420  gx_print_error("convolver", "error in Convproc::configure ");
421  return false;
422  }
423 
424  float gain_a[2] = {gain, lgain};
425  unsigned int delay_a[2] = {delay, ldelay};
426  return read_sndfile(audio, 2, samplerate, gain_a, delay_a, offset, length, points);
427 }
428 
429 bool __rt_func GxConvolver::compute(int count, float* input1, float *input2,
430  float *output1, float *output2) {
431  if (state() != Convproc::ST_PROC) {
432  if (input1 != output1) {
433  memcpy(output1, input1, count * sizeof(float));
434  }
435  if (input2 != output2) {
436  memcpy(output2, input2, count * sizeof(float));
437  }
438  if (state() == Convproc::ST_WAIT) {
439  check_stop();
440  }
441  if (state() == ST_STOP) {
442  ready = false;
443  }
444  return true;
445  }
446  memcpy(inpdata(0), input1, count * sizeof(float));
447  memcpy(inpdata(1), input2, count * sizeof(float));
448 
449  int flags = process(sync);
450 
451  memcpy(output1, outdata(0), count * sizeof(float));
452  memcpy(output2, outdata(1), count * sizeof(float));
453  return flags == 0;
454 }
455 
456 bool GxConvolver::configure(string fname, float gain, unsigned int delay, unsigned int offset,
457  unsigned int length, unsigned int size, unsigned int bufsize,
458  const Gainline& points) {
459  Audiofile audio;
460  cleanup();
461  if (fname.empty()) {
462  return false;
463  }
464  if (audio.open_read(fname)) {
465  gx_print_error("convolver", Glib::ustring::compose("Unable to open '%1'", fname));
466  return false;
467  }
468  if (audio.chan() > 1) {
470  "convolver",
471  Glib::ustring::compose("only taking first channel of %1 channels in impulse response", audio.chan()));
472  return false;
473  }
474  unsigned int ldelay = delay;
475  adjust_values(audio.size(), buffersize, offset, delay, ldelay, length, size, bufsize);
476 
477  if (samplerate != static_cast<unsigned int>(audio.rate())) {
478  float f = float(samplerate) / audio.rate();
479  size = round(size * f) + 2; // 2 is safety margin for rounding differences
480  delay = round(delay * f);
481  }
482  if (Convproc::configure(1, 1, size, buffersize, bufsize, Convproc::MAXPART)) {
483  gx_print_error("convolver", "error in Convproc::configure ");
484  return false;
485  }
486 
487  float gain_a[1] = {gain};
488  unsigned int delay_a[1] = {delay};
489  return read_sndfile(audio, 1, samplerate, gain_a, delay_a, offset, length, points);
490 }
491 
492 bool __rt_func GxConvolver::compute(int count, float* input, float *output) {
493  if (state() != Convproc::ST_PROC) {
494  if (input != output) {
495  memcpy(output, input, count * sizeof(float));
496  }
497  if (state() == Convproc::ST_WAIT) {
498  check_stop();
499  }
500  if (state() == ST_STOP) {
501  ready = false;
502  }
503  return true;
504  }
505  memcpy(inpdata(0), input, count * sizeof(float));
506 
507  int flags = process(sync);
508 
509  memcpy(output, outdata(0), count * sizeof(float));
510  return flags == 0;
511 }
512 
513 
514 /****************************************************************
515  ** GxSimpleConvolver
516  */
517 
519 private:
520  float *vec;
522 public:
523  CheckResample(gx_resample::BufferResampler& resamp_): vec(0), resamp(resamp_) {}
524  float *resample(int *count, float *impresp, unsigned int imprate, unsigned int samplerate) {
525  if (imprate != samplerate) {
526  vec = resamp.process(imprate, *count, impresp, samplerate, count);
527  if (!vec) {
528  boost::format msg = boost::format("failed to resample %1% -> %2%") % imprate % samplerate;
529  if (samplerate) {
530  gx_print_error("convolver", msg);
531  } else {
532  // not need for extra error when no samplerate (probably not connected to jack)
533  gx_print_warning("convolver", msg);
534  }
535  return 0;
536  }
537  return vec;
538  }
539  return impresp;
540  }
542  if (vec) {
543  delete vec;
544  }
545  }
546 };
547 
548 bool GxSimpleConvolver::configure(int count, float *impresp, unsigned int imprate) {
549  CheckResample r(resamp);
550  impresp = r.resample(&count, impresp, imprate, samplerate);
551  if (!impresp) {
552  return false;
553  }
554  cleanup();
555  unsigned int bufsize = buffersize;
556  if (bufsize < Convproc::MINPART) {
557  bufsize = Convproc::MINPART;
558  }
559  if (Convproc::configure(1, 1, count, buffersize,
560  bufsize, Convproc::MAXPART)) {
561  gx_print_error("convolver", "error in Convproc::configure");
562  return false;
563  }
564  if (impdata_create(0, 0, 1, impresp, 0, count)) {
565  gx_print_error("convolver", "out of memory");
566  return false;
567  }
568  return true;
569 }
570 
571 bool GxSimpleConvolver::update(int count, float *impresp, unsigned int imprate) {
572  CheckResample r(resamp);
573  impresp = r.resample(&count, impresp, imprate, samplerate);
574  if (!impresp) {
575  return false;
576  }
577  if (impdata_update(0, 0, 1, impresp, 0, count)) {
578  gx_print_error("convolver", "update: internal error");
579  return false;
580  }
581  return true;
582 }
583 
584 bool __rt_func GxSimpleConvolver::compute(int count, float* input, float *output) {
585  if (state() != Convproc::ST_PROC) {
586  if (input != output) {
587  memcpy(output, input, count * sizeof(float));
588  }
589  if (state() == Convproc::ST_WAIT) {
590  check_stop();
591  }
592  if (state() == ST_STOP) {
593  ready = false;
594  }
595  return true;
596  }
597  memcpy(inpdata(0), input, count * sizeof(float));
598 
599  int flags = process(sync);
600 
601  memcpy(output, outdata(0), count * sizeof(float));
602  return flags == 0;
603 }
604 
606 
607 bool GxSimpleConvolver::configure_stereo(int count, float *impresp, unsigned int imprate)
608 {
609  //printf("try configure()\n");
610  CheckResample r(resamp);
611  impresp = r.resample(&count, impresp, imprate, samplerate);
612  if (!impresp)
613  {
614  printf("no impresp\n");
615  return false;
616  }
617  cleanup();
618  unsigned int bufsize = buffersize;
619  if (bufsize < Convproc::MINPART)
620  {
621  bufsize = Convproc::MINPART;
622  }
623  if (Convproc::configure(2, 2, count, buffersize,
624  bufsize, bufsize)) // Convproc::MAXPART
625  {
626  printf("no configure\n");
627  return false;
628  }
629  if (impdata_create(0, 0, 1, impresp, 0, count) & impdata_create(1, 1, 1, impresp, 0, count))
630  {
631  printf("no impdata_create()\n");
632  return false;
633  }
634  //printf("configure()\n");
635 
636  return true;
637 }
638 
639 bool GxSimpleConvolver::update_stereo(int count, float *impresp, unsigned int imprate)
640 {
641  CheckResample r(resamp);
642  impresp = r.resample(&count, impresp, imprate, samplerate);
643  if (!impresp)
644  {
645  return false;
646  }
647  if (impdata_update(0, 0, 1, impresp, 0, count) & impdata_update(1, 1, 1, impresp, 0, count))
648  {
649  return false;
650  }
651  return true;
652 }
653 
654 bool __rt_func GxSimpleConvolver::compute_stereo(int count, float* input, float* input1, float *output, float *output1)
655 {
656  // printf("try run\n");
657  if (state() != Convproc::ST_PROC)
658  {
659  //printf("state() != ST_PROC\n");
660  if (input != output)
661  {
662  memcpy(output, input, count * sizeof(float));
663  memcpy(output1, input1, count * sizeof(float));
664  }
665  if (state() == Convproc::ST_WAIT)
666  {
667  //printf("state() == ST_WAIT\n");
668  check_stop();
669  }
670  if (state() == ST_STOP)
671  {
672  //printf("state() == ST_STOP\n");
673  ready = false;
674  }
675  return true;
676  }
677  int flags = 0;
678  if (static_cast<unsigned int>(count) == buffersize)
679  {
680  memcpy(inpdata(0), input, count * sizeof(float));
681  memcpy(inpdata(1), input1, count * sizeof(float));
682 
683  flags = process(sync);
684 
685  memcpy(output, outdata(0), count * sizeof(float));
686  memcpy(output1, outdata(1), count * sizeof(float));
687  } else {
688  float *in, *in1, *out, *out1;
689  in = inpdata(0);
690  in1 = inpdata(1);
691  out = outdata(0);
692  out1 = outdata(1);
693  unsigned int b = 0;
694  unsigned int c = 1;
695  for(int i = 0; i<count; ++i){
696  in[b] = input[i];
697  in1[b] = input1[i];
698  if(++b == buffersize) {
699  b=0;
700  flags = process();
701  for(unsigned int d = 0; d<buffersize; ++d) {
702  output[d*c] = out[d];
703  output1[d*c] = out1[d];
704  }
705  ++c;
706  }
707  }
708  }
709  return flags == 0;
710 }
711 
712 }
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
bool update_stereo(int count, float *impresp, unsigned int imprate)
int chan(void) const
Definition: gx_convolver.h:74
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
unsigned int size(void) const
Definition: gx_convolver.h:75
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)
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)
int type(void) const
Definition: gx_convolver.h:71
bool compute_stereo(int count, float *input, float *input1, float *output, float *output1)
int rate(void) const
Definition: gx_convolver.h:73
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
bool configure_stereo(int count, float *impresp, unsigned int imprate)
float * resample(int *count, float *impresp, unsigned int imprate, unsigned int samplerate)
CheckResample(gx_resample::BufferResampler &resamp_)
int form(void) const
Definition: gx_convolver.h:72
int read(float *data, unsigned int frames)