Connor McCutcheon
/ Music
livecode.orc
orc
/*
  Live Coding Functions
  Author: Steven Yi
*/ 
instr S1
  ifreq = p4
  iamp = p5
endin
instr P1
  ibeat = p4
endin
;; TIME
gk_tempo init 120 
/** Set tempo of global clock to itempo value in beats per minute. */
opcode set_tempo,0,i
  itempo xin
  gk_tempo init itempo
endop
/** Returns tempo of global clock in beats per minute. */
opcode get_tempo,i,0
  xout i(gk_tempo)
endop
/** Adjust tempo of global clock towards by inewtempo by incr amount. */
opcode go_tempo, 0, ii
  inewtempo, incr xin
  icurtempo = i(gk_tempo)
  itemp init icurtempo 
  if(inewtempo > icurtempo) ithen
    itemp = min:i(inewtempo, icurtempo + abs(incr))
    gk_tempo init itemp 
  elseif (inewtempo < icurtempo) ithen
    itemp = max:i(inewtempo, icurtempo - abs(incr))
    gk_tempo init itemp 
  endif
endop
instr Perform
  ibeat = p4
  schedule("P1", 0, p3, ibeat) 
endin
gk_clock_internal init 0
gk_clock_tick init 0
gk_now init 0
/** Returns value of now beat time
   (Code used from Thorin Kerr's LivecodeLib.csd) */
opcode now, i, 0
  xout i(gk_now)
endop
/** Returns current clock tick at init time */
opcode now_tick, i, 0
  xout i(gk_clock_tick)
endop
/** Returns duration of time in given number of beats (quarter notes) */
opcode beats, i, i
  inumbeats xin
  ibeatdur = divz(60, i(gk_tempo), -1)
  xout ibeatdur * inumbeats
endop
/** Returns duration of time in given number of measures (4 quarter notes) */
opcode measures, i, i
  inummeasures xin
  xout beats(inummeasures * 4)
endop
/** Returns duration of time in given number of ticks (16th notes) */
opcode ticks, i, i
  inumbeats xin
  ibeatdur = divz(60, i(gk_tempo), -1)
  ibeatdur = ibeatdur / 4
  xout ibeatdur * inumbeats
endop
/** Returns time from now for next beat, rounding to align
    on beat boundary. 
   (Code used from Thorin Kerr's LivecodeLib.csd) */
opcode next_beat, i, p
  ibeatcount xin
  inow = now()
  ibc = frac(ibeatcount)
  inudge = int(ibeatcount)
  iresult = inudge + ibc + (round(divz(inow, ibc, inow)) * (ibc == 0 ? 1 : ibc)) - inow
  xout beats(iresult)
endop
/** Returns time from now for next measure, rounding to align to measure  
    boundary. */
opcode next_measure, i,0
  inow = now() % 4
  ival = 4 - inow 
  if(ival < 0.25) then
    ival += 4
  endif
  inext = beats(ival)
  xout inext
endop
/** Reset clock so that next tick starts at 0 */
opcode reset_clock, 0, 0
  gk_clock_internal init 0 
  gk_clock_tick init -1 
  gk_now init -(ksmps / sr)
endop
/** Adjust clock by iadjust number of beats.
    Value may be positive or negative. */
opcode adjust_clock, 0, i 
  iadjust xin
  gk_now init i(gk_now) + iadjust 
endop
instr Clock ;; our clock  
  ;; tick at 1/16th note
  kfreq = (4 * gk_tempo) / 60     ;; frequency of 16th note
  kdur = 1 / kfreq                ;; duration of 16th note in seconds 
  kstep = (gk_tempo / 60) / kr    ;; step size in quarter notes per buffer
  kstep16th = kfreq / kr          ;; step size in 16th notes per buffer
  gk_now += kstep                 ;; advance beat clock
  gk_clock_internal += kstep16th  ;; advance 16th note clock
  // checks if next buffer will be one where clock will
  // trigger.  If so, then schedule event for time 0 
  // which will get processed next buffer. 
  if(gk_clock_internal + kstep16th >= 1.0 ) then
    gk_clock_internal -= 1.0 
    gk_clock_tick += 1 
    event("i", "Perform", 0, kdur, gk_clock_tick)
  endif
endin
;; Randomization
/** Given a random chance value between 0 and 1, calculates a random value and
returns 1 if value is less than chance value. For example, giving a value of 0.7,
it can read as "70 percent of time, return 1; else 0" */
opcode choose, i, i
  iamount xin
  ival = 0
  if(random(0,1) < limit:i(iamount, 0, 1)) then
    ival = 1 
  endif
  xout ival
endop
;; Array Functions
/** Cycles through karray using index. */
opcode cycle, i, ik[]
  indx, kvals[] xin
  ival = i(kvals, indx % lenarray(kvals))
  xout ival
endop
/** Checks to see if item exists within array. Returns 1 if
  true and 0 if false. */
opcode contains, i, ii[]
  ival, iarr[] xin
  indx = 0
  iret = 0
  while (indx < lenarray:i(iarr)) do
    if (iarr[indx] == ival) then
      iret = 1
      igoto end
    endif
    indx += 1
  od
end:
  xout iret
endop 
/** Checks to see if item exists within array. Returns 1 if
  true and 0 if false. */
opcode contains, i, ik[]
  ival, karr[] xin
  indx = 0
  iret = 0
  while (indx < lenarray:i(karr)) do
    if (i(karr,indx) == ival) then
      iret = 1
      igoto end
    endif
    indx += 1
  od
end:
  xout iret
endop 
/** Create a new array by removing all instances of a
given number from an existing array. */ 
opcode remove, k[], ik[]
  ival, karr[] xin
 
  ifound = 0
  indx = 0
  while (indx < lenarray:i(karr)) do
  	if(i(karr, indx) == ival) then
      ifound += 1
    endif
    indx += 1
  od
  kout[] init (lenarray:i(karr) - ifound)
    
  indx = 0
  iwriteIndx = 0
  
  while (indx < lenarray:i(karr)) do
    iv = i(karr, indx)
    if(iv != ival) then
      kout[iwriteIndx] init iv
      iwriteIndx += 1
    endif
    indx += 1
  od
    
  xout kout
endop
/** Returns random item from karray. */
opcode rand, i, k[]
  kvals[] xin
  indx = int(random(0, lenarray(kvals)))
  ival = i(kvals, indx)
  xout ival
endop
/** Returns random item from String array. */
opcode rand, S, S[]
  Svals[] xin
  indx = int(random(0, lenarray(Svals)))
  Sval = Svals[indx]
  xout Sval
endop
/** Returns random item from karray. */
opcode randk, k, k[]
  kvals[] xin
  kndx = int(random:k(0, lenarray:k(kvals)))
  kval = kvals[kndx]
  xout kval
endop
/** Returns random item from karray. */
opcode randk, S, S[]
  Svals[] xin
  kndx = int(random:k(0, lenarray:k(Svals)))
  Sval = Svals[kndx]
  xout Sval
endop
;; Event
/** Wrapper opcode that calls schedule only if iamp > 0 and ifreq > 0. */
opcode cause, 0, Siiii
  Sinstr, istart, idur, ifreq, iamp xin
  if(ifreq > 0 && iamp > 0) then
    schedule(Sinstr, istart, idur, ifreq, iamp)
  endif
endop
;; Beats
/** Given a hexadecimal beat string pattern and optional
itick (defaults to current now_tick()), returns value 1 if
the given tick matches a hit in the hexadecimal beat, or 
returns 0 otherwise. */
opcode hexbeat, i, So
  Spat, itick xin
  if(itick <= 0) then
    itick = now_tick()
  endif
  istrlen = strlen(Spat)
  iout = 0
  if (istrlen > 0) then
    ;; 4 bits/beats per hex value
    ipatlen = strlen(Spat) * 4
    ;; get beat within pattern length
    itick = itick % ipatlen
    ;; figure which hex value to use from string
    ipatidx = int(itick / 4)
    ;; figure out which bit from hex to use
    ibitidx = itick % 4 
    
    ;; convert individual hex from string to decimal/binary
    ibeatPat = strtol(strcat("0x", strsub(Spat, ipatidx, ipatidx + 1))) 
    ;; bit shift/mask to check onset from hex's bits
    iout = (ibeatPat >> (3 - ibitidx)) & 1 
  endif
  xout iout
endop
/** Given hex beat pattern, use given itick to fire 
  events for given instrument, duration, frequency, and
  amplitude */
opcode hexplay, 0, SiSiip
  Spat, itick, Sinstr, idur, ifreq, iamp xin
  if(ifreq > 0 && iamp > 0 && strlen(Sinstr) > 0 && hexbeat(Spat, itick) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp )
  endif
endop
/** Given hex beat pattern, use global clock to fire 
  events for given instrument, duration, frequency, and
  amplitude */
opcode hexplay, 0, SSiip
  Spat, Sinstr, idur, ifreq, iamp xin
  itick = i(gk_clock_tick)
  if(ifreq > 0 && iamp > 0 && strlen(Sinstr) > 0 && hexbeat(Spat, itick) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp )
  endif
endop
/** Given an octal beat string pattern and optional
itick (defaults to current now_tick()), returns value 1 if
the given tick matches a hit in the octal beat, or 
returns 0 otherwise. */
opcode octalbeat, i, Si
  Spat, itick xin
  ;; 3 bits/beats per octal value
  ipatlen = strlen(Spat) * 4
  ;; get beat within pattern length
  itick = itick % ipatlen
  ;; figure which octal value to use from string
  ipatidx = int(itick / 3)
  ;; figure out which bit from octal to use
  ibitidx = itick % 3 
  
  ;; convert individual octal from string to decimal/binary
  ibeatPat = strtol(strcat("0", strsub(Spat, ipatidx, ipatidx + 1))) 
  ;; bit shift/mask to check onset from hex's bits
  xout (ibeatPat >> (2 - ibitidx)) & 1 
endop
opcode octalplay, 0, SiSiip
  Spat, ibeat, Sinstr, idur, ifreq, iamp xin
  if(octalbeat(Spat, ibeat) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp )
  endif
endop
opcode octalplay, 0, SSiip
  Spat, Sinstr, idur, ifreq, iamp xin
  itick = i(gk_clock_tick)
  if(octalbeat(Spat, itick) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp )
  endif
endop
;; Phase Functions
/** Given count and period, return phase value in range [0-1) */
opcode phs, i, ii
  icount, iperiod xin
  xout (icount % iperiod) / iperiod 
endop
/** Given period in ticks, return current phase of global
  clock in range [0-1) */
opcode phs, i, i
  iticks xin
  xout (i(gk_clock_tick) % iticks) / iticks
endop
/** Given period in beats, return current phase of global
  clock in range [0-1) */
opcode phsb, i, i
  ibeats xin
  iticks = ibeats * 4
  xout (i(gk_clock_tick) % iticks) / iticks
endop
/** Given period in measures, return current phase of global
  clock in range [0-1) */
