slider1:-90<-140,-10,10>Floor
slider2:0<0,5,1>CPU release
slider3:4<0,5,1{512,1024,2048,4096,8192,16384}>FFT size
slider4:2<0,5,0.1>Smoothing factor

@init
max_ch=14;
fftSize=8192;
maxFftSize=16384;
pcmBufferSize=200000;
pcmBuffer=0;
nextRecPosition=0;
lastBatchOfSamples=pcmBuffer;
windowType=2;
fftWorkspace = pcmBuffer+pcmBufferSize;
window=fftWorkspace+maxFftSize*2;
barWorkspace=window+maxFftSize;
barAutoReductionSpeed=7;
ampThreshold=-90;

//------------------------
// Grid-related constants
marginLeft=5;
marginRight=30;
hspacingFactor=8;
vspacingFactor=2;
marginTop=vspacingFactor*13;
marginBottom=vspacingFactor*13;
ampStep=10;
//------------------------

numBars=120;
numLinBars=0;
f0=16;
k=1.062088578; // Taken from Maple sheet
bars=barWorkspace+numBars+1;

dWindowPos = $pi*2/(fftSize-1);
iFftSize=1/fftSize;
windowCreated=0;
gfx_flag=0;

cpuReleaseCounter=0;

@slider
ampThreshold=slider1;
cpuReleaseCounter=0;
fftSize=2^(slider3+9);
slider4==0? (barAutoReductionSpeed=0) : (barAutoReductionSpeed=5.01-slider4;);

@sample
is=0;
my_num_ch=num_ch;
my_num_ch>max_ch ? my_num_ch=max_ch;
loop(my_num_ch/2,
pcmBufer[nextRecPosition]=spl(is*2+1); 
is+=1;
nextRecPosition+=1;
nextRecPosition==pcmBufferSize ? nextRecPosition=0;
);
lastBatchOfSamples=nextRecPosition-my_num_ch/2;

@gfx 0 300
cpuReleaseCounter==slider2 ? (
cpuReleaseCounter=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) :
windowType==4 ? 0 :
1.0)*0.5;
windowPos+=dWindowPos;
i+=1;
);

