desc:spectrograph

/*
Copyright (C) 2007 Cockos Incorporated
License: GPL - http://www.gnu.org/licenses/gpl.html
*/

slider1:6<0,9,1{16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}>FFT size
slider2:2<0,3,1{rectangular,hamming,blackman-harris,blackman}>window
slider3:-180<-180,6,1>gate (dB)
slider4:0<0,10,0.1}>frequency curve

in_pin:left input
in_pin:right input


/* color ramp:
1111222233334444555566667777
------------rrRRRRRRRRRRRRRR
----ggGGGGGGGGGGGGgg----ggGG
bbBBBBBBBBbb--------bbBBBBBB


7 sections, we'll say each will be 24dB


*/

@init
fftsize=32768;
recpos=0;
gfx_clear=-1;
windowtype=-1;
over24=1/24;
histsize=128*1024;
window=histsize;
fftworkspace=window+65536;

lrecpos=0;

@slider
lfft=fftsize;
a=(slider1|0);
a<0?a=0:a>11?a=11;
fftsize=2^(a+4);
minvol=10^(slider3/20*2); // squared
islogmode = slider4>0.0;
g_logscale=pow(10.0,slider4*10.0-11.0);

@block

ifftsize=1/fftsize;

@sample
recpos[]=(spl0+spl1);
recpos+=1;
recpos >= histsize ? recpos=0;


@gfx 640 400

old_w != gfx_w || old_h!=gfx_h? (
cur_xpos=0;
old_w=gfx_w; old_h=gfx_h;

gfx_r=gfx_g=gfx_b=0; gfx_a=1;
gfx_x=gfx_y=0;
gfx_rectto(gfx_w,gfx_h);

);

recpos != lrecpos ? (
  windowsize != fftsize || windowtype != slider2 ? (
    windowtype=slider2; 
    windowsize=fftsize;
    i=0;
    dwindowpos = $pi*2/(fftsize-1);
    windowpos=0;

    loop(fftsize,
       window[i] =  (
         windowtype==1 ? 0.53836 - cos(windowpos)*0.46164 :
         windowtype==2 ? 0.35875 - 0.48829 * cos(windowpos) + 0.14128 * cos(2*windowpos) - 0.01168 * cos(6*windowpos) :
         windowtype==3 ? 0.42 - 0.50 * cos(windowpos) + 0.08 * cos(2.0*windowpos) :
          1.0) *0.5*ifftsize;
       windowpos+=dwindowpos;
       i+=1;
    );
  );

  lrecpos=recpos;

  buf1=lrecpos-fftsize;
  buf1<0 ? buf1+=histsize;
  buf2=window;
  buf3=fftworkspace;
  loop(fftsize,
    buf3[] = buf1[]*buf2[];
    buf3[1]=0;
    buf3+=2;

    buf2+=1;
    (buf1+=1) >= histsize ? buf1 -= histsize;
  );
  fft(fftworkspace,fftsize);
  fft_permute(fftworkspace,fftsize);

  lfftpos=0;
  i=0;
  lscale=10/log(10);
  !(mouse_cap&1) ? (
   gfx_a=0.1;
   gfx_x=cur_xpos+1;
   gfx_y=0; 
   gfx_r=gfx_g=gfx_b=0;
   gfx_rectto(cur_xpos+20,gfx_h);
   cur_xpos+20 > gfx_w ? (
     gfx_x=0;
     gfx_y=0;
     gfx_rectto(cur_xpos+20-gfx_w,gfx_h);
   );
   uselm = islogmode;
   sc = (uselm ? (1.0/log(1+g_logscale)) : (1.0/gfx_h)) * 0.5*fftsize;
   sc2=g_logscale/gfx_h;
   loop(gfx_h,
    tpos = (uselm ? ((fftsize*0.5 - 1 - log(1+(gfx_h-1-i)*sc2)*sc)) : i*sc)|0;
    tpos >= fftsize*0.5 ? tpos=fftsize*0.5;
    lfftpos >= tpos ? ( lfftpos=tpos-1; );
    mv=0;
    loop(tpos-lfftpos,
      usei = max(lfftpos,0)*2;
      aa=fftworkspace[usei]; 
      bb=fftworkspace[usei+1];
      dv=aa*aa+bb*bb;
      dv<0.00000000000000000000001 ? dv=0.0000000000000000000000001;
      dv>mv?mv=dv;

      lfftpos+=1;
    );
    mv=mv <= minvol ? -200 : log(mv)*lscale;
     
    gfx_x=cur_xpos;    
    gfx_y=gfx_h-i-1; 
    gfx_a=1;


    mv <= -96  ? (
      mv<=-168 ? gfx_setpixel(0,0,0) : 
      mv <= -144 ? gfx_setpixel(0,0,(mv+168)*over24*0.25) :
      mv <= -120 ? gfx_setpixel(0,(mv+144)*over24*0.25,0.25) :
        gfx_setpixel(0,0.25+(mv+120)*over24*0.5,0.25-(mv+120)*over24*0.25) 
    ) : (
      mv <= -72  ? gfx_setpixel((mv+96)*over24,0.75,0) :
      mv <= -48  ? gfx_setpixel(1,0.5-(mv+72)*over24*0.5,0) : 
      mv <= -24  ? gfx_setpixel(1,0,(mv+48)*over24) : 
      mv <= 0 ? gfx_setpixel(1,(mv+24)*over24,1) : 
              gfx_setpixel(1,1,1);
    );      
    i+=1;
  );

  cur_xpos+=1;
  cur_xpos >= gfx_w ? cur_xpos=0;
  );
);

gfx_x=gfx_w-140;
gfx_y=gfx_h-gfx_texth;
gfx_r=gfx_g=gfx_b=0;
gfx_a=1;
gfx_rectto(gfx_w,gfX_h);

mouse_x >=0 && mouse_x < gfx_w  &&
mouse_y >= 0 && mouse_y < gfx_h ? (
  !(mouse_cap&1) ? mb=-1000;
  bla=0;
  loop(25,
    gfx_x=mouse_x -2 + (bla%5); 
    gfx_y=mouse_y -2 + (bla/5);
    gfx_getpixel(r,g,b); 
    r||g||b ? (

      // calculate amplitude at this point based on RGB
      !r && !g ? b = -168 + b*24*4:
      abs(b-0.25)<0.005 && !r ? b=-144 + g*24*4:
      g <= 0.25 && b <= 0.25 && !r ? b=-120 + (0.25-b)*24*4:
      abs(g-0.75)<0.005 && !b ? b=-96 + r*24:
      r == 1.0 && !b && g <= 0.5? b=-72 + (0.5-g)*24*2:
      r == 1.0 && !g ? b=-48 + b*24:
      r == 1.0 && b==1.0 ? b=-24+g*24 : 
      b=-1000000;

      b > mb ? mb=b;
    );
    bla+=1;
  );
  (
    gfx_x=gfx_w-140;
    gfx_y=gfx_h-gfx_texth;
    gfx_r=gfx_g=gfx_b=1;
    mb > -1000.0 ? (
     gfx_drawnumber(mb,1); 
    ) : (
      gfx_drawchar($'-');
      gfx_drawchar($'o');
      gfx_drawchar($'o');
    );
    gfx_drawchar($'d');
    gfx_drawchar($'B');
    gfx_drawchar($' ');

    disp_hz=mouse_y/gfx_h;
    islogmode ? ( 
      disp_hz = log(1+disp_hz*g_logscale)/log(1+g_logscale);
    );

    gfx_drawnumber((1-disp_hz)*srate*0.5,0);
    gfx_drawchar($'H');
    gfx_drawchar($'z');
  );
);