opcode phsm, i, i
  imeasures xin
  iticks = imeasures * 4 * 4
  xout (i(gk_clock_tick) % iticks) / iticks
endop
;; Iterative Euclidean Beat Generator
;; Returns string of 1 and 0's
opcode euclid_str, S, ii
  ihits, isteps xin
  Sleft = "1"
  Sright = "0"
  ileft = ihits
  iright = isteps - ileft
  while iright > 1 do
    if (iright > ileft) then
      iright = iright - ileft 
      Sleft = strcat(Sleft, Sright)
    else
      itemp = iright
      iright = ileft - iright
      ileft = itemp 
      Stemp = Sleft
      Sleft = strcat(Sleft, Sright)
      Sright = Stemp
    endif
  od
  Sout = ""
  indx = 0 
  while (indx < ileft) do
    Sout = strcat(Sout, Sleft)
    indx += 1
  od
  indx = 0 
  while (indx < iright) do
    Sout = strcat(Sout, Sright)
    indx += 1
  od
  xout Sout
endop
/** Given number of ihits for a period of isteps and an optional
itick (defaults to current now_tick()), returns value 1 if
the given tick matches a hit in the euclidean rhythm, or 
returns 0 otherwise. */
opcode euclid, i, iio
  ihits, isteps, itick  xin
  if(itick <= 0) then
    itick = now_tick()
  endif
  Sval = euclid_str(ihits, isteps)
  indx = itick % strlen(Sval)
  xout strtol(strsub(Sval, indx, indx + 1))
endop
opcode euclidplay, 0, iiiSiip
  ihits, isteps, itick, Sinstr, idur, ifreq, iamp xin
  if(euclid(ihits, isteps, itick) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp)
  endif
endop
opcode euclidplay, 0, iiSiip
  ihits, isteps, Sinstr, idur, ifreq, iamp xin
  itick = i(gk_clock_tick)
  if(euclid(ihits, isteps, itick) == 1) then
    schedule(Sinstr, 0, idur, ifreq, iamp)
  endif
endop
;; Phase-based Oscillators 
/** Returns cosine of given phase (0-1.0) */
opcode xcos, i,i
  iphase  xin
  xout cos(2 * $M_PI * iphase)
endop
/** Range version of xcos, similar to Impromptu's cosr */
opcode xcos, i,iii
  iphase, ioffset, irange  xin
  xout ioffset + (cos(2 * $M_PI * iphase) * irange)
endop
/** Returns sine of given phase (0-1.0) */
opcode xsin, i,i
  iphase  xin
  xout sin(2 * $M_PI * iphase)
endop
/** Range version of xsin, similar to Impromptu's sinr */
opcode xsin, i,iii
  iphase, ioffset, irange  xin
  xout ioffset + (sin(2 * $M_PI * iphase) * irange)
endop
/** Non-interpolating oscillator. Given phase in range 0-1, 
returns value within the give k-array table. */
opcode xosc, i, ik[]
  iphase, kvals[]  xin
  indx = int(lenarray:i(kvals) * (iphase % 1))  
  xout i(kvals, indx)
endop
/** Non-interpolating oscillator. Given phase duration in beats, 
returns value within the give k-array table. (shorthand for xosc(phsb(ibeats), karr) )*/
opcode xoscb, i,ik[]
  ibeats, kvals[] xin
  xout xosc(phsb(ibeats), kvals)
endop
/** Non-interpolating oscillator. Given phase duration in measures, 
returns value within the give k-array table. (shorthand for xosc(phsm(ibeats), karr) )*/
opcode xoscm, i, ik[]
  ibeats, kvals[] xin
  xout xosc(phsm(ibeats), kvals)
endop
/** Linearly-interpolating oscillator. Given phase in range 0-1, 
returns value intepolated within the two closest points of phase within k-array
table. */
opcode xosci, i, ik[]
  iphase, kvals[]  xin
  ilen = lenarray:i(kvals)
  indx = ilen * (iphase % 1)
  ibase = int(indx)  
  ifrac = indx - ibase 
  iv0 = i(kvals, ibase)  
  iv1 = i(kvals, (ibase + 1) % ilen) 
  xout iv0 + (iv1 - iv0) * ifrac
endop
/** Linearly-interpolating oscillator. Given phase duration in beats, 
returns value intepolated within the two closest points of phase within k-array
table. (shorthand for xosci(phsb(ibeats), karr) )*/
opcode xoscib, i,ik[]
  ibeats, kvals[] xin
  xout xosci(phsb(ibeats), kvals)
endop
/** Linearly-interpolating oscillator. Given phase duration in measures, 
returns value intepolated within the two closest points of phase within k-array
table. (shorthand for xosci(phsm(ibeats), karr) )*/
opcode xoscim, i,ik[]
  ibeats, kvals[] xin
  xout xosci(phsm(ibeats), kvals)
endop
/** Line (Ramp) oscillator. Given phase in range 0-1, return interpolated value between given istart and iend. */
opcode xlin, i, iii
  iphase, istart, iend xin
  xout istart + (iend - istart) * iphase
endop
;; Duration Sequences
/** Given a tick value and array of durations, returns new duration value for tick. */
opcode xoscd, i, ik[]
  itick, kdurs[] xin
  indx = 0
  isum = 0
  ilen = lenarray:i(kdurs)
  ival = 0
  while (indx < ilen) do
    isum += i(kdurs, indx)
    indx += 1
  od
  itick = itick % isum
  indx = 0
  ival = 0
  icur = 0
  while (indx < ilen) do
    itemp = i(kdurs, indx) 
    if(itick < icur + itemp) then
      ival = itemp 
      indx += ilen
    else
      icur += abs(itemp)
    endif
    
    indx += 1
  od
  xout ival 
 endop 
/** Given an array of durations, returns new duration value for current clock tick. Useful with mod division and cycle for additive/subtractive rhythms. */
opcode xoscd, i, k[]
  kdurs[] xin
  xout xoscd(now_tick(), kdurs)
endop
/** Given a tick value and array of durations, returns new duration or 0 depending upon whether tick hits a new duration value. Values
may be positive or negative, but not zero. Negative values can be interpreted as rest durations. */
opcode dur_seq, i, ik[]
  itick, kdurs[] xin
  ival = 0
  icur = 0
  ilen = lenarray:i(kdurs)
  itotal = 0
  indx = 0
  while (indx < ilen) do
    itotal += abs:i(i(kdurs, indx))
    indx += 1
  od
  ;print itotal
  indx = 0
  itick = itick % itotal
  while (indx < ilen) do
    itemp = i(kdurs, indx) 
    if(icur == itick) then
      ival = itemp 
      indx += ilen
    elseif (icur > itick) then
      indx += ilen 
    else
      icur += abs(itemp)
    endif
    
    indx += 1
  od
  xout ival 
endop
/** Given an array of durations, returns new duration or 0 depending upon
 * whether current clock tick hits a new duration value. Values
may be positive or negative, but not zero. Negative values can be interpreted
as rest durations. */
opcode dur_seq, i, k[]
  kdurs[] xin
  xout dur_seq(now_tick(), kdurs)
endop
/** Experimental opcode for generating melodic lines given array of durations, pitches, and amplitudes. Durations follow dur_seq practice that negative values are rests. Pitch and amp array indexing wraps according to their array lengths given index of non-rest duration value currently fired. */ 
opcode melodic, iii, ik[]k[]k[]
  itick, kdurs[], kpchs[], kamps[] xin
  idur = dur_seq(itick, kdurs)
  ipch = 0
  iamp = 0
  indx = 0
  itotal = 0
  ilen = lenarray:i(kdurs)
  while (indx < ilen) do
    itotal += abs:i(i(kdurs, indx))
    indx += 1
  od
  itick = itick % itotal
  if(idur > 0) then
    indx = 0
    icur = 0
    ivalindx = 0
    while (indx < ilen) do
      itemp = i(kdurs, indx) 
      if(icur == itick) then
        indx += ilen
      elseif (icur > itick) then
        indx += ilen 
      else
        if (itemp > 0) then
          ivalindx += 1 
        endif
        icur += abs(itemp)
      endif
      
      indx += 1
    od
    ipch = i(kpchs, ivalindx % lenarray:i(kpchs))
    iamp = i(kamps, ivalindx % lenarray:i(kamps))
  endif
  xout idur, ipch, iamp
endop
/** Experimental opcode for generating melodic lines given array of durations, pitches, and amplitudes. Durations follow dur_seq practice that negative values are rests. Pitch and amp array indexing wraps according to their array lengths given index of non-rest duration value currently fired. */ 
opcode melodic, iii, k[]k[]k[]
  kdurs[], kpchs[], kamps[] xin
  idur, ipch, iamp = melodic(now_tick(), kdurs, kpchs, kamps)
  xout idur, ipch, iamp
endop
;; String functions
/** 
  rotate - Rotates string by irot number of values.  
  (Inspired by rotate from Charlie Roberts' Gibber.)
*/
opcode rotate, S, Si
  Sval, irot xin
  ilen = strlen(Sval)
  irot = irot % ilen
  Sout = strcat(strsub(Sval, irot, ilen), strsub(Sval, 0, irot))
  xout Sout
endop
/** Repeats a given String x number of times. For example, `Sval = strrep("ab6a", 2)` will produce the value of "ab6aab6a". Useful in working with Hex beat strings.  */
opcode strrep, S, Si
  Sval, inum xin
    
  Sout = Sval
  indx = 1
  while (indx < inum) do
    Sout = strcat(Sout, Sval) 
    indx += 1
  od
  xout Sout
endop
;; Channel Helper
/** Sets i-rate value into channel and sets initialization to true. Works together 
  with xchan */
opcode xchnset, 0, Si
  SchanName, ival xin
  Sinit = sprintf("%s_initialized", SchanName)
  chnset(1, Sinit)
  chnset(ival, SchanName)
endop
/** xchan 
  Initializes a channel with initial value if channel has default value of 0 and
  then returns the current value from the channel. Useful in live coding to define
  a dynamic point that will be automated or set outside of the instrument that is
  using the channel. 
  Opcode is overloaded to return i- or k- value. Be sure to use xchan:i or xchan:k
  to specify which value to use. 
*/
opcode xchan, i,Si
  SchanName, initVal xin
   
  Sinit = sprintf("%s_initialized", SchanName)
  if(chnget:i(Sinit) == 0) then
    chnset(1, Sinit)
    chnset(initVal, SchanName)
  endif
  xout chnget:i(SchanName)
endop
/** xchan 
  Initializes a channel with initial value if channel has default value of 0 and
  then returns the current value from the channel. Useful in live coding to define
  a dynamic point that will be automated or set outside of the instrument that is
  using the channel. 
  Opcode is overloaded to return i- or k- value. Be sure to use xchan:i or xchan:k
  to specify which value to use. 
*/
opcode xchan, k,Si
  SchanName, initVal xin
    
  Sinit = sprintf("%s_initialized", SchanName)
  if(chnget:i(SchanName) == 0) then
    chnset(1, Sinit)
    chnset(initVal, SchanName)
  endif
  xout chnget:k(SchanName)
