// This effect Copyright (C) 2004 and later Cockos Incorporated
// License: LGPL - http://www.gnu.org/licenses/lgpl.html


desc: Convolution Amp/Cab Modeler
//tags: guitar amplifier convolution FFT

slider1:/amp_models:none:Model
slider2:0<-120,30,1>Preamp (dB)
slider3:2<0,2,1{No,Yes (no gain adjust),Yes (correct gain)}>Upsample Impulse If Required
slider4:0<0,1,1{L-Stereo,Stereo-Stereo}>Channel Mode
slider5:0,Filter Size
slider6:0,FFT Size


in_pin:left input
in_pin:right input
out_pin:left output
out_pin:right output

@init 
fftsize=-1;
need_refft=1;
convsrc=128*1024;
lslider1=-1;
impbuf=256*1024;


@slider
  tmp=slider1|0;
  tmp != lslider1 ?
  (
    lslider1=tmp;

    filehandle=file_open(slider1);
    impbuf_l=impbuf_nch=impbuf_srate=0;
    filehandle > 0 ? 
    (
      file_riff(filehandle,impbuf_nch,impbuf_srate);
      impbuf_nch ?
      (
        impbuf_l=(file_avail(filehandle)/impbuf_nch)|0; 
        need_refft=1; 
        file_mem(filehandle,impbuf,impbuf_l*impbuf_nch);
      );
      file_close(filehandle);
    );
  );
  !stereo_mode != !slider4 ? ( need_refft=1; stereo_mode=slider4; );



  useresample != slider3 ? (useresample=slider3; need_refft=1; );
  preamp=2^(slider2/6);

  slider6=fftsize;
  slider5=filtersize;

@block

need_refft ? (  // prepare convolution source, here...
  useresample && srate > impbuf_srate && impbuf_srate > 1 ? 
  (
    filtersize = ((srate*impbuf_l)/impbuf_srate)|0;
    filtersize > 16384 ? (
      filtersize = 16384;
      impbuf_l = ((filtersize * impbuf_srate) / srate)|0;
    );
    isc=impbuf_srate/srate;
  )
  : 
  (
    impbuf_l > 16384 ? impbuf_l = 16384;
    filtersize=impbuf_l;
    isc=1.0;
  );

  fftsize=32;

  while(
    filtersize > fftsize*0.5 ? 
    (
      fftsize += fftsize;
    ) : 0;
  );
  slider5=filtersize;
  slider6=fftsize;
  sliderchange(slider5);
  sliderchange(slider6); 
  chunksize=fftsize-filtersize-1; // size of chunk size of audio to use
  chunksize2=chunksize*2;
  bpos=0; 
  curblock=0;
  lastblock=64*1024;
  invfsize=1/fftsize;
  pre_sum = post_sum = i = 0;
  loop(impbuf_l,
    pre_sum += impbuf[i];
    stereo_mode == 0 ? pre_sum += impbuf[i + impbuf_nch - 1];
    i+=impbuf_nch;
  );
  i=0;
  i2=0;
  loop(min(fftsize,filtersize),
     ipos=i|0;
     ipart=(i-ipos);
     convsrc[i2]=impbuf[ipos*impbuf_nch]*(1-ipart) + impbuf[(ipos+1)*impbuf_nch]*ipart;
     convsrc[i2+1]=stereo_mode ? 0.0 : (impbuf[(ipos+1)*impbuf_nch-1]*(1-ipart) +
                                        impbuf[(ipos+2)*impbuf_nch-1]*(ipart));
     post_sum += convsrc[i2] + convsrc[i2+1];
     i += isc;
     i2+=2;
  );
  loop(fftsize-filtersize,
     convsrc[i2]=convsrc[i2+1]=0;
     i2+=2;
  );
  isc != 1 && useresample>=2 && abs(post_sum) > 0.0001*fftsize*(stereo_mode?1:2) &&
      abs(pre_sum) > 0.0001*impbuf_l*(stereo_mode?1:2) ? (
    invfsize *= abs(pre_sum / post_sum);
  );
  fft(convsrc,fftsize);
  i=0;
  loop(fftsize*2, convsrc[i] *= invfsize; i+=1; );
  need_refft=0;
);

@sample

filtersize > 0 ?
(

bpos >= chunksize ? 
(
  t=lastblock;
  lastblock=curblock;
  curblock=t;

  memset(curblock+chunksize*2,0,(fftsize-chunksize)*2);

  fft(curblock,fftsize);
  convolve_c(curblock,convsrc,fftsize);

  ifft(curblock,fftsize);

  bpos=0;
);

// save sample
bp2=bpos*2;
lastblock[bp2]=spl0*preamp;
lastblock[bp2+1]=stereo_mode ? (spl1*preamp) : 0;

spl0=curblock[bp2];
spl1=curblock[bp2+1];

bpos < fftsize-chunksize ? 
(
  spl0+=lastblock[chunksize2+bp2];
  spl1+=lastblock[chunksize2+bp2+1];
);


bpos += 1;

);
