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 
Audiofile(void)35 Audiofile::Audiofile(void) {
36     reset();
37 }
38 
39 
~Audiofile(void)40 Audiofile::~Audiofile(void) {
41     close();
42 }
43 
44 
reset(void)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 
open_read(string name)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 
close(void)104 int Audiofile::close(void) {
105     if (_sndfile) sf_close(_sndfile);
106     reset();
107     return 0;
108 }
109 
110 
seek(uint32_t posit)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 
read(float * data,uint32_t frames)118 int Audiofile::read(float *data, uint32_t frames) {
119     return sf_readf_float(_sndfile, data, frames);
120 }
121 
read_audio(const std::string & filename,unsigned int * audio_size,int * audio_chan,int * audio_type,int * audio_form,int * audio_rate,float ** buffer)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) {
138         gx_print_warning(
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 
~GxConvolverBase()164 GxConvolverBase::~GxConvolverBase() {
165     if (is_runnable()) {
166 	stop_process();
167     }
168 }
169 
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)170 void GxConvolverBase::adjust_values(
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) {
186             gx_print_warning(
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 
start(int policy,int priority)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 
checkstate()226 bool GxConvolverBase::checkstate() {
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 */
read_sndfile(Audiofile & audio,int nchan,int samplerate,const float * gain,unsigned int * delay,unsigned int offset,unsigned int length,const Gainline & points)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()) {
293         gx_print_info(
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 
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 & points)391 bool GxConvolver::configure(
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() || !samplerate) {
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) {
406         gx_print_error(
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 ZITA_CONVOLVER_VERSION == 4
420         if (Convproc::configure(2, 2, size, buffersize, bufsize, Convproc::MAXPART, 0.0)) {
421             gx_print_error("convolver", "error in Convproc::configure ");
422             return false;
423         }
424 #else
425         if (Convproc::configure(2, 2, size, buffersize, bufsize, Convproc::MAXPART)) {
426             gx_print_error("convolver", "error in Convproc::configure ");
427             return false;
428         }
429 #endif
430 
431     float gain_a[2] = {gain, lgain};
432     unsigned int delay_a[2] = {delay, ldelay};
433     return read_sndfile(audio, 2, samplerate, gain_a, delay_a, offset, length, points);
434 }
435 
compute(int count,float * input1,float * input2,float * output1,float * output2)436 bool __rt_func GxConvolver::compute(int count, float* input1, float *input2,
437 				    float *output1, float *output2) {
438     if (state() != Convproc::ST_PROC) {
439         if (input1 != output1) {
440             memcpy(output1, input1, count * sizeof(float));
441         }
442         if (input2 != output2) {
443             memcpy(output2, input2, count * sizeof(float));
444         }
445 	if (state() == Convproc::ST_WAIT) {
446 	    check_stop();
447 	}
448         if (state() == ST_STOP) {
449             ready = false;
450         }
451         return true;
452     }
453     memcpy(inpdata(0), input1, count * sizeof(float));
454     memcpy(inpdata(1), input2, count * sizeof(float));
455 
456     int flags = process(sync);
457 
458     memcpy(output1, outdata(0), count * sizeof(float));
459     memcpy(output2, outdata(1), count * sizeof(float));
460     return flags == 0;
461 }
462 
configure(string fname,float gain,unsigned int delay,unsigned int offset,unsigned int length,unsigned int size,unsigned int bufsize,const Gainline & points)463 bool GxConvolver::configure(string fname, float gain, unsigned int delay, unsigned int offset,
464 			    unsigned int length, unsigned int size, unsigned int bufsize,
465 			    const Gainline& points) {
466     Audiofile audio;
467     cleanup();
468     if (fname.empty() || !samplerate) {
469         return false;
470     }
471     if (audio.open_read(fname)) {
472         gx_print_error("convolver", Glib::ustring::compose("Unable to open '%1'", fname));
473 	return false;
474     }
475     if (audio.chan() > 1) {
476         gx_print_error(
477 	    "convolver",
478 	    Glib::ustring::compose("only taking first channel of %1 channels in impulse response", audio.chan()));
479 	return false;
480     }
481     unsigned int ldelay = delay;
482     adjust_values(audio.size(), buffersize, offset, delay, ldelay, length, size, bufsize);
483 
484     if (samplerate != static_cast<unsigned int>(audio.rate())) {
485 	float f = float(samplerate) / audio.rate();
486 	size = round(size * f) + 2; // 2 is safety margin for rounding differences
487 	delay = round(delay * f);
488     }
489 #if ZITA_CONVOLVER_VERSION == 4
490         if (Convproc::configure(1, 1, size, buffersize, bufsize, Convproc::MAXPART,0.0)) {
491             gx_print_error("convolver", "error in Convproc::configure ");
492             return false;
493         }
494 #else
495         if (Convproc::configure(1, 1, size, buffersize, bufsize, Convproc::MAXPART)) {
496             gx_print_error("convolver", "error in Convproc::configure ");
497             return false;
498         }
499 #endif
500 
501     float gain_a[1] = {gain};
502     unsigned int delay_a[1] = {delay};
503     return read_sndfile(audio, 1, samplerate, gain_a, delay_a, offset, length, points);
504 }
505 
compute(int count,float * input,float * output)506 bool __rt_func GxConvolver::compute(int count, float* input, float *output) {
507     if (state() != Convproc::ST_PROC) {
508         if (input != output) {
509             memcpy(output, input, count * sizeof(float));
510         }
511 	if (state() == Convproc::ST_WAIT) {
512 	    check_stop();
513 	}
514         if (state() == ST_STOP) {
515             ready = false;
516         }
517         return true;
518     }
519     memcpy(inpdata(0), input, count * sizeof(float));
520 
521     int flags = process(sync);
522 
523     memcpy(output, outdata(0), count * sizeof(float));
524     return flags == 0;
525 }
526 
527 
528 /****************************************************************
529  ** GxSimpleConvolver
530  */
531 
532 class CheckResample {
533 private:
534     float *vec;
535     gx_resample::BufferResampler& resamp;
536 public:
CheckResample(gx_resample::BufferResampler & resamp_)537     CheckResample(gx_resample::BufferResampler& resamp_): vec(0), resamp(resamp_) {}
resample(int * count,float * impresp,unsigned int imprate,unsigned int samplerate)538     float *resample(int *count, float *impresp, unsigned int imprate, unsigned int samplerate) {
539 	if (imprate != samplerate) {
540 	    vec = resamp.process(imprate, *count, impresp, samplerate, count);
541 	    if (!vec) {
542 		boost::format msg = boost::format("failed to resample %1% -> %2%") % imprate % samplerate;
543 		if (samplerate) {
544 		    gx_print_error("convolver", msg);
545 		} else {
546 		    // not need for extra error when no samplerate (probably not connected to jack)
547 		    gx_print_warning("convolver", msg);
548 		}
549 		return 0;
550 	    }
551 	    return vec;
552 	}
553         return impresp;
554     }
~CheckResample()555     ~CheckResample() {
556 	if (vec) {
557 	    delete[] vec;
558 	}
559     }
560 };
561 
configure(int count,float * impresp,unsigned int imprate)562 bool GxSimpleConvolver::configure(int count, float *impresp, unsigned int imprate) {
563     CheckResample r(resamp);
564     impresp = r.resample(&count, impresp, imprate, samplerate);
565     if (!impresp) {
566 	return false;
567     }
568     cleanup();
569     unsigned int bufsize = buffersize;
570     if (bufsize < Convproc::MINPART) {
571         bufsize = Convproc::MINPART;
572     }
573 #if ZITA_CONVOLVER_VERSION == 4
574         if (Convproc::configure(1, 1, count, buffersize,
575                                 bufsize, Convproc::MAXPART,0.0)) {
576             gx_print_error("convolver", "error in Convproc::configure");
577             return false;
578         }
579 #else
580         if (Convproc::configure(1, 1, count, buffersize,
581                                 bufsize, Convproc::MAXPART)) {
582             gx_print_error("convolver", "error in Convproc::configure");
583             return false;
584         }
585 #endif
586     if (impdata_create(0, 0, 1, impresp, 0, count)) {
587         gx_print_error("convolver", "out of memory");
588         return false;
589     }
590     return true;
591 }
592 
update(int count,float * impresp,unsigned int imprate)593 bool GxSimpleConvolver::update(int count, float *impresp, unsigned int imprate) {
594     CheckResample r(resamp);
595     impresp = r.resample(&count, impresp, imprate, samplerate);
596     if (!impresp) {
597 	return false;
598     }
599 #if ZITA_CONVOLVER_VERSION == 4
600         impdata_clear(0, 0);
601 #endif
602     if (impdata_update(0, 0, 1, impresp, 0, count)) {
603         gx_print_error("convolver", "update: internal error");
604         return false;
605     }
606     return true;
607 }
608 
compute(int count,float * input,float * output)609 bool __rt_func GxSimpleConvolver::compute(int count, float* input, float *output) {
610     if (state() != Convproc::ST_PROC) {
611         if (input != output) {
612             memcpy(output, input, count * sizeof(float));
613         }
614 	if (state() == Convproc::ST_WAIT) {
615 	    check_stop();
616 	}
617         if (state() == ST_STOP) {
618             ready = false;
619         }
620         return true;
621     }
622     int flags = 0;
623     if (static_cast<unsigned int>(count) == buffersize)
624     {
625       memcpy(inpdata(0), input, count * sizeof(float));
626 
627       flags = process(sync);
628 
629       memcpy(output, outdata(0), count * sizeof(float));
630     } else {
631         float *in, *out;
632       in = inpdata(0);
633       out = outdata(0);
634       unsigned int b = 0;
635       unsigned int c = 1;
636       for(int i = 0; i<count; ++i){
637         in[b] = input[i];
638         if(++b == buffersize) {
639           b=0;
640           flags = process();
641           for(unsigned int d = 0; d<buffersize; ++d) {
642             output[d*c] = out[d];
643           }
644           ++c;
645         }
646       }
647     }
648     return flags == 0;
649 }
650 
651 //////////////stero/////////////////
652 
configure_stereo(int count,float * impresp,unsigned int imprate)653 bool GxSimpleConvolver::configure_stereo(int count, float *impresp, unsigned int imprate)
654 {
655   //printf("try configure()\n");
656   CheckResample r(resamp);
657   impresp = r.resample(&count, impresp, imprate, samplerate);
658   if (!impresp)
659     {
660       printf("no impresp\n");
661       return false;
662     }
663   cleanup();
664   unsigned int bufsize = buffersize;
665   if (bufsize < Convproc::MINPART)
666     {
667       bufsize = Convproc::MINPART;
668     }
669 #if ZITA_CONVOLVER_VERSION == 4
670       if (Convproc::configure(2, 2, count, buffersize,
671                               bufsize, bufsize,0.0)) // Convproc::MAXPART
672         {
673           printf("no configure\n");
674           return false;
675         }
676 
677 #else
678       if (Convproc::configure(2, 2, count, buffersize,
679                               bufsize, bufsize)) // Convproc::MAXPART
680         {
681           printf("no configure\n");
682           return false;
683         }
684 #endif
685   if (impdata_create(0, 0, 1, impresp, 0, count) & impdata_create(1, 1, 1, impresp, 0, count))
686     {
687       printf("no impdata_create()\n");
688       return false;
689     }
690   //printf("configure()\n");
691 
692   return true;
693 }
694 
update_stereo(int count,float * impresp,unsigned int imprate)695 bool GxSimpleConvolver::update_stereo(int count, float *impresp, unsigned int imprate)
696 {
697   CheckResample r(resamp);
698   impresp = r.resample(&count, impresp, imprate, samplerate);
699   if (!impresp)
700     {
701       return false;
702     }
703 #if ZITA_CONVOLVER_VERSION == 4
704       impdata_clear(0, 0);
705       impdata_clear(1, 1);
706 #endif
707   if (impdata_update(0, 0, 1, impresp, 0, count) & impdata_update(1, 1, 1, impresp, 0, count))
708     {
709       return false;
710     }
711   return true;
712 }
713 
compute_stereo(int count,float * input,float * input1,float * output,float * output1)714 bool __rt_func GxSimpleConvolver::compute_stereo(int count, float* input, float* input1, float *output, float *output1)
715 {
716   // printf("try run\n");
717   if (state() != Convproc::ST_PROC)
718     {
719       //printf("state() != ST_PROC\n");
720       if (input != output)
721         {
722           memcpy(output, input, count * sizeof(float));
723           memcpy(output1, input1, count * sizeof(float));
724         }
725       if (state() == Convproc::ST_WAIT)
726         {
727           //printf("state() == ST_WAIT\n");
728           check_stop();
729         }
730       if (state() == ST_STOP)
731         {
732           //printf("state() == ST_STOP\n");
733           ready = false;
734         }
735       return true;
736     }
737   int flags = 0;
738   if (static_cast<unsigned int>(count) == buffersize)
739     {
740       memcpy(inpdata(0), input, count * sizeof(float));
741       memcpy(inpdata(1), input1, count * sizeof(float));
742 
743       flags = process(sync);
744 
745       memcpy(output, outdata(0), count * sizeof(float));
746       memcpy(output1, outdata(1), count * sizeof(float));
747     } else {
748         float *in, *in1, *out, *out1;
749       in = inpdata(0);
750       in1 = inpdata(1);
751       out = outdata(0);
752       out1 = outdata(1);
753       unsigned int b = 0;
754       unsigned int c = 1;
755       for(int i = 0; i<count; ++i){
756         in[b] = input[i];
757         in1[b] = input1[i];
758         if(++b == buffersize) {
759           b=0;
760           flags = process();
761           for(unsigned int d = 0; d<buffersize; ++d) {
762             output[d*c] = out[d];
763             output1[d*c] = out1[d];
764           }
765           ++c;
766         }
767       }
768     }
769   return flags == 0;
770 }
771 
772 }
773