endop
;; SCALE/HARMONY (experimental)
gi_scale_major[] = array(0, 2, 4, 5, 7, 9, 11) 
gi_scale_minor[] = array(0, 2, 3, 5, 7, 8, 10)
gi_cur_scale[] = gi_scale_minor
gi_scale_base = 60
gi_chord_offset = 0
/** Set root note of scale in MIDI note number. */
opcode set_root, 0,i 
  iscale_root xin
  gi_scale_base = iscale_root
endop
/** Calculate frequency from root note of scale, using 
octave and pitch class. */
opcode from_root, i, ii
  ioct, ipc xin
  ival = gi_scale_base + (ioct * 12) + ipc
  xout cpsmidinn(ival)
endop
/** Set the global scale.  Currently supports "maj" for major and "min" for minor scales. */
opcode set_scale, 0,S
  Scale xin
  if(strcmp("maj", Scale) == 0) then
    gi_cur_scale = gi_scale_major
  else
    gi_cur_scale = gi_scale_minor
  endif
endop
/** Calculate frequency from root note of scale, using 
octave and scale degree. */
opcode in_scale, i, ii
  ioct, idegree xin
  ibase = gi_scale_base + (ioct * 12)
  idegrees = lenarray(gi_cur_scale)
  ioct = int(idegree / idegrees)
  indx = idegree % idegrees
  if(indx < 0) then
    ioct -= 1
    indx += idegrees
  endif
  xout cpsmidinn(ibase + (ioct * 12) + gi_cur_scale[int(indx)]) 
endop
/** Calculate frequency from root note of scale, using 
octave and scale degree. (k-rate version of opcode) */
opcode in_scale, k, kk 
  koct, kdegree xin
  kbase = gi_scale_base + (koct * 12)
  idegrees = lenarray(gi_cur_scale)
  koct = int(kdegree / idegrees)
  kndx = kdegree % idegrees
  if(kndx < 0) then
    koct -= 1
    kndx += idegrees
  endif
  xout cpsmidinn(kbase + (koct * 12) + gi_cur_scale[int(kndx)]) 
endop
/** Quantizes given MIDI note number to the given scale 
    (Base on pc:quantize from Extempore) */
opcode pc_quantize, i, ii[]
  ipitch_in, iscale[] xin
  inotenum = round:i(ipitch_in)
  ipc = inotenum % 12
  iout = inotenum
  
  
  indx = 0
  while (indx < 7) do
    if(contains(ipc + indx, iscale) == 1) then
      iout = inotenum + indx
      goto end
    elseif (contains(ipc - indx, iscale) == 1) then
      iout = inotenum - indx
      goto end
    endif
    indx += 1
  od
  end:
  xout iout
endop
/** Quantizes given MIDI note number to the current active scale 
    (Base on pc:quantize from Extempore) */
opcode pc_quantize, i, i
  ipitch_in xin
  ival = pc_quantize(ipitch_in, gi_cur_scale)
  xout ival
endop  
/* BELOW CHORD SYSTEM IS EXPERIMENTAL */
gi_chord_base = 0 
gi_chord_maj[] = array(0,4,7)
gi_chord_maj7[] = array(0,4,7,11)
gi_chord_min[] = array(0,3,7)
gi_chord_min7[] = array(0,3,7,10)
gi_chord_dim[] = array(0,3,6)
gi_chord_dim7[] = array(0,3,6,9)
gi_chord_aug[] = array(0,4,8)
gi_chord_current[] = gi_chord_maj 
opcode set_chord, 0, ii[]
  ichord_root, ichord_intervals[] xin
  gi_chord_base = ichord_root
  gi_chord_current = ichord_intervals
endop
opcode set_chord, 0, S 
  Schord xin
endop
opcode in_chord, i, ii
  ioct, idegree xin
  ibase = gi_scale_base + (ioct * 12) + gi_chord_base
  idegrees = lenarray(gi_chord_current)
  ioct = int(idegree / idegrees)
  indx = idegree % idegrees
  if(indx < 0) then
    ioct -= 1
    indx += idegrees
  endif
  xout cpsmidinn(ibase + (ioct * 12) + gi_chord_current[indx]) 
endop
;; AUDIO
/** Utility opcode for declicking an audio signal. Should only be used in instruments that have positive p3 duration. */
opcode declick, a, a
  ain xin
  aenv = linseg:a(0, 0.01, 1, p3 - 0.02, 1, 0.01, 0, 0.01, 0)
  xout ain * aenv
endop
/** Custom non-interpolating oscil that takes in kfrequency and array to use as oscillator table
data. Outputs k-rate signal. */
opcode oscil, k, kk[]
  kfreq, kin[] xin
  ilen = lenarray(kin)
  kphs = phasor:k(kfreq)
  kout = kin[int(kphs * ilen) % ilen]
  xout kout
endop
;; KILLING INSTANCES
instr KillImpl
  Sinstr = p4 
  if (nstrnum(Sinstr) > 0) then
    turnoff2(Sinstr, 0, 0)
  endif
  turnoff
endin
/** Turns off running instances of named instruments.  Useful when livecoding
  audio and control signal process instruments. May not be effective if for
  temporal recursion instruments as they may be non-running but scheduled in the
  event system. In those situations, try using clear_instr to overwrite the
  instrument definition. */
opcode kill, 0,S
  Sinstr xin
  schedule("KillImpl", 0, 0.01, Sinstr)
endop
/** Redefines instr to empty body. Useful for killing
  temporal recursion or clock callback functions */
opcode clear_instr, 0,S
  Sinstr xin
  Sinstr_body = sprintf("instr %s\nendin\n", Sinstr)
  ires = compilestr(Sinstr_body)
  prints(sprintf("Cleared instrument definition: %s\n", 
          Sinstr))
endop
/** Starts running a named instrument for indefinite time using p2=0 and p3=-1. 
  Will first turnoff any instances of existing named instrument first.  Useful
  when livecoding always-on audio and control signal process instruments. */
opcode start, 0,S
  Sinstr xin
  if (nstrnum(Sinstr) > 0) then
    kill(Sinstr)
    schedule(Sinstr, ksmps / sr,-1)
  endif
endop
/** Stops a running named instrument, allowing for release segments to operate. */
opcode stop, 0,S
  Sinstr xin
  if (nstrnum(Sinstr) > 0) then
    schedule(-nstrnum(Sinstr), 0, 0)
  endif
endop
instr CodeEval
  Scode = p4
  ires = compilestr(Scode)
endin
/** Evaluate code at a given time */
opcode eval_at_time, 0, Si 
  Scode, istart xin
  iblock init ksmps / sr
  ;; adjust one block of time difference since this is
  ;; will need to be added as an event back on to the scheduler
  schedule("CodeEval", max:i(0, istart - iblock), 0, Scode)
endop
;; Fades 
gi_fade_range init -30
/** Sets the range in db to fade over. By default, range is -30 (i.e., fades from -30dbfs to 0dbfs) */
opcode set_fade_range, 0, i
  irange xin
  gi_fade_range init irange
endop
/** Given a fade channel identifier (number) and number of ticks to fade over time, advances from current fade channel value towards 0dbfs (1.0) using the globally set fade range. (By default starts fading in from -30dBfs and stops at 0dbfs.) */
opcode fade_in, i, ii
  ident, inumticks xin
  Schan = sprintf("fade_chan_%d", ident)
  ival = chnget:i(Schan)
  if(ival < 1.0) then
    ival = limit:i(ival + (1 / inumticks), 0, 1.0) 
    chnset(ival, Schan)
    iret = ampdbfs((1- ival) * gi_fade_range)
  else
    iret = ival
  endif
  xout iret 
endop
/** Given a fade channel identifier (number) and number of ticks to fade over time, advances from current fade channel value towards 0 using the globally set fade range. (By default starts fading out from 0dBfs and stops at -30dbfs.) */
opcode fade_out, i, ii
  ident, inumticks xin
  Schan = sprintf("fade_chan_%d", ident)
  ival = chnget:i(Schan)
  iret init 0
  if(ival > 0.0) then
    ival = limit:i(ival - (1 / inumticks), 0, 1.0) 
    chnset(ival, Schan)
    iret = ampdbfs((1- ival) * gi_fade_range)
  else
    iret = ival
  endif
  xout iret 
endop
/** Read value from fade channel. Useful if copy/pasting then wanting to just read from fade and control in the original code. */
opcode fade_read, i, i
  ident xin
  Schan = sprintf("fade_chan_%d", ident)
  iret = chnget:i(Schan)
  xout iret 
endop
/**  Set value for fade channel to given value. Should be in range 0-1.0.  (Typically one sets to either 0 or 1.) */
opcode set_fade, 0,ii
  ident, ival xin
  Schan = sprintf("fade_chan_%d", ident)
  ival = limit:i(ival, 0, 1.0) 
  chnset(ival, Schan)
endop
;; Stereo Audio Bus
ga_sbus[] init 16, 2
/** Write two audio signals into stereo bus at given index */
opcode sbus_write, 0,iaa
  ibus, al, ar xin
  ga_sbus[ibus][0] = al
  ga_sbus[ibus][1] = ar
endop
/** Mix two audio signals into stereo bus at given index */
opcode sbus_mix, 0,iaa
  ibus, al, ar xin
  ga_sbus[ibus][0] = ga_sbus[ibus][0] + al
  ga_sbus[ibus][1] = ga_sbus[ibus][1] + ar
endop
/** Clear audio signals from bus channel */
opcode sbus_clear, 0, i
  ibus xin
  aclear init 0
  ga_sbus[ibus][0] = aclear
  ga_sbus[ibus][1] = aclear
endop
/** Read audio signals from bus channel */
opcode sbus_read, aa, i
  ibus xin
  aclear init 0
  al = ga_sbus[ibus][0] 
  ar = ga_sbus[ibus][1] 
  xout al, ar
endop
;; MIXER
gi_reverb_mixer_on init 0
/** Always-on Mixer instrument with Reverb send channel. Use start("ReverbMixer") to run. Designed 
    for use with pan_verb_mix to simplify signal-based live coding. */
instr ReverbMixer
  gi_reverb_mixer_on init 1
  ;; dry and reverb send signals
  a1, a2 sbus_read 0
  a3, a4 sbus_read 1
  
  al, ar reverbsc a3, a4, xchan:k("Reverb.fb", 0.7), xchan:k("Reverb.cut", 12000)
  
  kamp = xchan:k("Mix.amp", 1.0)
  
  a1 = tanh(a1 + al) * kamp
  a2 = tanh(a2 + ar) * kamp
  
  out(a1, a2)
  
  sbus_clear(0)
  sbus_clear(1)
endin
/** Always-on Mixer instrument with Reverb send channel and feedback delay. Use start("FBReverbMixer") to run. Designed 
    for use with pan_verb_mix to simplify signal-based live coding. */