gfx_flag<1  ? (
gfx_flag+=1;
) : (

num_ch<=max_ch? (

my_num_ch=num_ch;
my_num_ch>max_ch ? my_num_ch=max_ch;

i=0;
gfx_r=1;
gfx_a=1;
i=lastBatchOfSamples;

// Draw grid
i=0;
spacingFlag=0;
vspacingFlag=0;
f=0;

gfx_r=1;
gfx_g=1;
gfx_b=1;	

barWidth=floor((gfx_w-marginLeft-marginRight)/numBars);

// Drawing border
gfx_a=1;
gfx_x=marginLeft-1;
gfx_y=marginTop;
gfx_lineto(gfx_x,gfx_h-marginBottom,1);

gfx_x=marginLeft-1;
gfx_y=marginTop;
gfx_lineto(gfx_x+numBars*barWidth,gfx_y,1);

gfx_x=marginLeft-1;
gfx_y=gfx_h-marginBottom;
gfx_lineto(gfx_x+numBars*barWidth,gfx_y,1);

gfx_x=marginLeft+barWidth*numBars;
gfx_y=marginTop;
gfx_lineto(gfx_x,gfx_h-marginBottom,1);

// Drawing decibel figures and lines
amp=0;
i=0;
gfx_y=marginTop;
loop(my_num_ch/2,
amp=0;
gfx_y=marginTop+(gfx_h-marginTop-marginBottom)/(my_num_ch/2)*i;
loop(-ampThreshold/ampStep,
gfx_a=1;
gfx_x=marginLeft+numBars*barWidth+2;
gfx_y-=gfx_texth/2;
gfx_drawnumber(amp,0);
gfx_y+=(gfx_h-marginTop-marginBottom)/(my_num_ch)*2/(-ampThreshold/ampStep);
gfx_y+=gfx_texth/2;

gfx_x=marginLeft;
gfx_a=0.1;
gfx_lineto(gfx_x+numBars*barWidth,gfx_y,1);
amp-=ampStep;
);
i+=1;
);

c=1;
gfx_a=0.5;
loop(my_num_ch/2-1,
gfx_x=marginLeft;
gfx_y=ceil(marginTop+((gfx_h-marginTop-marginBottom)/(my_num_ch/2))*c);
gfx_lineto(gfx_x+numBars*barWidth,gfx_y,1);
c+=1;
);

// Drawing frequency grid
loop(numBars,
f!=0? f*=k : f=f0;
spacingFlag==0? (
gfx_a=1;
gfx_x=barWidth*(i+1)+2+marginLeft;
gfx_y=5+gfx_texth*1.3*vspacingFlag;
f<1000? gfx_drawnumber(f,0) : gfx_drawnumber(f/1000,1);
vspacingFlag+=1;
vspacingFlag==vspacingFactor? vspacingFlag=0;
gfx_a=0.1;
gfx_x=barWidth*(i+1)+marginLeft;
gfx_y=marginTop;
gfx_lineto(gfx_x,gfx_h-marginBottom,0);
gfx_a=1;
gfx_y=gfx_h-gfx_texth*1.3*(vspacingFlag+1);
f<1000? gfx_drawnumber(f,0) : gfx_drawnumber(f/1000,1);
);
i+=1;
spacingFlag+=1;
spacingFlag==hspacingFactor? spacingFlag=0;
);
c=0;
lbs=lastBatchOfSamples;
gfx_a=1; 
my_num_ch_div_2=my_num_ch/2;
loop (my_num_ch_div_2,

// Silence detection algorithm
i=lbs+c-fftSize*my_num_ch/2;
i < 0 ? i+=pcmBufferSize;
j=0; 
sum1=0;
silenceDetectionLength=5;
j=0; 
loop (silenceDetectionLength,
sum1+=abs(pcmBuffer[i]);
i+=my_num_ch_div_2*floor(fftSize/silenceDetectionLength);
i >= pcmBufferSize ? i-=pcmBufferSize;
);
sum1>=0.001? ( // if NOT silence 
i=lbs+c-fftSize*my_num_ch/2;
i < 0 ? i+=pcmBufferSize;
j=0; 
j=0; 
loop (fftSize,
fftWorkspace[j+j]=pcmBuffer[i]*window[j];
fftWorkspace[j+j+1]=0;
i+=my_num_ch_div_2;
i >= pcmBufferSize ? i-=pcmBufferSize;
sum1+=abs(pcmBuffer[i]);
j+=1;
);

fft(fftWorkspace,fftSize);
fft_permute(fftWorkspace,fftSize);

i=0;
loop(numBars,
barWorkspace[i]=0;
i+=1;
);

fftWorkspace[fftSize]=100000;
g=(fftSize)/srate;
i=0;
f2=f0; // the high frequency for the bar zero
f1=0;  // the low frequency
loop(numBars,
j=floor(g*f1); // calculating corresponding element from fft results
sum=0;
num=ceil(g*f2)-floor(g*f1);
loop(ceil(g*f2)-floor(g*f1),
aa=fftWorkspace[j*2+2]; bb=fftWorkspace[j*2+3]; cc=sqrt(aa*aa+bb*bb);
sum+=cc; 
//cc>sum?sum=cc;
j+=1;
);
num? ( 
barWorkspace[i]=sum/num/(fftSize/2)/2; // the last /2 because we do not devide PCM data in sample block
barWorkspace[i+1]=barWorkspace[i];
);
f1=f2;
f2=f2*k;
i+=1;
);

// applying vertical transform
i=0;
loop(numBars,
barWorkspace[i]=20*log(barWorkspace[i])/log(10)-ampThreshold;
barWorkspace[i]<0? barWorkspace[i]=0;
i+=1;
);

i=0;
loop(numBars,
barAutoReductionSpeed ? bars[c*numBars+i]-=barAutoReductionSpeed*(slider2+1) : bars[c*numBars+i]=0; 
bars[c*numBars+i]<barWorkspace[i] ? bars[c*numBars+i]=barWorkspace[i];
//barAutoReductionSpeed ? bars[c*numBars+i]-=barAutoReductionSpeed : bars[c*numBars+i]=0; 
i+=1;
);

i=0;
gfx_r=1;
gfx_g=0;
gfx_b=0;
x=marginLeft;
barWidth=floor((gfx_w-marginLeft-marginRight)/numBars);
barWidth>2? barSpacing=1 : barSpacing=0;

loop(numBars,
gfx_r-=1/numBars;
gfx_b+=1/numBars;
gfx_g+=1/numBars/1.5;

gfx_x=x;
gfx_y=marginTop+ceil((gfx_h-marginTop-marginBottom)/my_num_ch*2*(c+1)+1);

h=(gfx_h-marginTop-marginBottom)/my_num_ch*2*bars[c*numBars+i]/abs(ampThreshold);
h > gfx_h/my_num_ch*2 ? h=gfx_h/my_num_ch*2;
gfx_rectto(gfx_x+barWidth-barSpacing,gfx_y-h);

gfx_x=x;
//gfx_y=ceil(gfx_h/my_num_ch*2*(c+1)-1);
//gfx_y=marginTop+ceil((gfx_h-marginTop-marginBottom)/my_num_ch*2*(c+1));
//gfx_lineto(gfx_x+barWidth,gfx_y,1);

x+=barWidth;
i+=1;
); 
); // end of silence detection condition
c+=1;
);

) : (
gfx_a=1;
gfx_r=1;
gfx_x=10;
gfx_y=10;
gfx_drawchar($'t');
gfx_drawchar($'o');
gfx_drawchar($'o');
gfx_drawchar($' ');
gfx_drawchar($'m');
gfx_drawchar($'a');
gfx_drawchar($'n');
gfx_drawchar($'y');
gfx_drawchar($' ');
gfx_drawchar($'c');
gfx_drawchar($'h');
gfx_drawchar($'a');
gfx_drawchar($'n');
gfx_drawchar($'n');
gfx_drawchar($'e');
gfx_drawchar($'l');
gfx_drawchar($'s');

);
);
) : (
cpuReleaseCounter+=1;
);
