// This effect Copyright (C) 2004 and later Cockos Incorporated
// License: GPL - http://www.gnu.org/licenses/gpl.html
desc:drum sequencer advanced

slider1:120<0,800,1>bpm
slider2:-6<-120,6,1>volume (dB)
slider3:/drum_patchsets:patchset_pacific1_adpcm.wav:Patch set
slider4:/drum_tracks:track.txt:Sequence
slider5:1<0.1,4,0.05>pitch scaling
slider6:16<1,64,1>max voices
slider7:0<0,100,1>random error (ms)
slider8:0<0,2,1{instant,end of pattern,end of beat}>sequence change granularity

@init
beat_pos=1;
actlist=0; // paired list of sample index, position, max len = 4096 pairs
actsize=0;
actentsize=6;
instinfo=8192;
instentsize=3;
sbt=8192+32*instentsize; // these only go in the first load
lslider3=-100;
lastseq = -100;
track_spd=1;

@template slider4
2.0 # scale
#defines
KICK=1, RIDE=2, BELL=4, SPLASH=8, CRASH=16, HIHATC=32, SNARE=64
SMSNARE=128, STICK=256, HITOM=512, MIDTOM=1024, LOWTOM=2048, HIHATO=4096
VOLUME=1048576, PAN=2097152, DELAY=3145728

# write your drum sequence here
# it is a series of events, or modifier events that include
# VOLUME, PAN, or DELAY and a parameter. Example:
# KICK+HIHATC   (normal event)
# VOLUME+KICK+SNARE, 2.0  (modifier event, sets volume of kick and snare to 2)
# volumes can be 0..1..x (louder)
# pan can be -1..1 (do not go above 1 or below -1)
# delay can be 0..1 (or more, but not recommended since it ties up a channel)
# (delay is in events, so 1 is like having it in the next slot)

KICK+HIHATC, HIHATC, SNARE+HIHATC, HIHATC
HIHATO+KICK, 0, RIDE+SNARE, 0

#eof

@slider

tmp=slider3|0;
lslider3 != tmp ? 
(
  lslider3=tmp;
  sbt_top=sbt+32*2;
  sbt_ns=0;
  filehandle=file_open(slider3);
  filehandle > 0 ? 
  (
    file_riff(filehandle,spl_nch,spl_srate);
    spl_srate/=srate;
    spl_nch==2 ?
    (  
      numsilent=0;
      pairs=min(file_avail(filehandle),(1024*1024 - 65536*2))*0.5;
      inspl=0;
      pos=0;
      sbt[sbt_ns*2]=sbt_top; 
      loop(pairs,
         file_var(filehandle,l);
         file_var(filehandle,r);
         quiet=max(abs(l),abs(r)) < 0.0001;
         inspl || !quiet ?
         (
           sbt_top[0]=l;
           sbt_top[1]=r;
           inspl=1;
           pos+=2;
           sbt_top+=2;
         );

         inspl && quiet ? 
         (
           (numsilent += 1) >= 2048 ? (
             // new sample time
             sbt_top-=numsilent*2;
             sbt[sbt_ns*2+1]=(pos-numsilent*2);
             sbt_ns+=1;
             sbt[sbt_ns*2]=sbt_top;
             inspl=0;
             pos=0;
           );
         ) : numsilent=0;
       );
       sbt[sbt_ns*2+1]=pos-numsilent*2;
       sbt_ns+=1; 
    );
    file_close(filehandle);
  );
  actsize=0;
);

vol=2^(slider2/6);
slider5=max(0.1,slider5);
actsize=0|min(min(actsize,slider6),4096);
gpitchsc=2*slider5*spl_srate;
errsc=(srate*slider7*0.001)*0.001;
instdelscale=(srate*60)/slider1/track_spd;
mbps=slider1/60/srate*track_spd;

@sample