instr FBReverbMixer 
  al, ar sbus_read 0
  
  afb0 init 0
  afb1 init 0
  gi_reverb_mixer_on init 1
  ;; dry and reverb send signals
  a1, a2 sbus_read 0
  a3, a4 sbus_read 1
  
  al, ar reverbsc a3, a4, xchan:k("Reverb.fb", 0.7), xchan:k("Reverb.cut", 12000)
  a1 = tanh(a1 + al + afb0) 
  a2 = tanh(a2 + ar + afb1)
 
  kfb_amt = xchan:k("FB.amt", 0.9)
  kfb_dur = xchan:k("FB.dur", 4.2) * 1000 ;; time in ms
  afb0 = vdelay(a1 * kfb_amt, kfb_dur, 10000)
  afb1 = vdelay(a2 * kfb_amt, kfb_dur, 10000)
  kamp = xchan:k("Mix.amp", 1.0)
  a1 *= kamp
  a2 *= kamp
  
  out(a1, a2)
  
  sbus_clear(0)
  sbus_clear(1)
endin
/** Utility opcode to pan signal, send dry to mixer, and send amount 
    of signal to reverb. If ReverbMixer is not on, will output just 
    panned signal using out opcode. */
opcode pan_verb_mix, 0,akk
  asig, kpan, krvb xin
   ;; Panning and send to mixer
  al, ar pan2 asig, kpan
 
  if(gi_reverb_mixer_on == 1) then
    sbus_mix(0, al, ar)
    sbus_mix(1, al * krvb, ar * krvb)
  else 
    out(al, ar)
  endif
endop
/** Utility opcode to send dry stereo to mixer and send amount 
    of stereo signal to reverb. If ReverbMixer is not on, will output just 
    panned signal using out opcode. */
opcode reverb_mix, 0, aak
  al, ar, krvb xin
 
  if(gi_reverb_mixer_on == 1) then
    sbus_mix(0, al, ar)
    sbus_mix(1, al * krvb, ar * krvb)
  else 
    out(al, ar)
  endif
endop
;; Automation
/** Set a channel value at a given time. p4=ChannelName, p5=value*/ 
instr ChnSet
  Schan = p4
  ival = p5
  chnset(ival, Schan)
endin
/** Automation instrument for channels. Takes in "ChannelName", start value, end value, and automation type (0=linear, else exponential). */ 
instr Auto 
  Schan = p4
  istart = p5
  iend = p6
  itype = p7
  kauto init 0
  if(itype == 0) then
    kauto = line:k(istart, p3, iend)
  else
    kauto = expon:k(istart, p3, iend)
  endif
  chnset(kauto, Schan)
endin
/** Automate channel value over time. Takes in "ChannelName", duration, start value, end value, and automation type (0=linear, else exponential). For exponential, signs of istart and end must match and neither can be zero. */ 
opcode automate, 0, Siiii
  Schan, idur, istart, iend, itype xin
  schedule("Auto", 0, idur, Schan, istart, iend, itype)
endop
instr FadeOutMix
  kauto = ampdbfs:k(line:k(0, p3, -60))
  chnset(kauto, "Mix.amp")
endin
/** Utility opcode for end of performances to fade out Mixer over given idur time. idur defaults to 30 seconds. **/
opcode fade_out_mix, 0, o
  idur xin
  idur = (idur <= 0 ? 30 : idur)
  schedule("FadeOutMix", 0, idur) 
  schedule("ChnSet", idur + 0.1, 0, "Mix.amp", 0)
endop
;; DSP
/** Saturation using tanh */
opcode saturate, a, ak
  asig, ksat xin
  xout tanh(asig * ksat) / tanh(ksat)
endop
;; SYNTHS
xchnset("rvb.default", 0.1)
xchnset("drums.rvb.default", 0.1)
/** Substractive Synth, 3osc */
instr Sub1
  asig = vco2(ampdbfs(-12), p4)
  asig += vco2(ampdbfs(-12), p4 * 1.01, 10)
  asig += vco2(ampdbfs(-12), p4 * 2, 10)
  asig = zdf_ladder(asig, expon(10000, p3, 400), 5)
  asig = declick(asig) * p5
  pan_verb_mix(asig, xchan:i("Sub1.pan", 0.5), xchan:i("Sub1.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, two saws, fifth freq apart */
instr Sub2
  icut = xchan:i("Sub2.cut", sr / 3)
  asig = vco2(ampdbfs(-12), p4) 
  asig += vco2(ampdbfs(-12), p4 * 1.5) 
  asig = zdf_ladder(asig, expon(icut, p3, 400), 5)
  asig = declick(asig) * p5
  pan_verb_mix(asig, xchan:i("Sub2.pan", 0.5), xchan:i("Sub2.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, three detuned saws, swells in */
instr Sub3 
  asig = vco2(p5, p4)
  asig += vco2(p5, p4 * 1.01)
  asig += vco2(p5, p4 * 0.995)
  asig *= 0.33 
  asig = zdf_ladder(asig, expon(100, p3, 22000), 12) 
  asig = declick(asig)
  pan_verb_mix(asig, xchan:i("Sub3.pan", 0.5), xchan:i("Sub3.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, detuned square/saw, stabby. 
   Nice as a lead in octave 2, nicely grungy in octave -2, -1
*/
instr Sub4 
  asig = vco2(0.5, p4 * 2)
  asig += vco2(0.5, p4 * 2.01, 10)
  asig += vco2(1, p4, 10)
  asig += vco2(1, p4 * 0.99)
  itarget = p4 * 2
  asig = zdf_ladder(asig, expseg(20000, 0.15, itarget, 0.1, itarget), 5)
  asig = declick(asig) * p5 * 0.15
  pan_verb_mix(asig, xchan:i("Sub4.pan", 0.5), xchan:i("Sub4.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, detuned square/triangle */
instr Sub5
  asig = vco2(0.5, p4, 10)
  asig += vco2(0.25, p4 * 2.0001, 12)
  asig = zdf_ladder(asig, expseg(10000, 0.1, 500, 0.1, 500), 2)
  asig = declick(asig) * p5 * 0.75
  pan_verb_mix(asig, xchan:i("Sub5.pan", 0.5), xchan:i("Sub5.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, saw, K35 filters */
instr Sub6
  asig = vco2(p5, p4)
  asig = K35_hpf(asig, limit:i(p4, 30, 16000), 1)
  asig = K35_lpf(asig, expseg:k(12000, p3, limit:i(p4 * 8, 30, 12000)), 2.5)
  
  asig = saturate(asig, 4.5)
  asig *= p5 * 0.5
  
  asig = declick(asig)
  
  pan_verb_mix(asig, xchan:i("Sub6.pan", 0.5), xchan:i("Sub6.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, saw + tri, K35 filters */
instr Sub7
  asig = vco2(p5, p4)
  asig += vco2(p5, p4 * 2, 4, 0.5)
  asig = K35_hpf(asig, limit:i(p4, 30, 16000), 1)
  asig = K35_lpf(asig, expseg:k(12000, p3, limit:i(p4 * 8, 30, 12000)), 2.5)
  
  asig = saturate(asig, 4.5)
  asig *= p5 * 0.3
  
  asig = declick(asig)
  
  pan_verb_mix(asig, xchan:i("Sub7.pan", 0.5), xchan:i("Sub7.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Synth, square + saw + tri, diode ladder filter */
instr Sub8
  asig = vco2(p5, p4, 10)
  asig += vco2(p5 * 0.5, p4 * 2)
  asig += vco2(p5 * 0.15, p4 * 3.5, 12)  
  
  aenv = expon:a(1, 0.15, 0.001)
  asig = saturate(asig, 10)
  asig = diode_ladder(asig, 4000 + aenv * 4000, 12)
  asig = zdf_2pole(asig, p5, 0.25, 1)
  asig *= linen:a(1, 0, p3, .001) * 0.5
  pan_verb_mix(asig, xchan:i("Sub8.pan", 0.5), xchan:i("Sub8.rvb", chnget:i("rvb.default")))
endin
/** SynthBrass subtractive synth */ 
instr SynBrass
  ipch = p4
  asig = vco2(0.25, ipch)
  asig += vco2(0.25, ipch * 2.00)
  asig = zdf_ladder(asig, expseg(12000, 0.25, 500, 0.05, 500), 4)
  asig = declick(asig * p5)
  pan_verb_mix(asig, xchan:i("SynBrass.pan", 0.5), xchan:i("SynBrass.rvb", chnget:i("rvb.default")))
endin
/** Synth Harp subtracitve Synth */
instr SynHarp
  
  asig = vco2(p5, p4)
  asig += vco2(p5, p4 * 0.9993423423)
  asig += vco2(p5, p4 * 1.00093029423048) 
  
  ioct = octcps(p4)
  
  asig = zdf_ladder(asig, cpsoct(limit(linseg:a(ioct + 4, 0.015, ioct + 2, 0.2, ioct), 4.25, 14)), 0.5)
  asig = zdf_2pole(asig, p4 * 0.5, 0.5, 1)    
  
  asig *= linen:a(1, 0.012, p3, 0.01)
  
  pan_verb_mix(asig, xchan:i("SynHarp.pan", 0.5), xchan:i("SynHarp.rvb", chnget:i("rvb.default")))
endin
 
/** SuperSaw sound using 9 bandlimited saws (3 sets of detuned saws at octaves)*/
instr SSaw
  asig = vco2(1, p4)
  asig += vco2(1, p4 * cent(9.04234))
  asig += vco2(1, p4 * cent(-7.214342))
  
  asig += vco2(1, p4 * cent(1206.294143))
  asig += vco2(1, p4 * cent(1193.732))
  asig += vco2(1, p4 * cent(1200))
  
  asig += vco2(1, p4 * cent(2406.294143))
  asig += vco2(1, p4 * cent(2393.732))
  asig += vco2(1, p4 * cent(2400))
  
  asig *= 0.1
  icut = xchan:i("SSaw.cut", 16000)
  asig = zdf_ladder(asig, expseg(icut, p3 - 0.05, icut, 0.05, 200), 0.5)
  asig *= p5 
  asig = declick(asig)
  pan_verb_mix(asig, xchan:i("SSaw.pan", 0.5), xchan:i("SSaw.rvb", chnget:i("rvb.default")))
endin
/** Modal Synthesis Instrument: Percussive/organ-y sound */
instr Mode1
  asig = mpulse(p5, 0)
  asig1 = mode(asig, p4, p4 * 0.5)
  asig1 += mode(asig, p4 * 2, p4 * 0.25)
  asig1 += mode(asig, p4 * 4, p4 * 0.125)
  asig = declick(asig1) 
  pan_verb_mix(asig, xchan:i("Mode1.pan", 0.5), xchan:i("Mode1.rvb", chnget:i("rvb.default")))
endin
/** Pluck sound using impulses, noise, and waveguides*/
instr Plk 
  asig = mpulse(p5, 1 / p4)
  asig += random:a(-0.1, 0.1) * expseg(p5, 0.02, 0.001, p3, 0.001)
  
  aout wguide1 asig, 1/ p4, 10000, 0.8
  aout += wguide1(asig, 1/ (2 * p4), 12000, 0.6)
  aout = K35_hpf(aout, p4, 0.5)
  aout = zdf_ladder(aout, expon(10000, p3, 100), 3)
  aout = dcblock2(aout)
  
  asig = declick(aout) 
  
  pan_verb_mix(asig, xchan:i("Plk.pan", 0.5), xchan:i("Plk.rvb", chnget:i("rvb.default")))
endin
gi_organ1 = ftgen(0, 0, 65536, 10, 1, 0.5, 0.3, 0.2, 0.05, 0.015)
/** Wavetable Organ sound using additive synthesis */
instr Organ1
  asig = oscili(p5, p4, gi_organ1)
  asig *= 0.5
  asig = declick(asig)
  pan_verb_mix(asig, xchan:i("Organ1.pan", 0.5), xchan:i("Organ1.rvb", chnget:i("rvb.default")))
endin
/** Organ sound based on M1 Organ 2 patch */
instr Organ2
  asig = vco2(1, p4, 4, 0.25)
  asig += vco2(0.8, p4 * 2, 12)
  asig += vco2(0.3, p4 * 3, 10)
     
  icutStart = limit:i(xchan:i("Organ2.cut", 2000), 40, sr * 1/2)
  icutEnd = limit:i(xchan:i("Organ2.cutEnd", 500), 40, sr * 1/2)
  asig = zdf_ladder(asig, expseg(icutStart, 0.08, icutEnd, p3, icutEnd), 2)
  
  asig *= p5 * 0.67
  asig = declick(asig)
  
  pan_verb_mix(asig, xchan:i("Organ2.pan", 0.5), xchan:i("Organ2.rvb", chnget:i("rvb.default")))
endin
giorgan_claribel_flute = ftgen(0, 0, 65536, 10, 1, ampdbfs(-30), ampdbfs(-35), ampdbfs(-40), ampdbfs(-32), ampdbfs(-40), ampdbfs(-42))
/** Wavetable Organ using Flute 8' and Flute 4', wavetable based on Claribel Flute 
    http://www.pykett.org.uk/the_tonal_structure_of_organ_flutes.htm */
instr Organ3 
  asig = oscili(p5, p4, giorgan_claribel_flute)
  asig += oscili(p5, p4 * 2, giorgan_claribel_flute)  
  ;asig += oscili(p5, p4 * 0.5)
  
  asig *= linen:a(1, .02, p3, .01)
  pan_verb_mix(asig, xchan:i("Organ3.pan", 0.5), xchan:i("Organ3.rvb", chnget:i("rvb.default")))
endin
/** Subtractive Bass sound */
instr Bass
  asig = vco2(p5, p4, 10)
  asig += vco2(p5 * 0.25, p4 * 0.9992342342, 10)  
  asig += vco2(p5 * 0.5, p4 * 2.000234234)
  aenv = linseg:a(1, 0.2, 0.1, p3 - 0.2, 0) * 6
  asig = zdf_ladder(asig, cpsoct(5 + aenv), 4 )
  
  asig *= linen:a(0.7, 0, p3, 0.01)
  
  pan_verb_mix(asig, xchan:i("Bass.pan", 0.5), xchan:i("Bass.rvb", chnget:i("rvb.default")))
endin
/** MS20-style Bass Sound */
instr ms20_bass 
  ipch = p4 
  iamp = p5 
  aenv = expseg(1000, 0.1, ipch * 2, p3 - .05, ipch * 2)
  asig = vco2(1.0, ipch)
  asig = K35_hpf(asig, ipch, 5, 0, 1)
  asig = K35_lpf(asig, aenv, 8, 0, 1)
  asig *= expon:a(iamp, p3, 0.0001) 
  pan_verb_mix(asig, xchan:i("ms20_bass.pan", 0.5), xchan:i("ms20_bass.rvb", chnget:i("rvb.default")))
endin
/** VoxHumana Patch */
instr VoxHumana 
  ipch = p4 
  iamp = p5 
  aenv = transegr:a(0, 0.453, 1, 1.0, 2.242, -1, 0)
  klfo_pulse_width = lfo(0.125, 5.72, 1)
  klfo_saw = lfo(0.021, 5.04, 1)
  klfo_pulse = lfo(0.013, 3.5, 1)
  asaw = vco2(iamp, ipch * (1 + klfo_saw))
  apulse = vco2(iamp, ipch * (1.00004 + klfo_pulse), 2, 0.625 + klfo_pulse_width)
  aout = sum(asaw, apulse) * 0.0625 * aenv
  ikeyfollow = 1 + exp( (ipch - 50) / 10000)
  aout = butterlp(aout, 1986 * ikeyfollow)
  pan_verb_mix(aout, xchan:i("VoxHumana.pan", 0.5), xchan:i("VoxHumana.rvb", chnget:i("rvb.default")))
endin
/** FM 3:1 C:M ratio, 2->0.025 index, nice for bass */
instr FM1 
  icar = xchan("FM1.car", 1)
  imod = xchan("FM1.mod", 3)
  asig = foscili(p5, p4, icar, imod, expon(2, 0.2, 0.025))
  asig = declick(asig) * 0.5
  pan_verb_mix(asig, xchan:i("FM1.pan", 0.5), xchan:i("FM1.rvb", chnget:i("rvb.default")))
endin
/** Filtered noise, exponential envelope */
instr Noi 
  p3 = max:i(p3, 0.4) 
  asig = pinker() * p5 * expon(1, p3, 0.001) * 0.1
  a1 = mode(asig, p4, 80)
  a2 = mode(asig, p4 * 2, 40)
  a3 = mode(asig, p4 * 3, 30)
  a4 = mode(asig, p4 * 4, 20)
  asig sum a1, a2, a3, a4
  asig = declick(asig) * 0.25
  pan_verb_mix(asig, xchan:i("Noi.pan", 0.5), xchan:i("Noi.rvb", chnget:i("rvb.default")))
endin
/** Wobble patched based on Jacob Joaquin's "Tempo-Synced Wobble Bass" */
instr Wobble
  /*p3 = max:i(p3, 0.4) */
  itri = chnget:i("Wobble.triangle")
  if(itri == 0) then
    ;; unipolar triangle
    itri = ftgen(0, 0, 8192, -7, 0, 4096, 1, 4096, 0)
    chnset(itri, "Wobble.triangle")
  endif
  ;; dur in ticks (16ths) for wobble lfo 
  iticks = xchan("Wobble.ticks", 2)
  ;; modulation max
  imod = p4 * 8 
  klfo = oscili:k(1, 1 / ticks(iticks), itri)
  asig = vco2(p5, p4 * 2.018)
  asig += vco2(p5, p4, 10)
  asig = zdf_ladder(asig, min:k(p4 + (imod * klfo), 22000), 12) 
  asig *= expon(1, beats(16), 0.001)
  asig = declick(asig)
  pan_verb_mix(asig, xchan:i("Wobble.pan", 0.5), xchan:i("Wobble.rvb", chnget:i("rvb.default")))
endin
/** Simple Sine-wave instrument with exponential envelope */
instr Sine
  asig = oscili(p5, p4)
  asig *= expseg:a(0.1, 0.001, 1, 0.1, 0.001, p3, 0.001)
  pan_verb_mix(asig, xchan:i("Sine.pan", 0.5), xchan:i("Sine.rvb", chnget:i("rvb.default")))
endin
/** Simple Square-wave instrument with exponential envelope */
instr Square
  asig = vco2(p5, p4, 10)
  asig *= expseg:a(0.1, 0.005, 1, 0.1, 0.001, p3, 0.001)
  pan_verb_mix(asig, xchan:i("Square.pan", 0.5), xchan:i("Square.rvb", chnget:i("rvb.default")))
endin
/** Simple Sawtooth-wave instrument with exponential envelope */
instr Saw
  asig = vco2(p5, p4)
  asig *= expseg:a(0.1, 0.005, 1, 0.1, 0.001, p3, 0.001)
  pan_verb_mix(asig, xchan:i("Saw.pan", 0.5), xchan:i("Saw.rvb", chnget:i("rvb.default")))
endin
;; SQUINE WAVE SYNTHS
/** Squinewave Synth, 2 osc */
instr Squine1
  asig squinewave a(p4), expon:a(.8, p3, .1), expon:a(.9, p3, .5), 0, 4
  a2 squinewave a(p4 * 1.0019234234), expseg:a(.8, p3, .6), a(0), 0, 4
  asig = (asig + a2 * 0.05) * p5 * 0.5
  asig = butterhp(asig, p4)
  asig *= linen:a(1, .015, p3, .02) 
  asig = dcblock2(asig)
  pan_verb_mix(asig, xchan:i("Squine1.pan", 0.5), xchan:i("Squine1.rvb", chnget:i("rvb.default")))
  
endin
gi_lc_sine = ftgen(0, 0, 65536, 10, 1)
/** Formant Synth, buzz source, soprano ah formants */
instr Form1 
  iamp = p5
  ifreq = p4
  asig = buzz(1, ifreq * (1 + lfo(.003, 4)), (sr / 2) / ifreq, gi_lc_sine)
  
  a1 = butterbp(asig, 800, 80)
  a2 = butterbp(asig * ampdbfs(-6), 1150, 90)
  a3 = butterbp(asig * ampdbfs(-32), 2900 , 120)
  a4 = butterbp(asig * ampdbfs(-20), 3900, 130)
  a5 = butterbp(asig * ampdbfs(-50), 4950, 140)
  asig = a1 + a2 + a3 + a4 + a5
  asig *= 35 * iamp * adsr(0.05, 0, 1, 0.01)
  
  pan_verb_mix(asig, xchan:i("Form1.pan", 0.5), xchan:i("Form1.rvb", chnget:i("rvb.default")))
endin
;; MONOPHONIC SYNTHS
/** Monophone synth using sawtooth wave and 4pole lpf. Use "start("Mono") to run the monosynth, then use MonoNote instrument to play the instrument. */
instr Mono
  asig = vco2(xchan:k("Mono.amp", 0.0), portk(xchan:k("Mono.freq", 60), xchan:k("Mono.glide", 0.02)))
  asig = zdf_ladder(asig, xchan:k("Mono.cut", 4000), xchan:k("Mono.Q", 10))
  
  kpan = xchan:k("Mono.pan", 0.5)
  aL,aR pan2  asig,kpan             
  pan_verb_mix(asig, xchan:k("Mono.pan", 0.5), xchan:k("Mono.rvb", chnget:i("rvb.default")))
endin
maxalloc("Mono", 1)
/** Note playing instrument for Mono synth. Be careful to use this
and not try to create multiple Mono instruments! */
instr MonoNote
  chnset(expon(p5, p3, 0.001), "Mono.amp")
  chnset(p4, "Mono.freq")
endin
;; DRUMS
/** Bandpass-filtered impulse glitchy click sound. p4 = center frequency (e.g., 3000, 6000) */
instr Click 
  asig = mpulse(1, 0)
  asig = zdf_2pole(asig, p4, 3, 3)
  
  asig *= p5 * 4      ;; adjust amp 
  asig *= linen:a(1, 0, p3, 0.01)
  
  pan_verb_mix(asig, xchan:i("Click.pan", 0.5), xchan:i("Click.rvb", chnget:i("rvb.default")))
endin
/** Highpass-filtered noise+saw sound. Use NoiSaw.cut channel to adjust cutoff. */
instr NoiSaw 
  asig = random:a(-1, 1)
  asig += vco2(1, 100)
  asig = zdf_2pole(asig, xchan:i("NoiSaw.cut", 3000), 1, 3)
  
  asig *= p5 * 0.5
  asig *= expseg:a(1, 0.1, 0.001, p3, 0.0001)
  
  asig *= linen:a(1, 0, p3, 0.01)
  
  pan_verb_mix(asig, xchan:i("NoiSaw.pan", 0.5), xchan:i("NoiSaw.rvb", chnget:i("rvb.default")))
endin
/** Modified clap instrument by Istvan Varga (clap1.orc) */
instr Clap
  ifreq = p4 ;; ignore
  iamp = p5
  ibpfrq  =  1046.5       /* bandpass filter frequency */
  kbpbwd =  port:k(ibpfrq*0.25, 0.03, ibpfrq*4.0)   /* bandpass filter bandwidth */
  idec  =  0.5          /* decay time        */
  a1  =  1.0
  a1_ delay1 a1
  a1  =  a1 - a1_
  a2  delay a1, 0.011
  a3  delay a1, 0.023
  a4  delay a1, 0.031
  a1  tone a1, 60.0
  a2  tone a2, 60.0
  a3  tone a3, 60.0
  a4  tone a4, 1.0 / idec
  aenv1 =  a1 + a2 + a3 + a4*60.0*idec
  a_  unirand 2.0
  a_  =  aenv1 * (a_ - 1.0)
  a_  butterbp a_, ibpfrq, kbpbwd
  aout = a_ * 80 * iamp ;; 
  pan_verb_mix(aout, xchan:k("Clap.pan", 0.7), xchan:k("Clap.rvb", chnget:i("drums.rvb.default")))
endin
gi_808_sine  ftgen 0,0,1024,10,1   ;A SINE WAVE
gi_808_cos ftgen 0,0,65536,9,1,1,90  ;A COSINE WAVE 
/** Bass Drum - From Iain McCurdy's TR-808.csd */
instr BD  ;BASS DRUM
  p3  = 2 * xchan("BD.decay", 0.5)              ;NOTE DURATION. SCALED USING GUI 'Decay' KNOB
  ilevel = xchan("BD.level", 1) * 2
  itune = xchan("BD.tune", 0)
  ;SUSTAIN AND BODY OF THE SOUND
  kmul = transeg(0.2,p3*0.5,-15,0.01, p3*0.5,0,0)         ;PARTIAL STRENGTHS MULTIPLIER USED BY GBUZZ. DECAYS FROM A SOUND WITH OVERTONES TO A SINE TONE.
  kbend = transeg(0.5,1.2,-4, 0,1,0,0)            ;SLIGHT PITCH BEND AT THE START OF THE NOTE 
  asig = gbuzz(0.5,50*octave(itune)*semitone(kbend),20,1,kmul,gi_808_cos)   ;GBUZZ TONE
  aenv = transeg:a(1,p3-0.004,-6,0)             ;AMPLITUDE ENVELOPE FOR SUSTAIN OF THE SOUND
  aatt = linseg:a(0,0.004,1, .01, 1)              ;SOFT ATTACK
  asig= asig*aenv*aatt
  ;HARD, SHORT ATTACK OF THE SOUND
  aenv  = linseg:a(1,0.07,0, .01, 0)              ;AMPLITUDE ENVELOPE (FAST DECAY)            
  acps = expsega(400,0.07,0.001,1,0.001)            ;FREQUENCY OF THE ATTACK SOUND. QUICKLY GLISSES FROM 400 Hz TO SUB-AUDIO
  aimp = oscili(aenv,acps*octave(itune*0.25),gi_808_sine)       ;CREATE ATTACK SOUND
  
  amix  = ((asig*0.5)+(aimp*0.35))*ilevel*p5      ;MIX SUSTAIN AND ATTACK SOUND ELEMENTS AND SCALE USING GUI 'Level' KNOB
  
  pan_verb_mix(amix, xchan:k("BD.pan", 0.5), xchan:k("BD.rvb", chnget:i("drums.rvb.default")))
endin
/** Snare Drum - From Iain McCurdy's TR-808.csd */
instr SD  ;SNARE DRUM
  
  ;SOUND CONSISTS OF TWO SINE TONES, AN OCTAVE APART AND A NOISE SIGNAL
  idur = xchan("SD.decay", 1.0) 
  ilevel = xchan("SD.level", 1) 
  itune = xchan("SD.tune", 0)
  ifrq    = 342   ;FREQUENCY OF THE TONES
  iNseDur = 0.3 * idur  ;DURATION OF THE NOISE COMPONENT
  iPchDur = 0.1 * idur  ;DURATION OF THE SINE TONES COMPONENT
  p3  = iNseDur   ;p3 DURATION TAKEN FROM NOISE COMPONENT DURATION (ALWATS THE LONGEST COMPONENT)
  
  ;SINE TONES COMPONENT
  aenv1 = expseg(1, iPchDur, 0.0001, p3-iPchDur, 0.0001)    ;AMPLITUDE ENVELOPE
  apitch1 = oscili(1, ifrq * octave(itune), gi_808_sine)      ;SINE TONE 1
  apitch2 = oscili(0.25, ifrq * 0.5 * octave(itune), gi_808_sine)   ;SINE TONE 2 (AN OCTAVE LOWER)
  apitch  = (apitch1+apitch2)*0.75        ;MIX THE TWO SINE TONES
  ;NOISE COMPONENT
  aenv2 = expon(1,p3,0.0005)          ;AMPLITUDE ENVELOPE
  anoise = noise(0.75, 0)           ;CREATE SOME NOISE
  anoise = butbp(anoise, 10000*octave(itune), 10000)    ;BANDPASS FILTER THE NOISE SIGNAL
  anoise = buthp(anoise, 1000)          ;HIGHPASS FILTER THE NOISE SIGNAL
  kcf = expseg(5000, 0.1, 3000, p3-0.2, 3000)     ;CUTOFF FREQUENCY FOR A LOWPASS FILTER
  anoise = butlp(anoise,kcf)                      ;LOWPASS FILTER THE NOISE SIGNAL
  amix  = ((apitch*aenv1)+(anoise*aenv2))*ilevel*p5 ;MIX AUDIO SIGNALS AND SCALE ACCORDING TO GUI 'Level' CONTROL
  pan_verb_mix(amix, xchan:k("SD.pan", 0.5), xchan:k("SD.rvb", chnget:i("drums.rvb.default")))
endin
/** Open High Hat - From Iain McCurdy's TR-808.csd */
instr OHH ;OPEN HIGH HAT
  idur = xchan("OHH.decay", 1.0)  
  ilevel = xchan("OHH.level", 1) 
  itune = xchan("OHH.tune", 0)
  ioct = octave:i(itune)
  kFrq1 = 296*ioct  ;FREQUENCIES OF THE 6 OSCILLATORS
  kFrq2 = 285*ioct  
  kFrq3 = 365*ioct  
  kFrq4 = 348*ioct  
  kFrq5 = 420*ioct  
  kFrq6 = 835*ioct  
  p3  = 0.5*idur    ;DURATION OF THE NOTE
  
  ;SOUND CONSISTS OF 6 PULSE OSCILLATORS MIXED WITH A NOISE COMPONENT
  ;PITCHED ELEMENT
  aenv  linseg  1,p3-0.05,0.1,0.05,0    ;AMPLITUDE ENVELOPE FOR THE PULSE OSCILLATORS
  ipw = 0.25        ;PULSE WIDTH
  a1  vco2  0.5,kFrq1,2,ipw     ;PULSE OSCILLATORS...
  a2  vco2  0.5,kFrq2,2,ipw
  a3  vco2  0.5,kFrq3,2,ipw
  a4  vco2  0.5,kFrq4,2,ipw
  a5  vco2  0.5,kFrq5,2,ipw
  a6  vco2  0.5,kFrq6,2,ipw
  amix  sum a1,a2,a3,a4,a5,a6   ;MIX THE PULSE OSCILLATORS
  amix  reson amix,5000*ioct,5000,1 ;BANDPASS FILTER THE MIXTURE
  amix  buthp amix,5000     ;HIGHPASS FILTER THE SOUND...
  amix  buthp amix,5000     ;...AND AGAIN
  amix  = amix*aenv     ;APPLY THE AMPLITUDE ENVELOPE
  
  ;NOISE ELEMENT
  anoise  noise 0.8,0       ;GENERATE SOME WHITE NOISE
  aenv  linseg  1,p3-0.05,0.1,0.05,0    ;CREATE AN AMPLITUDE ENVELOPE
  kcf expseg  20000,0.7,9000,p3-0.1,9000  ;CREATE A CUTOFF FREQ. ENVELOPE
  anoise  butlp anoise,kcf      ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,8000     ;HIGHPASS FILTER THE NOISE SIGNAL
  anoise  = anoise*aenv     ;APPLY THE AMPLITUDE ENVELOPE
  
  ;MIX PULSE OSCILLATOR AND NOISE COMPONENTS
  amix  = (amix+anoise)*ilevel*p5*0.55
  pan_verb_mix(amix, xchan:k("OHH.pan", 0.5), xchan:k("OHH.rvb", chnget:i("drums.rvb.default")))
endin
/** Closed High Hat - From Iain McCurdy's TR-808.csd */
instr CHH ;CLOSED HIGH HAT
  idur = xchan("CHH.decay", 1.0)  
  ilevel = xchan("CHH.level", 1) 
  itune = xchan("CHH.tune", 0)
  ioct = octave:i(itune)
  kFrq1 = 296*ioct  ;FREQUENCIES OF THE 6 OSCILLATORS
  kFrq2 = 285*ioct  
  kFrq3 = 365*ioct  
  kFrq4 = 348*ioct  
  kFrq5 = 420*ioct  
  kFrq6 = 835*ioct  
  idur  = 0.088*idur    ;DURATION OF THE NOTE
  p3  limit idur,0.1,10   ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)
  iohh = nstrnum("OHH")
  iactive = active(iohh)      ;SENSE ACTIVITY OF PREVIOUS INSTRUMENT (OPEN HIGH HAT) 
  if iactive>0 then     ;IF 'OPEN HIGH HAT' IS ACTIVE...
   turnoff2 iohh,0,0    ;TURN IT OFF (CLOSED HIGH HAT TAKES PRESIDENCE)
  endif
  ;PITCHED ELEMENT
  aenv  expsega 1,idur,0.001,1,0.001    ;AMPLITUDE ENVELOPE FOR THE PULSE OSCILLATORS
  ipw = 0.25        ;PULSE WIDTH
  a1  vco2  0.5,kFrq1,2,ipw     ;PULSE OSCILLATORS...     
  a2  vco2  0.5,kFrq2,2,ipw
  a3  vco2  0.5,kFrq3,2,ipw
  a4  vco2  0.5,kFrq4,2,ipw
  a5  vco2  0.5,kFrq5,2,ipw
  a6  vco2  0.5,kFrq6,2,ipw
  amix  sum a1,a2,a3,a4,a5,a6   ;MIX THE PULSE OSCILLATORS
  amix  reson amix,5000*ioct,5000,1 ;BANDPASS FILTER THE MIXTURE
  amix  buthp amix,5000     ;HIGHPASS FILTER THE SOUND...
  amix  buthp amix,5000     ;...AND AGAIN
  amix  = amix*aenv     ;APPLY THE AMPLITUDE ENVELOPE
  
  ;NOISE ELEMENT
  anoise  noise 0.8,0       ;GENERATE SOME WHITE NOISE
  aenv  expsega 1,idur,0.001,1,0.001    ;CREATE AN AMPLITUDE ENVELOPE
  kcf expseg  20000,0.7,9000,idur-0.1,9000  ;CREATE A CUTOFF FREQ. ENVELOPE
  anoise  butlp anoise,kcf      ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,8000     ;HIGHPASS FILTER THE NOISE SIGNAL
  anoise  = anoise*aenv     ;APPLY THE AMPLITUDE ENVELOPE
  
  ;MIX PULSE OSCILLATOR AND NOISE COMPONENTS
  amix  = (amix+anoise)*ilevel*p5*0.55
  pan_verb_mix(amix, xchan:k("CHH.pan", 0.5), xchan:k("CHH.rvb", chnget:i("drums.rvb.default")))
endin
/** High Tom - From Iain McCurdy's TR-808.csd */
instr HiTom ;HIGH TOM
  idur = xchan("HiTom.decay", 1.0)  
  ilevel = xchan("HiTom.level", 1) 
  itune = xchan("HiTom.tune", 0)
  ioct = octave:i(itune)
  ifrq      = 200 * ioct  ;FREQUENCY
  p3      = 0.5 * idur      ;DURATION OF THIS NOTE
  ;SINE TONE SIGNAL
  aAmpEnv transeg 1,p3,-10,0.001        ;AMPLITUDE ENVELOPE FOR SINE TONE SIGNAL
  afmod expsega 5,0.125/ifrq,1,1,1      ;FREQUENCY MODULATION ENVELOPE. GIVES THE TONE MORE OF AN ATTACK.
  asig  oscili  -aAmpEnv*0.6,ifrq*afmod,gi_808_sine   ;SINE TONE SIGNAL
  ;NOISE SIGNAL
  aEnvNse transeg 1,p3,-6,0.001       ;AMPLITUDE ENVELOPE FOR NOISE SIGNAL
  anoise  dust2 0.4, 8000       ;GENERATE NOISE SIGNAL
  anoise  reson anoise,400*ioct,800,1 ;BANDPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,100*ioct   ;HIGHPASS FILTER THE NOSIE SIGNAL
  anoise  butlp anoise,1000*ioct    ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  = anoise * aEnvNse      ;SCALE NOISE SIGNAL WITH AMPLITUDE ENVELOPE
  
  ;MIX THE TWO SOUND COMPONENTS
  amix  = (asig + anoise)*ilevel*p5
  pan_verb_mix(amix, xchan:k("HiTom.pan", 0.5), xchan:k("HiTom.rvb", chnget:i("drums.rvb.default")))
endin
/** Mid Tom - From Iain McCurdy's TR-808.csd */
instr MidTom ;MID TOM
  idur = xchan("MidTom.decay", 1.0) 
  ilevel = xchan("MidTom.level", 1) 
  itune = xchan("MidTom.tune", 0)
  ioct = octave:i(itune)
  ifrq      = 133*ioct    ;FREQUENCY
  p3      = 0.6 * idur      ;DURATION OF THIS NOTE
  ;SINE TONE SIGNAL
  aAmpEnv transeg 1,p3,-10,0.001        ;AMPLITUDE ENVELOPE FOR SINE TONE SIGNAL
  afmod expsega 5,0.125/ifrq,1,1,1      ;FREQUENCY MODULATION ENVELOPE. GIVES THE TONE MORE OF AN ATTACK.
  asig  oscili  -aAmpEnv*0.6,ifrq*afmod,gi_808_sine   ;SINE TONE SIGNAL
  ;NOISE SIGNAL
  aEnvNse transeg 1,p3,-6,0.001       ;AMPLITUDE ENVELOPE FOR NOISE SIGNAL
  anoise  dust2 0.4, 8000       ;GENERATE NOISE SIGNAL
  anoise  reson anoise, 400*ioct,800,1  ;BANDPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,100*ioct   ;HIGHPASS FILTER THE NOSIE SIGNAL
  anoise  butlp anoise,600*ioct   ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  = anoise * aEnvNse      ;SCALE NOISE SIGNAL WITH AMPLITUDE ENVELOPE
  
  ;MIX THE TWO SOUND COMPONENTS
  amix  = (asig + anoise)*ilevel*p5
  pan_verb_mix(amix, xchan:k("MidTom.pan", 0.5), xchan:k("MidTom.rvb", chnget:i("drums.rvb.default")))
endin
/** Low Tom - From Iain McCurdy's TR-808.csd */
instr LowTom  ;LOW TOM
  idur = xchan("LowTom.decay", 1.0) 
  ilevel = xchan("LowTom.level", 1) 
  itune = xchan("LowTom.tune", 0)
  ioct = octave:i(itune)
  ifrq      = 90 * ioct ;FREQUENCY
  p3    = 0.7*idur    ;DURATION OF THIS NOTE
  ;SINE TONE SIGNAL
  aAmpEnv transeg 1,p3,-10,0.001        ;AMPLITUDE ENVELOPE FOR SINE TONE SIGNAL
  afmod expsega 5,0.125/ifrq,1,1,1      ;FREQUENCY MODULATION ENVELOPE. GIVES THE TONE MORE OF AN ATTACK.
  asig  oscili  -aAmpEnv*0.6,ifrq*afmod,gi_808_sine   ;SINE TONE SIGNAL
  ;NOISE SIGNAL
  aEnvNse transeg 1,p3,-6,0.001       ;AMPLITUDE ENVELOPE FOR NOISE SIGNAL
  anoise  dust2 0.4, 8000       ;GENERATE NOISE SIGNAL
  anoise  reson anoise,40*ioct,800,1    ;BANDPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,100*ioct   ;HIGHPASS FILTER THE NOSIE SIGNAL
  anoise  butlp anoise,600*ioct   ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  = anoise * aEnvNse      ;SCALE NOISE SIGNAL WITH AMPLITUDE ENVELOPE
  
  ;MIX THE TWO SOUND COMPONENTS
  amix  = (asig + anoise)*ilevel*p5
  pan_verb_mix(amix, xchan:k("LowTom.pan", 0.5), xchan:k("LowTom.rvb", chnget:i("drums.rvb.default")))
endin
/** Cymbal - From Iain McCurdy's TR-808.csd */
instr Cymbal  ;CYMBAL
  idur = xchan("Cymbal.decay", 1.0) 
  ilevel = xchan("Cymbal.level", 1) 
  itune = xchan("Cymbal.tune", 0)
  ioct = octave:i(itune)
  iFrq1 = 296*ioct  ;FREQUENCIES OF THE 6 OSCILLATORS
  iFrq2 = 285*ioct
  iFrq3 = 365*ioct
  iFrq4 = 348*ioct     
  iFrq5 = 420*ioct
  iFrq6 = 835*ioct
  p3  = 2*idur  ;DURATION OF THE NOTE
  ;SOUND CONSISTS OF 6 PULSE OSCILLATORS MIXED WITH A NOISE COMPONENT
  ;PITCHED ELEMENT
  aenv  expon 1,p3,0.0001   ;AMPLITUDE ENVELOPE FOR THE PULSE OSCILLATORS 
  ipw = 0.25      ;PULSE WIDTH      
  a1  vco2  0.5,iFrq1,2,ipw   ;PULSE OSCILLATORS...  
  a2  vco2  0.5,iFrq2,2,ipw
  a3  vco2  0.5,iFrq3,2,ipw
  a4  vco2  0.5,iFrq4,2,ipw
  a5  vco2  0.5,iFrq5,2,ipw 
  a6  vco2  0.5,iFrq6,2,ipw
  amix  sum a1,a2,a3,a4,a5,a6   ;MIX THE PULSE OSCILLATORS
  amix  reson amix,5000 * ioct,5000,1 ;BANDPASS FILTER THE MIXTURE
  amix  buthp amix,10000      ;HIGHPASS FILTER THE SOUND
  amix  butlp amix,12000      ;LOWPASS FILTER THE SOUND...
  amix  butlp amix,12000      ;AND AGAIN...
  amix  = amix*aenv     ;APPLY THE AMPLITUDE ENVELOPE
  
  ;NOISE ELEMENT
  anoise  noise 0.8,0       ;GENERATE SOME WHITE NOISE
  aenv  expsega 1,0.3,0.07,p3-0.1,0.00001 ;CREATE AN AMPLITUDE ENVELOPE
  kcf expseg  14000,0.7,7000,p3-0.1,5000  ;CREATE A CUTOFF FREQ. ENVELOPE
  anoise  butlp anoise,kcf      ;LOWPASS FILTER THE NOISE SIGNAL
  anoise  buthp anoise,8000     ;HIGHPASS FILTER THE NOISE SIGNAL
  anoise  = anoise*aenv     ;APPLY THE AMPLITUDE ENVELOPE            
  ;MIX PULSE OSCILLATOR AND NOISE COMPONENTS
  amix  = (amix+anoise)*ilevel*p5*0.85
  pan_verb_mix(amix, xchan:k("Cymbal.pan", 0.5), xchan:k("Cymbal.rvb", chnget:i("drums.rvb.default")))
endin
;WAVEFORM FOR TR808 RIMSHOT
giTR808RimShot  ftgen 0,0,1024,10, 0.971,0.269,0.041,0.054,0.011,0.013,0.08,0.0065,0.005,0.004,0.003,0.003,0.002,0.002,0.002,0.002,0.002,0.001,0.001,0.001,0.001,0.001,0.002,0.001,0.001  
/** Rimshot - From Iain McCurdy's TR-808.csd */
instr Rimshot ;RIM SHOT
  idur = xchan("Rimshot.decay", 1.0)  
  ilevel = xchan("Rimshot.level", 1) 
  itune = xchan("Rimshot.tune", 0)
  idur  = 0.027*idur    ;NOTE DURATION
  p3  limit idur,0.1,10     ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)
  ;RING
  aenv1 expsega 1,idur,0.001,1,0.001    ;AMPLITUDE ENVELOPE FOR SUSTAIN ELEMENT OF SOUND
  ifrq1 = 1700*octave(itune)    ;FREQUENCY OF SUSTAIN ELEMENT OF SOUND
  aring oscili  1,ifrq1,giTR808RimShot,0    ;CREATE SUSTAIN ELEMENT OF SOUND  
  aring butbp aring,ifrq1,ifrq1*8 
  aring = aring*(aenv1-0.001)*0.5     ;APPLY AMPLITUDE ENVELOPE
  ;NOISE
  anoise  noise 1,0         ;CREATE A NOISE SIGNAL
  aenv2 expsega 1, 0.002, 0.8, 0.005, 0.5, idur-0.002-0.005, 0.0001, 1, 0.0001  ;CREATE AMPLITUDE ENVELOPE
  anoise  buthp anoise,800      ;HIGHPASS FILTER THE NOISE SOUND
  kcf expseg  4000,idur,20        ;CUTOFF FREQUENCY FUNCTION FOR LOWPASS FILTER
  anoise  butlp anoise,kcf      ;LOWPASS FILTER THE SOUND
  anoise  = anoise*(aenv2-0.001)  ;APPLY ENVELOPE TO NOISE SIGNAL
  ;MIX
  amix  = (aring+anoise)*ilevel*p5*0.8
  pan_verb_mix(amix, xchan:k("Rimshot.pan", 0.5), xchan:k("Rimshot.rvb", chnget:i("drums.rvb.default")))
endin
/** Claves - From Iain McCurdy's TR-808.csd */
instr Claves  
  idur = xchan("Claves.decay", 1.0) 
  ilevel = xchan("Claves.level", 1) 
  itune = xchan("Claves.tune", 0)
  ifrq  = 2500*octave(itune)  ;FREQUENCY OF OSCILLATOR
  idur  = 0.045   * idur    ;DURATION OF THE NOTE
  p3  limit idur,0.1,10     ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)      
  aenv  expsega 1,idur,0.001,1,0.001    ;AMPLITUDE ENVELOPE
  afmod expsega 3,0.00005,1,1,1     ;FREQUENCY MODULATION ENVELOPE. GIVES THE SOUND A LITTLE MORE ATTACK.
  asig  oscili  -(aenv-0.001),ifrq*afmod,gi_808_sine,0  ;AUDIO OSCILLATOR
  asig  = asig * 0.4 * ilevel * p5    ;RESCALE AMPLITUDE
  pan_verb_mix(asig, xchan:k("Claves.pan", 0.5), xchan:k("Claves.rvb", chnget:i("drums.rvb.default")))
endin
/** Cowbell - From Iain McCurdy's TR-808.csd */
instr Cowbell 
  idur = xchan("Cowbell.decay", 1.0)  
  ilevel = xchan("Cowbell.level", 1) 
  itune = xchan("Cowbell.tune", 0)
  ifrq1 = 562 * octave(itune) ;FREQUENCIES OF THE TWO OSCILLATORS
  ifrq2 = 845 * octave(itune) ;
  ipw   = 0.5         ;PULSE WIDTH OF THE OSCILLATOR  
  ishp  = -30   
  idur  = 0.7         ;NOTE DURATION
  p3  = 0.7*idur      ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)
  ishape  = -30       ;SHAPE OF THE CURVES IN THE AMPLITUDE ENVELOPE
  kenv1 transeg 1,p3*0.3,ishape,0.2, p3*0.7,ishape,0.2  ;FIRST AMPLITUDE ENVELOPE - PRINCIPALLY THE ATTACK OF THE NOTE
  kenv2 expon 1,p3,0.0005       ;SECOND AMPLITUDE ENVELOPE - THE SUSTAIN PORTION OF THE NOTE
  kenv  = kenv1*kenv2     ;COMBINE THE TWO ENVELOPES
  itype = 2       ;WAVEFORM FOR VCO2 (2=PULSE)
  a1  vco2  0.65,ifrq1,itype,ipw    ;CREATE THE TWO OSCILLATORS
  a2  vco2  0.65,ifrq2,itype,ipw
  amix  = a1+a2       ;MIX THE TWO OSCILLATORS 
  iLPF2 = 10000       ;LOWPASS FILTER RESTING FREQUENCY
  kcf expseg  12000,0.07,iLPF2,1,iLPF2  ;LOWPASS FILTER CUTOFF FREQUENCY ENVELOPE
  alpf  butlp amix,kcf      ;LOWPASS FILTER THE MIX OF THE TWO OSCILLATORS (CREATE A NEW SIGNAL)
  abpf  reson amix, ifrq2, 25     ;BANDPASS FILTER THE MIX OF THE TWO OSCILLATORS (CREATE A NEW SIGNAL)
  amix  dcblock2  (abpf*0.06*kenv1)+(alpf*0.5)+(amix*0.9) ;MIX ALL SIGNALS AND BLOCK DC OFFSET
  amix  buthp amix,700      ;HIGHPASS FILTER THE MIX OF ALL SIGNALS
  amix  = amix * 0.07 * kenv * p5 * ilevel  ;RESCALE AMPLITUDE
  pan_verb_mix(amix, xchan:k("Cowbell.pan", 0.5), xchan:k("Cowbell.rvb", chnget:i("drums.rvb.default")))
endin
/** Maraca - from Iain McCurdy's TR-808.csd */ 
instr Maraca  ;MARACA
  idur = xchan("Maraca.decay", 1.0) 
  ilevel = xchan("Maraca.level", 1) 
  itune = xchan("Maraca.tune", 0)
  ioct = octave:i(itune)
  idur  = 0.07*idur       ;DURATION 3
  p3  limit idur,0.1,10       ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)
  iHPF  limit 6000*ioct,20,sr/2 ;HIGHPASS FILTER FREQUENCY  
  iLPF  limit 12000*ioct,20,sr/3  ;LOWPASS FILTER FREQUENCY. (LIMIT MAXIMUM TO PREVENT OUT OF RANGE VALUES)
  ;AMPLITUDE ENVELOPE
  iBP1  = 0.4         ;BREAK-POINT 1
  iDur1 = 0.014*idur      ;DURATION 1
  iBP2  = 1         ;BREAKPOINT 2
  iDur2 = 0.01 *idur      ;DURATION 2
  iBP3  = 0.05          ;BREAKPOINT 3
  p3  limit idur,0.1,10       ;LIMIT THE MINIMUM DURATION OF THE NOTE (VERY SHORT NOTES CAN RESULT IN THE INDICATOR LIGHT ON-OFF NOTE BEING TO0 SHORT)
  aenv  expsega iBP1,iDur1,iBP2,iDur2,iBP3    ;CREATE AMPLITUDE ENVELOPE
  anoise  noise 0.75,0          ;CREATE A NOISE SIGNAL
  anoise  buthp anoise,iHPF       ;HIGHPASS FILTER THE SOUND
  anoise  butlp anoise,iLPF       ;LOWPASS FILTER THE SOUND
  anoise  = anoise*aenv*p5*ilevel ;SCALE THE AMPLITUDE
  pan_verb_mix(anoise, xchan:k("Maraca.pan", 0.5), xchan:k("Maraca.rvb", chnget:i("drums.rvb.default")))
endin
/** High Conga - From Iain McCurdy's TR-808.csd */
instr HiConga ;HIGH CONGA
  idur = xchan("HiConga.decay", 1.0)  
  ilevel = xchan("HiConga.level", 1) 
  itune = xchan("HiConga.tune", 0)
  ioct = octave:i(itune)
  ifrq    = 420*ioct    ;FREQUENCY OF NOTE
  p3    = 0.22*idur     ;DURATION OF NOTE
  aenv  transeg 0.7,1/ifrq,1,1,p3,-6,0.001  ;AMPLITUDE ENVELOPE
  afrq  expsega ifrq*3,0.25/ifrq,ifrq,1,ifrq  ;FREQUENCY ENVELOPE (CREATE A SHARPER ATTACK)
  asig  oscili  -aenv*0.25,afrq,gi_808_sine   ;CREATE THE AUDIO OSCILLATOR
  asig  = asig*p5*ilevel  ;SCALE THE AMPLITUDE
  
  pan_verb_mix(asig, xchan:k("HiConga.pan", 0.5), xchan:k("HiConga.rvb", chnget:i("drums.rvb.default")))
endin
/** Mid Conga - From Iain McCurdy's TR-808.csd */
instr MidConga  ;MID CONGA
  idur = xchan("MidConga.decay", 1.0) 
  ilevel = xchan("MidConga.level", 1) 
  itune = xchan("MidConga.tune", 0)
  ioct = octave:i(itune)
  ifrq    = 310*ioct    ;FREQUENCY OF NOTE
  p3    = 0.33*idur     ;DURATION OF NOTE
  aenv  transeg 0.7,1/ifrq,1,1,p3,-6,0.001  ;AMPLITUDE ENVELOPE 
  afrq  expsega ifrq*3,0.25/ifrq,ifrq,1,ifrq  ;FREQUENCY ENVELOPE (CREATE A SHARPER ATTACK)
  asig  oscili  -aenv*0.25,afrq,gi_808_sine   ;CREATE THE AUDIO OSCILLATOR
  asig  = asig*p5*ilevel    ;SCALE THE AMPLITUDE
  pan_verb_mix(asig, xchan:k("MidConga.pan", 0.5), xchan:k("MidConga.rvb", chnget:i("drums.rvb.default")))
endin
/** Low Conga - From Iain McCurdy's TR-808.csd */
instr LowConga  ;LOW CONGA
  idur = xchan("LowConga.decay", 1.0) 
  ilevel = xchan("LowConga.level", 1) 
  itune = xchan("LowConga.tune", 0)
  ioct = octave:i(itune)
  ifrq    = 227*ioct    ;FREQUENCY OF NOTE
  p3    = 0.41*idur     ;DURATION OF NOTE   
  aenv  transeg 0.7,1/ifrq,1,1,p3,-6,0.001  ;AMPLITUDE ENVELOPE 
  afrq  expsega ifrq*3,0.25/ifrq,ifrq,1,ifrq  ;FREQUENCY ENVELOPE (CREATE A SHARPER ATTACK)
  asig  oscili  -aenv*0.25,afrq,gi_808_sine   ;CREATE THE AUDIO OSCILLATOR
  asig  = asig*p5*ilevel  ;SCALE THE AMPLITUDE
  pan_verb_mix(asig, xchan:k("LowConga.pan", 0.5), xchan:k("LowConga.rvb", chnget:i("drums.rvb.default")))
endin
;; INITIALIZATION OF SYSTEM
start("Clock")
No comments yet.