spl_nch == 2 ? (

beat_pos+=mbps;

(slider4|0) != lastseq &&
(!slider8 || (slider8==2 && beat_pos>=1) || (slider8==1 && beat_pos>=1 && track_p < 1)) ? 
  ( 
    lastseq=slider4|0;
    filehandle=file_open(slider4);
    track_s=1024*1024-65536;
    track_l=0;
    track_p=0;
    beat_pos=1;
    filehandle > 0 ?
    (
      file_var(filehandle,track_spd);
      while
      (
        file_var(filehandle,track_s[track_l]);
        file_avail(filehandle) > 0 ? 
        (
          track_l+=1;
          track_l < 65536;
        ) : 0;
      );
      file_close(filehandle);
    );
    instdelscale=(srate*60)/slider1/track_spd;
    mbps=slider1/60/srate*track_spd;
  );

beat_pos >= 1 ? 
(

  track_p < 1 ? (
    tmp=0;
    loop(sbt_ns, instinfo[tmp]=1; instinfo[tmp+1]=instinfo[tmp+2]=0; tmp+=instentsize; );
  );

  beat_pos -= 1;

  // add this beat's shit to the queue
  v=track_s[track_p];
  noact=0;
  while ( 
    v & 3145728 ? (
      ch=v & 3145728;
      ch = (ch == 1048576 ? 0 : (ch == 2097152 ? 1 : 2)); 
      newval=track_s[track_p+=1];
      i=1;
      cnti=0;
      while(
        v & i ? instinfo[cnti+ch] = newval;
        cnti+=instentsize;
        i+=i;
        (v&1048575) >= i;
      );            

      (track_p += 1) >= track_l ? 
      (
         track_p=0;
         tmp=0;
         loop(sbt_ns, instinfo[tmp]=1; instinfo[tmp+1]=instinfo[tmp+2]=0; tmp+=instentsize; );
       ); 
       v = track_s[track_p];     
       v & 3145728 && (noact += 1) < track_l;  // go again?  
     );
  );
 
 
  v > 1048575 ? v=0;
  cnti=0;
  i=1;
  ws=sbt;
  acptr=actlist+actsize*actentsize;
  v ? while(
    (v&i) ? (
      actsize >= slider6 ? (
        min_l=10000000;
        min_p=actlist;
        lptr=actlist;
        // find sample closest to end
        loop(actsize,
           t=(lptr[1]-lptr[0]);
           t < min_l ? (min_l=t; min_p=lptr);
           lptr+=actentsize;
        );
        min_p[1]=(min_p[0]=ws[0])+ws[1];
        min_p[2]=rand(1000)*errsc+instinfo[cnti+2] * instdelscale;
        min_p[3]=instinfo[cnti];
        min_p[4]=instinfo[cnti+1];
      ) 
      :
      (
        acptr[1]=(acptr[0]=ws[0])+ws[1];
        acptr[2]=rand(1000)*errsc+instinfo[cnti+2] * instdelscale;
        acptr[3]=instinfo[cnti];
        acptr[4]=instinfo[cnti+1];
        actsize+=1;
        acptr+=actentsize;
      )
    );
    ws+=2;
    cnti+=instentsize;
    v >= (i+=i); // as long as v might have i in it
  );
  (track_p += 1) >= track_l ? (track_p=0);
);

s0=s1=0;

// render samples
lastptr=(actptr=actlist)+actsize*actentsize;
actptr < lastptr ? while(
  (p=actptr[0]) >= actptr[1] ? 
  (
    // move last sample in to this one
    actsize-=1;
    actptr < (lastptr-=actentsize) ?
    (       
      memcpy(actptr,lastptr,actentsize);
    );
  )
  :
  (
    actptr[2] >= 0 ? (actptr[2]-=1) : 
    (
      lv = rv = actptr[3];
      pan=actptr[4];
      pan > 0 ? lv *= 1-pan;
      pan < 0 ? rv *= 1+pan;
      p &= 1048574; // convert to integer, remove low bit (for stereo)
      s0+=p[0]*lv;
      s1+=p[1]*rv;
      actptr[0]+=gpitchsc;
    );
    actptr+=actentsize;
  );

  actptr<lastptr; // condition for while
);

spl0+=s0*vol;
spl1+=s1*vol;
); // spl_nch == 2
