   ADLS            0  8                    VCO Sync      # VCO Sync Collection

## HardSync VCO

A basic hard sync VCO in which the synced waveform is reset by the syncing oscillator. A bipolar VCA briefly inverts the signal at the sync point in order to reduce transient noise. (This reduction can be internally adjusted according to ones own tastes.)

## DoubleHardSync VCO

A dual hard sync VCO in which the synced waveform is reset by the syncing oscillator. A bipolar VCA briefly inverts the signal at the sync point in order to reduce transient noise. The second hard sync VCO can run independently, parallel to the first, or can be (double)synced from the already synced first VCO. A crossfader adjusts the mix between the two.

## SubSync VCO
### A Subharmonic SoftSync VCO

A soft-sync VCO in which the synced waveform is reversed following trigger points derived from both the syncing and synced oscillators. This results in a form of soft sync in which the nodes of a subharmonic series (in relation to the syncing oscillator) are brought into focus without the root syncing pitch being present (as is the case with regular hard and soft forms of syncing). 
Since the ‘root’ isn’t directly present in the sound a second oscillator, which can set to different octaves within the sync range, can be mixed in to fill out its place.  


## SoftSync VCO

A basic soft-sync VCO in which the synced waveform changes direction whenever the syncing waveform falls below zero. The synced oscillator can also be reset at the point of reversal, i.e. hard soft-synced.    
             VCO Sync    
  l  P  ,                |  h  T  @  0                        |  l  \  L  8  (                    t  d  T  @  0                        t  d  T  D  4  $                  p  \  H  4                     t  `  P  @  0                       t  d  T  D  4  $                    |  l  X  H  8  (                    |  l  \  L  8                  l  X  D  0                  |  h  T  @  ,                      t  d  P  <  ,                      p  `  P  @  0                      p  \  L  <  (                    |  l  \  L  8  (                    x  h  X  D  4                        t  d  T  D  4                       t  d  P  @  0                       p  `  P  @  ,                      t  `  L  <  ,                      p  `  P  <  (                      l  \  L  <  ,                      l  \  H  8  (                    |  l  \  H  8  $                    |  h  X  H  4  $                     p  `  L  <  ,                      |  l  \  L  <  ,                      t  d  T  D  4  $                    x  d  P  <  (                     |  l  \  L  <  ,                      p  `  L  <  ,                      l  \  L  <  (                      p  \  H  8  (                    |  l  \  L  8  $                    |  h  X  H  8  (                     |  h  X  D  4  $                    x  h  X  D  4              ̿          t  d  T  D  4           ܾ  ̾          t  d  P  @  0           ؽ  Ƚ          x  h  X  H  8  (          ؼ  ļ          l  \  L  8  (          л          x  h  T  @  0            ܺ  ̺          x  h  X  H  8  (          ع  ȹ        |  h  T  @  ,        ܸ  ȸ        t  \  D  ,        ̷        l  \  L  <  ,          ܶ  ̶          |  l  \  L  <  ,          ܵ  ̵          |  l  \  L  <  (          Դ  Ĵ          p  \  H  8  $         س  ȳ          x  h  X  H  8  $      ܲ  Ĳ      |  h  T  D  0          ̱        t  \  D  ,        ذ  Ȱ          t  d  P  <  (          Я            l  \  L  <  ,        ܮ  Ȯ          p  `  L  8  (          ح  ȭ          p  \  L  <  ,          ج  Ĭ          p  `  P  <  ,          ԫ  ī        |  l  \  L  <  ,          Ԫ  Ī          l  \  L  <  ,          ԩ  ĩ          p  \  L  <  ,          Ԩ  Ĩ          t  `  L  <  ,          ا  ȧ          x  h  T  D  4  $          Ԧ  Ħ        t  d  T  D  4              ̥          x  h  T  D  0              Ф          |  l  \  L  <  ,        ܣ  ȣ          l  \  L  <  ,          آ  Ȣ          x  h  X  H  4  $         ܡ  ̡          t  d  T  D  4              Р          |  l  X  H  8  (          ԟ  ğ          p  `  P  @  0            ܞ  ̞          |  h  X  H  8  (          ԝ  ĝ          t  d  P  @  0              М          t  d  P  <  ,          ܛ  ̛          t  d  P  @  0           ؚ  Ț          x  h  X  D  4           ؙ  ș          p  \  H  8  (          Ԙ  Ę        x  h  X  D  0          ܗ  ȗ          p  `  L  <  (          Ԗ          x  h  X  D  0            ܕ  ȕ          x  h  X  H  8  (          Ԕ  Ĕ          p  `  P  @  ,          ԓ  ē          p  \  H  8  (          ؒ  Ȓ          x  h  T  D  4  $         ܑ  ̑          x  h  X  H  8  (          А          t  d  T  D  ,          ܏  ̏          x  h  X  H  4  $        ܎  ̎          p  `  P  @  ,          ܍  ̍          x  h  X  H  8  (        ܌  Ȍ          p  `  P  @  0              Ћ            p  `  P  @  0              Њ          |  l  X  D  4  $          ԉ  ĉ          p  `  P  @  ,          ̈          x  h  X  H  4  $           Ї          x  h  X  D  4  $         ܆  Ȇ          p  \  H  4  $           ̅          t  d  T  D  4  $         ܄  Ȅ          l  \  L  <  (          Ѓ          |  l  \  L  <  ,          ܂  ̂          x  h  T  D  0            ܁  ́          x  d  P  <  ,          ؀  Ȁ        |  l  X  H  8  (                    x  `  H  8  (       ~  ~  ~  ~  ~  ~  ~  ~  l~  T~  <~  $~  ~   ~  }  }  }  }  }  }  }  t}  d}  T}  D}  4}  $}  }   }  |  |  |  |  |  |  |  x|  h|  T|  <|  $|  |  {  {  {  {  {  {  {  t{  d{  T{  @{  ,{  {  {  z  z  z  z  z  z  z  z  pz  `z  Pz  @z  0z   z  z  y  y  y  y  y  y  y  xy  dy  Ty  Dy  0y  y  y  x  x  x  x  x  x  |x  dx  Lx  4x  x  x  w  w  w  w  w  w  w  |w  lw  \w  Lw  <w  $w  w  v  v  v  v  v  |v  dv  Pv  <v  $v  v  u  u  u  u  u  u  tu  `u  Lu  8u  $u  u   u  t  t  t  t  t  t  t  pt  `t  Pt  @t  (t  t  s  s  s  s  s  s  s  s  xs  hs  Xs  Hs  8s  (s  s  s  r  r  r  r  r  r  r  r  tr  `r  Pr  @r  ,r  r  r  q  q  q  q  q  q  q  lq  Xq  Dq  0q  q  q  p  p  p  p  p  p  p  p  tp  dp  Tp  Dp  4p  $p  p  o  o  o  o  o  o  o  o  |o  lo  \o  Ho  4o  $o  o  o  n  n  n  n  n  n  n  ln  Xn  Hn  8n  $n  n  m  m  m  m  m  m  m  m  pm  `m  Lm  <m  (m  m   m  l  l  l  l  l  l  l  pl  \l  Ll  <l  (l  l  l  k  k  k  k  k  k  k  |k  lk  Xk  Hk  8k  (k  k  k  j  j  j  j  j  j  j  |j  hj  Tj  Dj  4j  $j  j  j  i  i  i  i  i  i  i  ti  di  Ti  Di  4i  $i  i  i  h  h  h  h  h  h  h  h  ph  `h  Ph  @h  0h   h  h   h  g  g  g  g  g  g  g  pg  `g  Pg  @g  0g  g  g  f  f  f  f  f  f  f  f  xf  hf  Xf  Hf  8f  (f  f  f  e  e  e  e  e  e  e  e  pe  `e  Pe  <e  ,e  e  e  d  d  d  d  d  d  d  d  pd  `d  Pd  @d  0d   d  d   d  c  c  c  c  c  c  c  pc  `c  Pc  @c  0c   c  c  b  b  b  b  b  b  b  b  tb  db  Pb  <b  (b  b  b  a  a  a  a  a  a  a  a  la  \a  La  8a  (a  a  a  `  `  `  `  `  `  `  `  l`  \`  L`  <`  ,`  `  `  _  _  _  _  _  _  _  _  p_  `_  P_  @_  0_  _  _  ^  ^  ^  ^  ^  ^  ^  |^  l^  \^  L^  8^  (^  ^  ^  ]  ]  ]  ]  ]  ]  ]  ]  l]  X]  H]  8]  (]  ]  ]  \  \  \  \  \  \  \  \  p\  `\  P\  @\  0\   \  \  [  [  [  [  [  [  [  [  p[  \[  L[  <[  ,[  [  [  Z  Z  Z  Z  Z  Z  Z  |Z  lZ  \Z  LZ  <Z  $Z  Z  Z  Y  Y  Y  Y  Y  Y  Y  Y  pY  \Y  LY  <Y  ,Y  Y  Y  X  X  X  X  X  X  X  xX  hX  XX  HX  8X  (X  X  X  W  W  W  W  W  W  W  W  pW  `W  PW  @W  0W   W  W  V  V  V  V  V  V  V  V  tV  `V  PV  @V  0V   V  V   V  U  U  U  U  U  U  U  |U  lU  XU  DU  0U  U  U  T  T  T  T  T  T  T  T  xT  hT  XT  HT  8T  $T  T  T  S  S  S  S  S  S  S  S  tS  dS  TS  DS  0S  S  S  R  R  R  R  R  R  R  R  pR  \R  HR  4R   R  R  Q  Q  Q  Q  Q  Q  Q  lQ  \Q  LQ  <Q  ,Q  Q  Q  P  P  P  P  P  P  P  P  |P  lP  XP  HP  8P  $P  P   P  O  O  O  O  O  O  O  tO  dO  TO  @O  0O   O  O  N  N  N  N  N  N  N  N  lN  \N  LN  <N  ,N  N  N  M  M  M  M  M  M  M  M  xM  hM  XM  DM  4M  $M  M  M  L  L  L  L  L  L  L  L  tL  dL  TL  DL  4L   L  L  K  K  K  K  K  K  K  K  tK  dK  TK  @K  ,K  K  K  J  J  J  J  J  J  J  J  pJ  \J  HJ  8J  $J  J  J  I  I  I  I  I  I  I  xI  dI  TI  DI  4I  $I  I  I  H  H  H  H  H  H  H  pH  `H  PH  @H  0H  H  H  G  G  G  G  G  G  G  G  lG  XG  DG  0G   G  G   G  F  F  F  F  F  F  F  pF  `F  PF  @F  0F   F  F  E  E  E  E  E  E  E  E  pE  `E  PE  @E  0E   E  E   E  D  D  D  D  D  D  D  D  pD  `D  PD  @D  0D   D  D   D  C  C  C  C  C  C  C  tC  `C  LC  8C  $C  C  C  B  B  B  B  B  B  |B  hB  XB  HB  4B  $B  B  B  A  A  A  A  A  A  A  xA  hA  XA  HA  8A  (A  A   A  @  @  @  @  @  @  |@  h@  T@  D@  4@   @  @  ?  ?  ?  ?  ?  ?  ?  |?  l?  \?  L?  8?  $?  ?  >  >  >  >  >  >  >  >  l>  \>  L>  8>  (>  >  >  =  =  =  =  =  =  =  |=  l=  \=  L=  <=  ,=  =  =  <  <  <  <  <  <  <  <  p<  `<  P<  @<  0<   <  <  ;  ;  ;  ;  ;  ;  ;  ;  |;  h;  T;  @;  ,;  ;  ;  :  :  :  :  :  :  :  :  x:  h:  X:  H:  4:  $:  :  :  9  9  9  9  9  9  9  9  t9  d9  T9  @9  ,9  9  9  8  8  8  8  8  8  8  8  |8  h8  X8  D8  48  $8  8  8  7  7  7  7  7  7  7  |7  l7  \7  L7  <7  (7  7   7  6  6  6  6  6  6  6  |6  l6  X6  H6  86  (6  6  6  5  5  5  5  5  5  5  5  t5  d5  T5  D5  45  $5  5   5  4  4  4  4  4  4  4  |4  l4  \4  L4  84  (4  4  4  3  3  3  3  3  3  3  3  t3  d3  T3  D3  43   3  3  2  2  2  2  2  2  2  2  t2  d2  P2  @2  02   2  2   2  1  1  1  1  1  1  1  |1  l1  \1  L1  <1  ,1  1  1  0  0  0  0  0  0  0  0  t0  `0  P0  @0  00   0  0   0  /  /  /  /  /  /  /  |/  l/  X/  D/  0/   /  /   /  .  .  .  .  .  .  .  |.  l.  \.  H.  4.  $.  .  .  -  -  -  -  -  -  -  -  ^  8   d Tt s r 8r q Dd d c b b b a 8a ` ` _ (_ ^  \ xY V V ,V |U 4U T T xT 8T O N M tM L tL (L K XK K I I XI H LH H G G 0G F E |E D hD C B @B A A \A A @ @ @@ ? ? \? > > = = \= < < T< < ; ; X; ; : : ,: 9 9 <9 8 8 P8 7 7 h7 07 6 T6 6 5 5 85 4 4  / . x. 8. - , + + 4+ * * <* ) ) ) ( \( ' T' ' & & p& 8&  & % % X%  % $ $ x$ <$  $ # # L# # " " L" " ! <!     h  ,    p ,      D    ` (    l    (  ` $   h (   d $   (   @     0       t   l 4   |   D  d  h 0  |      x <     P    \ $   (       d     \ (   l 4   X       x <   t 4     D    0   X   P    L    h    `   p 0  d (   \ $   x @    8   H   <     4    P    \   `    X    X    ` (   l 4   8   0   t 0   l 0  H    \    l ,   | <   h 0    P    D  Կ  d ,   x  t 0   | 8    H    Ĺ x (   D   , ȶ x ( ܵ  L   h  ̳  Ա      | 0   t  ğ  D  x <    p 8  Ĝ  T  Л  L   \   P  ؘ  H  З  d ,   p $ ̕ t 4  l (   l     t <    H   L  ̏ D   Ď  D    L  ܌  X   ԋ | $    ؉  `  Ј  X $   h 0   T   |   t 8   p 0  Ă  @  Ё  , Ԁ  T   L  ~ ~ H~ ~ } } d} } | | \| | { l{ ,{ z `z $z y y Xy  y x x 8x w w `w $w v v pv 4v u u 8u t t t Ht t s |s 4s r Xr q q xq p p o o Po o n Tn n m m Xm m l l <l  l k k Hk k j Xj j ^ ^ ] |] <] \ 0\ 0[ V U U @U R lI H pH H G \G G F xF lE ? P> = = < D< ; 2 2 d2 $2 1 1 0 0 / / 8/ . . d. $. - h-  - h, ,, + |+ (+ * |* $* ) ) H) ( `( (( ' ' h' (' & & h& & % % X% % $ $ `$ # # d# (# " " X" " ! ! L!     ,    h ( p    L     p 4 \   ` (    t   H    L    L   T       H  d $  l ,   p  ,   $   <   \     p 0  p   | 4  x @   H       @   L   d ,  t 4   @   h     @   P   T   \    ,   T   `    x @   H   T   |    T   d   h   p 0   @    h   t      \   l   x 8   X   `    l ,   L   l $     8   L   D   L   d     \    4  (    ܼ  h   \   <   8   l $   `  ض  <     Ĵ x $   D   Ա | D   t 4 ܯ  d    @    8 d $  | D   ܡ   T  ԟ   ܞ  8   d , Ԝ  \  ؛ p 0   t 4  \  ܉  4   t  ć    l   t <   L  ̃  $   d   t   x (   @  ~ P~ ~ } x} } | | D| { { d{ { z lz ,z y xy 0y x x 8x w w xw w v v 0v u u @u t 8t s s Ps s r lr r q q @q p p Xp p o lo n ln m m dl k |k 0k  k dj i i di h h Ph g g <g f f hf  f e d d @d c c `c c b <b  b a xa 4a ` h` ,` _ _ `_ $_ ^ l^ ,^ ] ] |] L] \ \ H\ [ |[ @[ Z Z tZ <Z Y Y XY Y X X LX W W |W $W V V 8V U U PU U T T @T  T S HS S R R HR Q Q LQ Q P DP P O LO O N N LN M tM 4M L L 4L K K DK J J HJ I I `I I HH H dG ,G F F `F $F E E LE E D dD (D C C dC $C B B dB ,B A A A @A @ @ L@ ? ? t? > < ; ; L; : : X: : 9 7 6 |6 D6 6 5 5 5 4 l4  4 3 3 83 2 2 2  1 0 |0 40 / / @/ . . \. - - x- 0- , , X,  , + + x+ + * p* ,* ) ) h) ,) ( ( L( ( ' h' (' & & 8& % % `% % $ d$ $ # x#  # " " l" " ! t! 4!       T    P   h 0     t (   D    T    t 8      
 
 \
  
 	 D	   l (   l    P   p 4   `    D       t 8         4 ,   t 4  x @    T    d $   X   t 4   h    <    L |     P    @  \      X  H    4  4   t (   h ,   \ H   D       X   d     l   d     \     0   p    H   h   ȷ  Զ  0   @      P  Ԥ     X   h   8x    | $  | (  t   P  P H   L  H   P    D   T  <Z Y TY Y X X dX (X W W dW V dV V U U HU U T T PT T S S lS 4S R R \R R LQ Q P P dP P O O \O  O N hN 0N M M lM M L HL K K \K tD 8D C C < < : 9 9 D9  | 8  P   X  `    L    \     H    \ D   \ $   d  Կ  ܾ `   n hn n i Pi i `\ \ 8[ W W <W V V pV 4V U U T P O $O N N lN M M 0M L L LL L K K @K J J 0J XI  I H H XH  H G G TG G F F \F F E 8E D D <D  D C C XC  C B  B A A XA A @ H@ ? 4? > > $> = = H= = < T< < ; ; : : 0: L, + ) ( ( `( (( ' ' d'  ' & & l& ,& % P% % $ $ p$ 4$ # # |# $# " " h" 0" ! ! ! H! !     T   T    h ,      @      `   H    ,   p P   @  $   D    D    x @   P    \   X  P
  
 	 x	 $	   p 0   ` x 8   h     T      8   h ,   \      ` (   l (  \   d   h   p 4  T    0   H   x <   X      <      <   @    x <   D        `        D   d   p   L     p 4   <    X    $   <   D   p 0   P       X    T    H   d $   P   p    <    p 0   \    x 8    D   l   p 4  x <   X   | 4  ظ  D  ķ  X   H    8   X   t <   \   p (   d  ĩ  H   h    l , Ԧ x 4 ܥ  P < <   С  0   l $ x ,   H   d ` d d  ܗ  H    d Е  P   H  ̓  D   h 0   \ $   \    | 8   X  ԍ  0   l   ܋  < Ԋ  \   H  Ȉ  @  ȇ p 4   h ( } } d} | | P| | { L{ { z z Hz z y ly 4y x x `x (x w w `w $w v Hv v u u Xu u t pt 4t s s hs s r r Hr q q |q  q p xp @p o o ,o n n hn $n m m Lm m l xl <l k k pk ,k j i i Hi i h h Hh h g g Hg Ld d c lc $c a D`  ` _ _ D_ ^ ^ ^ L^ ^ ] ] L] ] \ \ L\ \ [ [ L[ [ Z Z PZ Z Y Y PY Y X X LX X W W DW W V S S R R dR Q Q Q P P \P P O lO 4O N N PN N M M (M L L ,L K lK ,K J J pJ ,J I I (I H H TH H G XG F LF E E dE  E D D XD D C tC ,C B B HB A A LA A @ @ <@ ? ? X? ? > \> > = = L= = < h< < ; l; ,; : : \: : 9 x9 ,9 8 |8 <8 8 7 l7 (7 6 6 <6 5 5 L5 5 ,3 2 2 P2 2 1 d1 0 0 t0 <0 / / `/ / . t. . - - L- , , p, ,, + + + * * \*  * ) H) ( ( 4( ' ' \'  ' & & h& ,& % % t% $ D$ # h# (#  \    x 0   t     h 0   ,   l 4    D     D   0   d ,    H     8   @    `   x ,   t <    @    H  p
 ,
 	 	 	 L	 	   X     X     p 4   |   @   ` $   ` (   T        t  0    X      \  $      `  $      p  0      d  $    |  h         @      `      L       H        D      h  0      \  $      \       D        T      l  0      d        D      x      t  <      (      d         H      t  (      P        ,      \    d  $      T        ,      l        D    p  0      ,      l  (      L        @        @      (      h  8      P    о    H      l  (  ܼ    \       X     غ  t    й    H    ȸ    ,      X    ض    X    Ե    4          @     Ȳ    4    `     ԰      د    \        <    ĭ    0      t  0        ت    X  (      @        8  ܧ    \    ̦    L      H    Ȥ  d      |  8      |        H      x     ԟ    P      T    ̝    T    ̜    P      l      P      P      h  0      4      t    ȕ    H      <      D    Ē  h  (          r]  [  r]  Y  r\  ]  rY    rY    rW    rV  
     rS  =  rR  M  sR  ;  sQ  T  sQ  R     sP  N     >sM  P  JsM  N  VsI  J  LsG  E     rsD  G  ~sD  E  sB  A  sA  9  s@  B  s>  Q  s>  I  s>  @  s=  D  s=  B     s;  7     s:  9     t:  8  t9  R  t8  9     6t7  5  Bt6  7  Nt5  '  Zt4  2  ft3  4  rt2  3
  ~t1  /  t0  1  t/  7  t-    t+  -  t+  ,  t)       t'  )  t'  (  t%  $  t$    u$  
  u"     u!    u        $u       Ju    Vu    bu    nu    zu    u     u    u    u  
  u    u    u    u  
  u    u	       v    v    v    &v    2v  
  (v   $     Nv
    Zv
  
  fv
  
  rv
  
  ~v
  
  v
  
  v
  
  v
  
  v
  
     v
  
     v
  
     v
  
     v
  
  v
  
  w
  #  w
    w
    *w
  F  6w
    Bw
  	  Nw
  
  Zw
  	  fw
  
  rw
  	  ~w
    w
    w
       w
    w
  
     w
  
  w
  
  w
  
  w
  
  w
  W  w
  
  
x
  
  x
  
  "x
  
  .x
  
  $x
  
     4x
  
     Zx
  
  fx
  
  rx
  
  ~x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
  x
  
     y
  
  y
  
  *y
  
  6y
  
  By
  
  8y
  
     ^y
  
  jy
  
  vy
  
  y
  
  y
  
  y
  
  y
  
  y
  
  y
  
     y
  
     y
  
     y
  
     y
  
  
z
  
  z
  
  "z
  
  .z
  
  :z
  
  Fz
  
  Rz
  
  ^z
  
  jz
  
  vz
  
  z
     
     z
  
  z
  
  z
  
  z
  
  z
  	     z
  	  z
  	     z
  
  z
  	  
{
  	  {
  ?
  "{
  	  .{
  	  :{
  
  F{
  a
  R{
  K
  ^{
  }
  j{~
  |
  `{}
  y
     p{|
  y
     {{
  e
  {z
  y
  {y
  {
  {u
  v
  {r
  p
  {q
  ]
  {p
  q
  {o
  n
  {n
  Q
  |m
  o
  |k
  j
  |j
  i
  &|i
  R
  2|h
  k
  (|f
  d
     N|e
  d
  Z|d
  m
  f|d
  h
  r|a
  b
  ~|^
  O
  t|]
  
     |\
  r
  |[
  X
  |Z
  [
  |X
  \
  |W
  Z
  |W
  S
  |V
  W
  |T
  P
  |S
  X
     |R
  S
     }Q
  P
     }P
  X
     :}O
  V
  F}O
  T
  R}M
  
  ^}M
  ^
  j}L
  z
  v}K
  	  }J
  u
  }J
  f
  }H
  
     }H
  	  }G
  H
  }C
  D
  }@
  	  }?
  	  };
  7
  };
  0
  }:
  ;
  
~8
  :
   ~6
  ;
     ~5
  6
     6~4
  
  ,~3
  0
     R~2
  4
  ^~1
  6
  j~0
  2
  v~.
  ,
  ~.
  *
  ~-
  .
  ~*
  
  ~*
  	  ~)
  G
  ~%
  5
  ~$
  %
  ~ 
  
     ~
  
     ~
  
     
  
  
  $
  
  #
  *
  
  6
  
  B
  
  8
  
     ^
  	  j
  
  `
  
     
     
  
     
  
     
  
  
  
   
  
  
  
  
  
  
     
  
     
  
      
  
     &
  
  2

  
  >	
  

  J
  
  V
  	  b
  3  n
  
  d 
  	     	     
  	     	  	     
  ʇ	     	  ڇ	     	  ڀ	  
  	  	  ܀	  	     	  	     	  	     	  	     	  
     ,	  
     <	  
     b	  
  n	  	  d	  3     t	  2     	  	  	  	  	  
  	  	  ʁ	  	  ց	  	  	  
  	  	  	  @
     	  	     	  	     *	  C
  6	  	  B	  	  N	  	  Z	  	  P	  	     v	  	  	  	  x	  4     	  	  	  	     ʉ	     	  ډ	     	  	     	  	     	  
	     	  
	  	  	  	  	  	     	  	     ,	  	     <	  	     L	  	     \	  	     l	  	     	  	  	  	  	  @
  	  	  	  	  ΃	  
  ڃ	  )
  	  	  	  	  	  
  
	  
  	  
  "	  
  .	  	  :	  	  F	  	  R	  	  ^	  
  j	  	  v	    	    	    	    	    	  	  	  	  ʄ	  	  ք	  	  	  	  	  +	  	  &	  	  	  	  	  	  	  	  	     $	  	     Z	     	  D	  	     j	  	  v	  	  	  	  	  	  	  	  	  	  	  	     	  	     	     	  ̅	  	     	  	  	  	  
	  	  	  	  "	  	  .	  	  $	  	     4	  	     j	     	  T	  	     z	  	  	  	  	  	  	  	  	  	  	  	  	  	     	  	     	     	  ܆	  	     	  	  	  	  	  	  &	  	  2	  	  >	  	  4	  	     D	  	     j	    `~	  	     |	     z	  z	  w	     y	  	  y	  	  x	  w	  ʇw	  y	  ևw	  x	  v	  u	  ؇u	  	     u	    t	  v	     *r	     p	  p	  m	     :o	  	  Fo	  v	  Rn	  m	  ^m	  o	  jm	  n	  vl	  k	  lk	  	     k	    j	  l	     h	     f	  f	  c	     Έe	  	  ڈe	  l	  d	  c	  c	  e	  c	  d	  
b	  a	  a	  	  a	  	     2a	    (`	  b	     ^^	     \	  H\	  Y	     n[	  	  z[	  b	  Z	  Y	  Y	  [	  Y	  Z	  X	  W	  W	  Q	  V	  T	  ΉU	  S	  ĉT	  P	     ԉS	  P	     R	  *	     R	  )	     Q	  P	  &P	  R	  2M	  *	  >L	  @	  JK	  )	  VJ	  H	  bH	  I	  nE	  >	  zD	  L	  C	  D	  B	  C	  @	  A	  >	  B	  <	  1	  ;	  J	  Ί:	  ;	  ڊ9	  :	  Њ8	  6	     5	  8	  5	  6	  3	  2	  1	  9	  0	  .	     6-	  0	  B-	  .	  N+	  M	  Z+	  -	  f*	  E	  r*	  3	  ~)	  <	  )	  (	  (	  '	  &	  K	  &	  5	  $	  #	  #	  	     "	  	     !	  "	   	  	  	  	     	  	  	  	  &	  	  	  	     ,	  	     R	  	  ^	  	  T	  	     z	  	  	  	  	  	  	       	       	  	  ʌ	  	  	       	    	  	  	  
	  
	       		       *	  		  6	  	  ,	       R	    ^	  	  j	   	  v	     	  j	    t	    k    ,     	    	  ʍ  	  ֍  	    ~	    	        `	    	       	       	     ,  	     <  #	     L  	     \  	     l  
	     |  	       	       	       	       "	     ̎  	     ܎  	       		       	      *    6    B    N    Z    P       `                               Ώ    ڏ                
        "           >    J    V    b    n    d                           Ɛ    Ґ    ސ    Ԑ                            *    6    B    N    Z    f  0  r    ~    t  &                   r  ʑ    ֑    ̑       ܑ                   &           B    N    D       j    v  x                y             Β    ڒ                           &    2    >    J~    V~  z  b}  ~  n{  w  dz       ty  z     x  w     w       v  }  Ɠv  {  t       t    t    s    r    q    q    n  6     $n  5     Jm  j  Vk  2  bk  /  nj  k  ze  b  c    c    c    b  c  `  [  _     \     ֔]  \  \  `  \  ^  \  ]  [    Z       R  *     2Q  O  >Q  M  JP  Q  VP  N  bM  E  XL  Q     hL  N     H  I  F  L  F  H  E  2     B  <     ҕA  :  ޕ?  @  ԕ?  9     <  *     
;  B  :  <  "9  S  9  :     >8  9  J7  8  V4  >  b3  4  n2  1  z1  *  0  
  |0  *     /    /  ?  /  &  Ɩ.  -  +  E     *  :  *  A  (  m  (  .  '    &  6  *&  7   %  $     0%       @#       f"    r!    ~   
  t          #        "    $  ʗ  !  ֗    ̗               
        "           (       N    Z    f    \       l	        |                   Ƙ           ̘          	       
            &    2    >    J    V    b    n    z        |                         Ι    ڙ                
      %  "           >    J    @       f    r    ~                              Κ    ښ    К                         "    .    :    0       @       f    r    ~    t                       ʛ    ֛                                              F    R    ^    j    v              
                 Μ    Ĝ       Ԝ  [               e      *    6    ,  [     R    ^    j  |  v  f                            Ɲ    ҝ    ޝ          x            l  &    2    >    J  m  V    L       r    ~        |  }  y  j  x       w    ʞv  s  ֞u  v  s  w  r  u  r  n  q  r  o  k  n  s     m  n     (l  k     8k  s     ^j  q  jj  o  vh    h  y  g    f    e    e    `  a  ʟ[  ]  [       Z    Y    W  V  
V  
  V  X  "V  W  .U    :U    FT  U  RT  C  ^S  u   jR  Q  `Q  S     P  S  O  J  N  L     N  D     M  L  L  O     ڠK  O  J  G  I  M  I  K  
I  D  G  4   F  K     F  D     BE  N  NC    Z?  ;  f?  4  r>  ?  ~<  >  t:  ?     9  :     8  
  7  4     ơ6  8  ҡ5  :  ޡ4  6  ԡ2  V     -  9  ,  -  (       '       &       B$  #  N#  ,  Z#  +  f#  %  r#  $  ~#    t"  #                      ҩ                           (  
  '    &                ,       <       b    X       ~                	  0    	                                      &       &    2    (       8        H       X       h       x                       Ƥ    Ҥ    ޤ    Ԥ  0       /     
        "  
  .  
  :    F    R    ^    j    v    l       |         [        Z  ƥ  `  ҥ    ޥ                           *    6    ,  1     R    H       ~                                       ʦ           Ц                                            F    R    H       n    z  Y                         Ƨ    ҧ    ާ      T                  &    2    >    J    V    b    n    z    p                                  Ψ    ڨ          ?    |                            0       V    b    ~       h  |     x  |                   ΰ       ް       ީ  }  ,          @          T          h          |                    L       \       Ī          ت                                         (          <          P          d          6    B    N    Z    f    r~    ~~    }  |  {  v  	   y     J     w  v     ʫt  w  ֫t  s  $s     v     8s     v     Ls     v     `s     v     ts     v     s     v     s     v     ns  v  zq  D  pp  B     o  p     n  l  m  n     l  C     Ҭk  m  ެj  `  Ԭi  _     h  _     
g  i  f  h  2e     d  2e  c  (d  ]     Nc  ]  b     d     Xb  c     ~a  j  `  _  _  [  ^  g  ^  f  ^  a  ƭ]  z  ҭ[  8  ޭ[  7  Z  X  Y  i     Y  h     Y  b  Y  `     2Y  ^  >Y  Q  4X  z     DX  j     jX  e  vX  T  lW  R     |V  R     U  R     µT     U  ҵT     W  T     V  T  S  S  R  <Q     U     PQ     W     dQ     V      Q  S     FP  ~  RP  t  ^P  Z  jP  A  vO  P  lN  O     M    M  |     M  {  M  r     ʯL  n  ֯K  J  J  x  J  O  J  M  J  K  J  E  H    *G  H   F  O     0F  E     fE     C  fE  B  rD  p  hC  G     B  G  ܰA          A          A          A       @    @    @  N  
?    ?  Y  "?  !  .=    :=    0<  =     @<  ;     f9  <  r9  :  8          Ա8          8          8    7       ֱ4  5  4  &  2  3  2  $  0  1  0  (  ,  -     .,  )  :+  ,  F*  -  <*  +     b)    X)  |     h)    
   (  +  &  %     %  6  %    $  #     Ҳ#    ޲#    !    !       |        ?       !     2  %  >     J  #  V    L  |     r  k  h    	     	            =  
  |     γ
  o  ĳ
       	    	  
        q       >  *  	  6  (  B    N    Z  -   f  r  r  q  ~  L                         ʴ    ִ          l                    &    2    (       N    Z    f    \       l                             ʵ           е                       &    2    >  z  4       D       j    v    l                 ~         ƶ           ̶       ܶ                                  0       @       f    r    h                          ·    η  i  ķ       Է                       *    6    ,       R    H       n    z                           Ƹ                                           .    :    F    R    ^    j    v    l                       ¹    ι  {  ڹ  x      ܹ       {       z    z    *x  v  6x  u  Bw    8v       ^u    js    vr    r    r  w  q  r  o    l  }  l     ʺk    ֺk  q  i    i  o  e  a  b  e  b  c  a  `  *`  ]  6^  1  B^    N^    Z^    f]  ^  r\  b  ~[  3  X  Y  W  N  V  T     U  T     »T  S  λT  R  ĻS  T     ԻR  6     Q  V     Q  U     P  V  &O  U  2N  T  >K  2  JK    VK    bK    nJ  K  dI       H  I  E  D  D  H  D  /  C  A  ƼA  B  ҼA  @  ޼@  E  Լ?  A     ;  <  9  ?  9  ;  8  I     6  8     >5  [  J5  8  @4  5     f3  W  \2  .     l1  .     0  O  /  .  .  0  '  $     ƽ#  '  ҽ#  $  ޽!       #     !                  *    6     B  	  N  
  Z
    f	                                                                L              *    6    B    N    Z    f    \                                      ڿ    п  t       r                 *  e  6    B  ~  N    Z  X  f  V  r    ~          d            c                                       &    2    >    J    @       P       v    l                                                             *    6  b  B    N    Z    f    r    ~          6            [                              I       8     *    6  5  B    N    D       T       d  4     t                 ,    )           +           (                 *            0       V    b    n  *  z    p                                             4         
            &    2    >    J    V  Z  b  X  X  W     h  3     x         J                     ~    |  {  {  v     z  v      y  v     &x    x  s     Bx  k  Nw  v  Zv  x  ft  i  rs    ~s  t  r    r    r  s  q    q  o     p  o     o    o  n  o  m  n  o     m    m  a  l  q      l  p     Fk    Rk  q  ^j  p  ji    vi  o  g  y  g  _  e  ]  d  w  c       c       b  z  b  `  a    `  \     _  \      ^       &^  j  2]  \  >\  ^  JX  Y  VR  P  bP  Q  nP  O  zO    pN  P     J  K  H  N  H  J  F  D  D  E  D  C  C    B  D     >  ?  <  B  <  >  :  8  *8  9  68  7  B7  7  N7    D6  8     j2  3  v0  6  0  2  .  ,  ,  -  ,  +  +    *  ,     &  '  $  *  $  &  !  "      
        "    .    $       J    V    b    X  
     ~      !    
  
                                       
        "     .    :    F    R    ^    T       z                                                     
               2    (       N    Z    f    r    ~                                                                  :    F    <       L       \       l       |                                                        &    2    >    J    V    b    n    z    p                                                            &    2    (       N    Z    f    r    h       x                                                                :    F    R    ^    j    v        x           }    }    z  x  x  y  x  w  w       v  x     r  s  p  v  p  r  *n  l  6l  m  Bl  k  8k       Hj  l     nf  g  zd  j  d  f  b  `  `  a  `  _  _       ^  `     Z  [  X  ^  X  Z  V  T  T  U  T  S  S       R  T     >N  O  JL  R  VL  N  bJ  H  nH  I  zH  G  pG       F  H     B  C  @  F  @  B  >  <  <  =  <  ;  ;       :  <     6  7  4  :  &4  6  22  0  >0  1  J0  /  @/       P.  0     v*  +  (  .  (  *  %  &  !  "                                               *    6    ,       <       b    X       ~        	  
        	                                              &    2    >    J    V    b    X       h                                                                        .    :    F    R    H       n    z                                                                   *    6    B    N    D       j    v    l                                               $          8          L                 >       N       ^       n       ~                                                            4          H          \          p                    @       f    r    ~                                                                *            0       @       f    r    ~                                                  
        "  V  .    :    F  !  R    ^  %  j    v          Q    p    i                x    t    p         w    s    o  *     6  g  B  T  N  A  Z    f    r     ~  .            ]          \           [          ^     (     U     <     T     P     S     d     V     x     n          m          l          k          d              Q       m       >    
        	   +       f       F  &     3  6        F       V       f       v       v                                    ~    }    {  
  {    z  {     "y  z  .x  {  :w    Fw    <v  w     bu  v  nt  w  zr  l  q  r  p  q  o  q     m  r     l    k  e  j  k  i  j  h  j     f  k     e     a  Z     `  Z     :_  Z  F^  _  R]  a  H\  Z     n[  `  zZ    pY  R     X  R     W  R  V  W  U  Y  T  R     S  X  R    Q  o  Q  h  
P  I  P  6  "P  #  .P    :O    FO    RO    ^O    jK  >  vI  B  I  A  H  D  G  B     G  :  F  :     D     C  G  B  H  A  ;  ?  G     >  ?  <  K  ;  <  :  H     $:  A     J8  +  V6  /  b6  .  n5  1  d4  /     4  '  3  '     1  C  0  4  /  5  .  (  ,  4     +  ,  )  8  (  )  '  5     '  .     *%    6#    B#    N"    D!       j!    `          0    !    "        !           %        "            
      	  "    .    $  	     J    @       f    r
    ~	                                                                *            F     R    ^    j    `                                                        
            &    2    >    J    @       f    r    ~    t                                                            *            F    R    ^    T       d                                                     
            &    2    >    4       D       j    v            u    t    M                         y    x    N  
        "    .    :    F    <       L       \       l       |                                                          "    .    :    F    R    ^    j    v              ~    {                                               &    2    >    J    V    b    n    z                    ~    |    {  |  z  n  y  w     x  z  w  x     v  m  u  s     .t  v  $s  t     Jr  l  @q  o     fp  r  \o  p     n  [  n  U  n       m  ^  m  T  m       l  ]  l  S  l       k  \  k  V  k       "i  \  .g  `  :g  _  Ff  b  <e  `     be  X  Xd  X     ~b  y  a  e  `  f  _  Y  ]  e     \  ]  Z  i  Y  Z  X  f     X  _     V  I  T  M  T  L  &S  O  R  M     BR  E  8Q  E     ^O  u  jN  R  vM  S  L  F  xJ  R     I  J  G  V  F  G  E  S     E  L     C  6  A  :  A  9  @  <  ?  :     "?  2  >  2     ><  q  J;  ?  V:  @  b9  3  X7  ?     ~6  7  4  C  3  4  2  @     2  9     0  #  .  '  .  &  -  )  ,  '     ,    +       )     *(  ,  6'  -  B&     8$  ,     ^#  $  j!  0  v   !  l  -     |  &                                         a  
        "           >    J    V    L       \       
                                        N                              *   
  6      ,        <         b      n      z            |                           ;                                   
                              B      N      Z      f      \               x            (                                                                 "   k           >      4         Z     f      r     ~                                0      q                  ?                        =                  :   >   0         @         P         v                                                x      q      ;               
         I           2      >   2   4         Z      P         v                              x                           }                                 &               ,         <         L   ~      \         l         |                                                                                          B~         R~         b~         r~         ~         ~         ~         ~         ~         ~      |     
     
   ~      {     
     
   ~      z   
}   ~   |      "{      .z      :x      Fu   E  Ru      Ht   b      Xs   P     ~r   R  r   P  q         o   n   n   i   k   m   k   j   j         i      i         i   q      g      g      *g      6e   d   Bd   1   Nc   b   Zb   `   fa   .   r`   _   ~_   a   ^   Z   ]   X   Z      Z      Z   |      Z   Q   Y      Y      Y   z      Y   O   
X      X      X   {      2X   P   >W   T   JW   S   VW   R   LT   Q      \S   O      lR   P      |Q         P         O         N   J   M   I   J         J         J   Q      I         I         I   O      $H         4H         DH   P      TE         dE   Q      tD         D   O      C         C   P      B   E   A   C   @   D   ?   *   >   $   =   %   ;         "9      7   /      >6   7   J4   /   V3      L3   n      r2   &   ~1   '   0   (   /      .   Q     -   F  -   s   ,   t   ,   h   ,   3   *   "      (   "      '   "      &   "   %   "      $$   "      J       V      L         r      ~                                                                                                $
         4
         D
         T
         z   
   p   	                  	                                                     
      
                            p 8 4 ,             $   (                                                                                 p      0   @                 @      D   dD$8CO            count            trigger      ?    -  
local n = 3

local Count = 0
local prevTrig = 0
local loadState = true
local saveState = false

function process(frames)
    if loadState then
        Count = storage[1] or 0
        loadState = false
    end	
		
    if trigger[1] > 0 and prevTrig == 0 then
        Count = (Count + 1) % n  -- Loop counter from 0 to (n-1)
        -- Count = Count % n + 1  -- Loop counter from 1 to n
        saveState = true
    end
    prevTrig = trigger[1]

    fill(count, Count)

    if saveState then
        storage[1] = Count
        saveState = false
    end
end
   .,   ,                   A  pAGLD*C               v<                            A  HBY     D,"CN   b   canvas_height = 30
canvas_width = 50
height = 10
stroke = 0.7
w = 2
waveform = 1
width = 15
x = 3
               waveform        [@   @                 0   0   (&@N  @ C   c  B               \  Y  [  ]  /,   ,                   B  pA}DVrC
               (4   4                 $   $   z?ъC  Cr 0               
  
  V  W  0,   ,                   B  A *  
               T0,   ,                       Aw/  	               (,   ,                 0B   @.D               0   Soft Sync

Double Hard Sync

Sub Sync

Hard Sync    \_$   $                 cD                0(   (                                     x       Dx                4   ;pDz                   k      m          (m/2)/(clamp(k+1,.01,2))    x                (    ;D                 x          abs((x-.5)*2)   1(   (                  AuK                Audio       `4   4                   pXf    C   B               a$   $                   jC                 2,   ,                           XB	               mD   D                 @P 0   0     ?          p   A  {D               M  N  O  P  |4   4                 ` U2    C   B               4b$   $                   jC                 4,   ,                           XB	               8nD   D                 <` 0   0     ?                D                 I  J  K  4(   (                 | AuK                Audio       ܡ4   4                 h  pXf    C   B               c$   $                   jC                 p5,   ,                           XB	               oD   D                 M 0   0     ?            H  DW               D  E  F  G  lf(   (                    .;"D'=               }                T n>EDp                x       P}                (    "D 
                x          (x-.5)*2    <   <                      C(       A     WD                    
Simple Linear
Bipolar VCA  y0   0                 7       C 
	               y0   0                 $       HC	                  MOD 04   4                 $   $   T?dfE _  A               8  9  :  ;  =  >  ?  @  A  B  C  H  L  Q  R  T  P8,   ,                   p   A	D
               z0   0                 0k      A TD @	               (8(   (                    pD                       b      a      x                       tR  TD                  x       i(   (                      f  /C=               i(   (                       /C>                                  J  /C                   k      m       tj(   (                        B=               j(   (                      /  B>               T                       B                   k      m       ,k(   (                    +-ĻB=               dk(   (                      *  B>                               4       B                   k      m          m/(clamp(k+1,.01,2))    34   4                 $   $     ?        ,`Īg               +  ,  -  ;,   ,                   *C  Ad<h
               0q0   0                   C   B   #h               u8   8                       ǣ>  C  A2%n               54   4                 $   $   1S?BDEDrĈ7               '  (  )  =,   ,                   *C  Ad<h
               Hr0   0                   C   B   #h               v8   8                       *
>  C  A2%n               h8   8                   A@ 'BZB   \DK               x8   8                      ?     HB  BYYD9`               n(   (                    obD.>               Z<   <                   A  pA@    @  B    'D  N                Toggle      X>(   (                 t  C                 >(   (                 A  CF               ؁0   0                        p    ,	               0   0                         =A	               X0   0                 ,   C     C  A
               Ę(   (                 , B	               ?(   (                 d   4B  0                       Max    Power      Control     8   8                 x $   $     ?        CC                          4   4                 0   @     瞖CsB               o$   $                   bC  XB               A,   ,                         C  TB	               {D   D                 0 0   0     ?           A   A  0DK                     8   8                 A $   $     ?          D                       0(   (                 D   wD  p	               <0   0                    B      D  p
               lB(   (                 A  D  p                Audio                        B                     Phasor      0   0                 C   C      RC  
               p(   (                 C   !  	               d8   8                 (B $   $     ?        =!D*                     C(   (                 4B SB)A                x       t                DB 勐C<@                x       T0   0                 PB   C      C  @
               (   (                 TB @	               8   8                 B $   $     ?        ߒ!D:                       (0   0                        p C  	               h0   0                          C  ,	               u              C%               L4   4                 DM         C   B               u$   $                 |~jC               F,   ,                         C  TB	               D   D                 lM 0   0     ?          HB   A  rKDk                     Է8   8                 B $   $     ?         D  %            	   
           	  
      (   (                 `F  LD  A	               0   0                 (   hC     D  
               Ԋ0   0                    B     @PD  PA
               H,   ,                   pB      B    
               <w$   $                         	               l8   8                 8E $   $     ?          D  aC               
  
  y(   (                      ,D  p?               I,   ,                   pB      B    
               8x$   $                         	               h8   8                 <D $   $     ?         C  bC               
  
  I(   (                 B ]CcB                Toggle      y$   $                 yC  |L               P0   0                 D       p  !C  	               0   0                 P         C  A	               y$   $                  C  AL               0   0                 B      @=  LC  XC	               ,8   8                 B $   $     ?         aD              
   
  
  
  
  
  
  
  
  
  
  LL,   ,                    A  APD               8   8                    >      A  B  C  O               L,   ,                   HB   AND 
               M,   ,                    A   A2DA+	               B @   @                   B  pBlF $   $     ?        H}               
  
  
  
          !  "  #  $  %  &   F4   4                 $   $     ?        cVzC               
  
  (N,   ,                    B        C
               |$   $                 ]MC	               `                     C                x       0N(   (                 (   DĄOC                x       	   cos(x*pi)   N(   (                 d ֿLC                x       }$   $                 >YʊB               x <   4   ( $                                                                    3       2                        x   8   8                 (   (   yg@ E    ڼfEB               2  V  W  X  
  xP,   ,                   pB  B  
  C
               H4   4                 $   $     ?            C               
  
  
  
  
  Q,   ,                   B  A  H  B
               LQ,   ,                       A    B	               0   0                   pB  pA   v	ö3C               4   4                    3*?   B  Aּ4C               d$   $                     B/               40   0                      pA   A^^               ؂(   (                      z  ?               H8   8                   A+ 'BZB   \DK               X8   8                      ?     HB  BYYD9`               (   (                    obD.>               o<   <                   A  pA+    @  B    'D  N                Toggle      8S(   (                   C                 pS(   (                 ,  CF               0   0                 8       p    ,	               0   0                 @       =A	               80   0                 L   C     C  A
               (   (                 L B	               T(   (                    4B  0                       Max    Power      Control     8   8                  $   $     ?        CC               
  
  
  
  
  4   4                    @     瞖CsB               $   $                   bC  XB               V,   ,                         C  TB	               D   D                  0   0     ?           A   A  0DK               
  
  
  t8   8                 - $   $     ?          D                 
  
  
  (   (                 /   wD  p	               0   0                    B      D  p
               LW(   (                 -  D  p                Audio                        (-                     Phasor      0   0                 .   C      RC  
               P(   (                 .   !  	               D8   8                 H- $   $     ?        =!D*               
  
  
  X(   (                 T- SB)A                x       T                d- 勐C<@                x       40   0                 p-   C      C  @
               (   (                 t- @	               8   8                 - $   $     ?        ߒ!D:               
  
  
  
  0   0                        p C  	               H0   0                          C  ,	                             C%               ,4   4                 d8         C   B               $   $                 |~jC               [,   ,                         C  TB	               D   D                 8 0   0     ?          HB   A  rKDk               
  
  
  8   8                 - $   $     ?         D  %            	   
  
  
  
  
  
  
  
  
  h(   (                 1  LD  A	               t0   0                 H   hC     D  
               0   0                    B     @PD  PA
               ],   ,                   pB      B    
               $   $                         	               L8   8                 X0 $   $     ?          D  aC               
  
  (   (                      ,D  p?               ^,   ,                   pB      B    
               $   $                         	               H8   8                 \/ $   $     ?         C  bC               
  
  ^(   (                 - ]CcB                Toggle      $   $                 yC  |L               00   0                 d       p  !C  	               p0   0                 p         C  A	               $   $                  C  AL               0   0                 -      @=  LC  XC	               8   8                 . $   $     ?         aD              
   
  
  
  
  
  
  
  
  
  
  ,a,   ,                    A  APD               8   8                    0>      A  B  C  O               a,   ,                   HB   AND 
               a,   ,                    A   A2DA+	               . @   @                   B  pB1 $   $     ?          B                 
  
  
  
  
  
  
  
  
  
  
  
  
  
  4   4                 0         C   B               T$   $                 |~jC               0c,   ,                         C  TB	               XD   D                 1 0   0     ?          A  B     p               
  
  
  4   4                 /         C   B               l$   $                 |~jC               Hd,   ,                         C  TB	               pD   D                 0 0   0     ?          B  B                    
  
  
  4   4                 .         C   B               $   $                 |~jC               `e,   ,                         C  TB	               D   D                 . 0   0     ?          A  A  `;B               
  
  
  <   <                    A  A(   dqA}?C   /;:j4N                  label = "s/h"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
    @   @                 0   0   @Dl'C  p  B  QER               
  
  
  
  
  `g,   ,                   B  B  zC  
               X8   8                   A  A     A  Ao؎M               <   <                   A  A8     A  A    B N                switch      F  

if switch > 0 then 
	label = "soft"
	circle_color = theme.azureHighlight
	border_color = theme.grooves
	text_color = theme.azureHighlightBackground
else 
	label = "hard" 
	circle_color = theme.azureHighlightBackground
	border_color = theme.azureHighlight
	text_color = theme.azureHighlight
end

save()
translate{canvas_width/2, canvas_height/2}
stroke_circle( {0,0}, 12, 4, color_paint(border_color))
fill_circle({0,0}, 11.5, color_paint(circle_color))

min, max = text_bounds(label)
scale{.9,.9}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
text(label, text_color)
restore()  i(   (                 \$ .BlG                 x       ܧ0   0                          ԷBT(                ?    p(   (                    ćD??               c4   4                 $   $   b'2@  CL2C               	  
  
  
  
  k,   ,                   B  A  H  B
               k,   ,                       A    B	               0   0                   pB  pA   v	ö3C               84   4                     (?   B  Aּ4C               l(   (                 P2    C                x       Hl(   (                 X[  @  B                x                       (                      x          x/pi-1  8   8                   A$ 'BZB   \DK               8   8                    l=*?     HB  BYYD9`               `(   (                    obD.>               L<   <                   A  pA<    @  B    'D  N                Toggle      m(   (                 h  C                 0n(   (                   CF               x0   0                 x       p    ,	               0   0                        =A	               0   0                    C     C  A
               d(   (                  B	               `o(   (                    4B  0                       Max    Power      Control     8   8                  $   $     ?        CC               y
  z
  {
  |
  }
  4   4                     @     瞖CsB               d$   $                   bC  XB               @q,   ,                         C  TB	               hD   D                  0   0     ?           A   A  0DK               u
  v
  w
  48   8                 H $   $     ?          D                 p
  q
  r
  (   (                     wD  p	               ܴ0   0                    B      D  p
               r(   (                 T  D  p                Audio                       h                     Phasor      0   0                     C      RC  
               (   (                    !  	               8   8                  $   $     ?        =!D*               m
  n
  o
  ds(   (                  SB)A                x                        勐C<@                x       0   0                    C      C  @
               `(   (                  @	               T8   8                  $   $     ?        ߒ!D:               h
  i
  j
  k
  ȷ0   0                 H       p C  	               0   0                 L         C  ,	               h              C%               4   4                          C   B               $   $                 |~jC               v,   ,                         C  TB	               D   D                  0   0     ?          HB   A  rKDk               a
  b
  c
  t8   8                  $   $     ?         D  %            	   N
  ]
  ^
  d
  e
  f
  g
  l
  s
  ((   (                   LD  A	               40   0                 z   hC     D  
               t0   0                    B     @PD  PA
               Hx,   ,                   pB      B    
               ܦ$   $                         	               8   8                  $   $     ?          D  aC               Z
  [
  d(   (                      ,D  p?               Dy,   ,                   pB      B    
               ا$   $                         	               8   8                  $   $     ?         C  bC               V
  W
  dy(   (                  ]CcB                Toggle      $   $                 yC  |L               0   0                        p  !C  	               00   0                          C  A	               \$   $                  C  AL               0   0                       @=  LC  XC	               8   8                 X $   $     ?         aD              
   O
  P
  Q
  R
  S
  T
  U
  X
  Y
  \
  {,   ,                    A  APD               8   8                    >      A  B  C  O               p|,   ,                   HB   AND 
               |,   ,                    A   A2DA+	               T\ @   @                   B  pB $   $     ?          C                 J
  K
  L
  M
  _
  `
  t
  x
  ~
  
  
  
  
  
  |(   (                 ^ i8                x       }(   (                 6 8(                 x       <   <                    A  @   A  +C   !N               04   4                 `         C   B               $   $                 |~jC               ~,   ,                         C  TB	               D   D                  0   0     ?          A   C  p$%vv               C
  D
  E
  p<   <                   A  A(   KAC   (RCN                  rotate(math.pi/2)

label = "soft sync"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
   (   (                 4   qu8)                   k      x          x+ k*3  ,(   (                 (    A                x       ,   ,                 4C, m+C^               ,   ,                 C ؛Tsq               $,   ,                 ̗C [Hd                                ;:                   fs     fc                       oã                fc      ,   ,                 C ).A               (   (                  7M ;               $   $                 OB               L(   (                    Xë >               0   0                          (	               0   0                    B   kDվ
               D(   (                    &B	               <$   $                 XaCF               p$   $                 :<g1               $   $                 9Cj/               8   8                 h  $   $     ?           C               0
  1
  2
  3
  4
  5
  6
  7
  8
  9
  :
  ;
  <
  =
  >
     ,   <                    <   dD$8CO            count            trigger     -  
local n = 4

local Count = 0
local prevTrig = 0
local loadState = true
local saveState = false

function process(frames)
    if loadState then
        Count = storage[1] or 0
        loadState = false
    end	
		
    if trigger[1] > 0 and prevTrig == 0 then
        Count = (Count + 1) % n  -- Loop counter from 0 to (n-1)
        -- Count = Count % n + 1  -- Loop counter from 1 to n
        saveState = true
    end
    prevTrig = trigger[1]

    fill(count, Count)

    if saveState then
        storage[1] = Count
        saveState = false
    end
end
   ,   ,                   A  pAGLD*C               0 8   8                      A  HB4      D,"CN                waveform          azure = color_paint{0,.831,.1,1}
azure_dk = color_paint{0,.608,.729,1}
azure_bkgd = color_paint{0,.059,.078,1}

green = color_paint{.231,.769,.333,1}
green_dk = color_paint{.149,.502,.216,1}
green_bkgd = color_paint{0,.078,.012,1}

red = color_paint{1,0,.384,1}
red_dk = color_paint{.651,.081,.251,1}
red_bkgd = color_paint{.110,0,.043,1}

text_color = color_paint{.839,.839,.839,1}



-- cover trigger node
fill_circle({canvas_width/2, canvas_height/2}, 16, color_paint{.12,.12,.12,1})
fill_rect({0,0}, {50,30}, 8, azure_bkgd)


function sine(width, height, stroke, paint)
	stroke_bezier({0,0},{0,height/2},{width*.25,height/2},stroke,paint)
	stroke_bezier({width*.25,height/2},{width*.5,height/2},{width*.5,0},stroke,paint)
	stroke_bezier({width*.5,0},{width*.5,-height/2},{width*.75,-height/2},stroke,paint)
	stroke_bezier({width*.75,-height/2},{width,-height/2},{width,0},stroke,paint)
end

function triangle(width, height, stroke, paint)
	stroke_bezier({0,-height/2},{width*.25,-.01},{width*.5,height/2},stroke,paint)
	stroke_bezier({width*.5,height/2},{width*.75,-.01},{width,-height/2},stroke,paint)
end

function square(width, height, stroke, paint)
	stroke_bezier({0,0},{0,height/2},{width*.2,height/2},stroke,paint)
	stroke_bezier({width*.2,height/2},{width*.53,height/1.8},{width*.5,0},stroke,paint)
	stroke_bezier({width*.5,0},{width*.47,-height/2},{width*.75,-height/2},stroke,paint)
	stroke_bezier({width*.8,-height/2},{width,-height/2},{width,0},stroke,paint)
	end
	
function tanh(width, height, stroke, paint)
	stroke_bezier({0,0},{0.01,height/4},{0,height/3},stroke,paint)
stroke_bezier({0,height/3},{0,height/2},{width*.2,height/2},stroke,paint)
	stroke_bezier({width/6,height/2},{width/3,height/2},{width/3,height/2},stroke,paint)
	stroke_bezier({width/2,height/3},{height/1.4,width/3},{width/3,height/2},stroke,paint)
stroke_bezier({width/2,height/3},{width/2-.01,0},{width/2,-height/4},stroke,paint)
	stroke_bezier({width/2,-height/4},{height/1.4,-width/3},{width/1.5,-height/2},stroke,paint)
	stroke_bezier({width/1.5,-height/2},{width,-height/2+.01},{width/1.7,-height/2},stroke,paint)
	stroke_bezier({width/1.15,-height/2},{15
	,-4.5},{width,-height/3},stroke,paint)
	stroke_bezier({width,-height/3},{width-.01,0},{width,0},stroke,paint)
end	

function saw(width, height, stroke, paint)
	stroke_bezier({0,-height/2},{0.01,0},{0,height/2},stroke,paint)
	stroke_bezier({0,height/2},{width/2,-0.01},{width,-height/2},stroke,paint)
	--stroke_bezier({width,-height/2},{width,0},{width,0},stroke,paint)
end

function sawInv(width, height, stroke, paint)
	stroke_bezier({0,0},{0,-height/2},{0,-height/2},stroke,paint)
	stroke_bezier({0,-height/2},{width,height/2},{width,height/2},stroke,paint)
	stroke_bezier({width,height/2},{width,0},{width,0},stroke,paint)
end

function rdm(width, height, stroke, paint)
	stroke_bezier({0,0},{0,-height/4},{0,-height/4},stroke,paint)
	stroke_bezier({0,-height/4},{width/4,-height/4},{width/4,-height/4},stroke,paint)
	stroke_bezier({width/4,-height/4},{width/4,height/2},{width/4,height/2},stroke,paint)
	stroke_bezier({width/4,height/2},{width/2,height/2},{width/2,height/2},stroke,paint)
	stroke_bezier({width/2,height/2},{width/2,height/5},{width/2,height/5},stroke,paint)
	stroke_bezier({width/2,height/5},{width*.75,height/5},{width*.75,height/5},stroke,paint)
	stroke_bezier({width*.75,height/5},{width*.75,-height/2},{width*.75,-height/2},stroke,paint)
	stroke_bezier({width*.75,-height/2},{width,-height/2},{width,-height/2},stroke,paint)
	stroke_bezier({width,-height/2},{width,0},{width,0},stroke,paint)
end



x = 3
function wave(x, width, height, stroke, paint) 

--translate{0,50}

	
if x == 1 then 
return sine (width, height, stroke, paint) 
elseif x == 2 then
return tanh (width, height, stroke, paint)
elseif x == 3 then
return triangle (width, height, stroke, paint)
elseif x == 4 then
return saw (width, height, stroke, paint)
end
end

w = math.floor(waveform)+1
--wave(w)
width = 15
height = 10
stroke = .7
save()
translate{18,15}
wave(w, width, height, stroke, green_dk)
restore()

  @   @                 0   0    ,'@*  @ C    a  B               -
  *
  ,
  .
  |,   ,                   B  pA}DVrC
               (   (                 (   ŠU                x       M   ((fract(x/(2*pi)+.25))<.5?1-(fract(x/(2*pi)+.25)): (fract(x/(2*pi)+.25)))*2-1   98   8                      C0 px/;Ce}D               <   <                    A  A@   pA  B   Tj+ķCN               ,44   4                   0B^ jAB-(ĴC               0   0                    B     C  >D
               ę(   (                  5B<D                x       $   $                 ̔¼<D               x,   ,                 /C wD               d54   4                    C@  A AnFAD               \(   (                    0×FHCF               (   (                    ?"CF               (   (                    FòTBF               <   <                   A  A\   A  p        %DN                x       (   (                 T RÁD                x       0   0                          Ì%D(                 @    ,   ,                    B  0Ìa%D               D   D                 x 0   0     ?             4B   ,  C               
  
  
  
  
  
  
  
  
  
  
  
  
  
  
   
  !
  "
  #
  $
  %
  ԝ,   ,                   B   C  ,C
               h(   (                      C   C=               (   (                 T ?.\C               (   (                    ;NC@               ,   ,                   @    j  C	               L$   $                 xߖBL               $   $                     BL               $   $                     HCL               $   $                     CL               $   $                 DF,B               P$   $                 vC2 B               t4   4                 $   $     ?        };K
ғ               	
  

  
  $   $                 ÉD               $   $                 kCa6               D(   (                 , W\                x       0(   (                 S^>};K
ғ               $   $                 #KFC7 C               $   $                 d|CQyC               $$   $                 ^CC               X$   $                 x-C`A               0   0                 .       AL+fD	               4   4                 $   $     ?          \  C               	  	  	  	  	  	  	  	  	   
  
  
  
  
  
  
  
  
  
  ,   ,                   \B  4  C   
               (   (                      C  =               آ(   (                  
     C               (   (                      4  C@               X0   0                 P         i  	               0   0                 t       p  j  B	               0   0                 0	         i  -C	               D(   (                 .   j  C	               <$   $                  qAL               p$   $                 ArCL               $   $                 pB!iCL               $   $                 @EBz5CL               (   (                 .    pC                x       8   8                         ?  A  B                    (   (                     >C                x       (   (                 !  @  pC                x       $(   (                 , Cф                   Mod    Slider      0   0                          }QvC;!               h<   <                   B  A      A    @D  N                mod     ,   ,                   ?  pJDY1
               ,   ,                   ?  )C8wd	               D   D                  0   0     ?          A  4C  (!/A               	  	  	  	  	  
  
  ,   ,                   A   Cl&ʨ	               $4   4                 $   $     ?        };K
ғ               	  	  	  $   $                 ÉD               $   $                 kCa6               (   (                 4$ W\                x       (   (                 S^>};K
ғ               l$   $                 #KFC7 C               $   $                 d|CQyC               $   $                 ^CC               $   $                 x-C`A               <(   (                       B>               x(   (                 $ 2A                flip        0   0                 T%       AL+fD	               4   4                 $   $     ?          \                 	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  8,   ,                   \B  4  C   
               (   (                      C  =               (   (                       C               <(   (                      4  C@               0   0                           i  	               0   0                 D       p  j  B	               0   0                            i  -C	               t(   (                 T%   j  C	               l$   $                  qAL               $   $                 ArCL               $   $                 pB!iCL               $   $                 @EBz5CL               @(   (                 h%                    x       ,   ,                 XCl% k)ؿC               ,   ,                   IC       C               *   derive sine and triangle and saw waveforms  4   4                 $   $     ?         0,  C               	  	   ,   ,                    B        C
               $   $                 ]MC	               $   $                    fC%                (   (                                     x       `$   $                    B%               ,   ,                 pC   bA                  reverse phase   $   $                     B/               L4   4                   lBx A?/C!ŝ               \(   (                    mŁ	B=               (   (                 /  @  C                o       ܱ(   (                 / ;HB                o       Ĳ,   ,                   B     C  B	               <   <                    A   A/   B  p     C  BN                oct     DD   D                 2 0   0     ?            A   @5  C               	  	  $D   h  h                  C  pB(  L  L  Gu?H3DiB  C  #  # SoftSync VCO

A basic soft-sync VCO in which the synced waveform changes direction whenever the syncing waveform falls below zero. The synced oscillator can also be reset at the point of reversal, i.e. hard soft-synced. 

### Controls 

- SoftSync Slider – alters the frequency of the synced oscillator, i.e. the position within the synced sweep.
- Soft/Hard Button – ‘Hard’ resets the synced oscillator as well as reversing its phase. With ‘Soft’ only the phase is reversed.    
- Root knob – adjusts the level of the ‘root’ oscillator.
- Oversampling Button – selects 1, 2, or 4x oversampling.   

### Ports

- Modulation input for the softSync slider – the incoming modulation value is added/subtracted to the value set by the slider 
- O – pitch input in 1/oct scaling. This is the standard in Audulus, where 0 or no cable attached sends 440 Hz to the oscillators.
- A – audio output. Sync (‘root’) and synced oscillators, summed.

### Notes

The waveforms are derived from the phasor node, with 2 – 4x oversampling and light anti-aliasing using a one-pole low pass filter. 

### Version History

- 1.0 – 22.04.2024: Added ‘tanh’ waveform graphic 
- 0.9.1 – 07.04.2024: Improved gain controls for the root oscillator 
- 0.9 – 30.03.2024: Jerry Smith and Rudiger Meyer             4   	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  
  
  &
  '
  (
  )
  +
  /
  ?
  @
  A
  B
  F
  G
  H
  
  
  
  
  
  
  
  
  
  
  2  3  4     SoftSync VCO    ,   ,                    A   A  4  C	               X,   ,                   HB   AZC
               <   <                   A  A(     *C  A   F)ĉCN               G   gray = {1,1,1,0.8}
rotate(math.pi/4)
scale {0.5, 0.5}
text("L R", gray) 8<   <                   A  A(   `B`@   SX@sCN               J   gray = {1,1,1,0.8}
rotate(math.pi/2)
scale {0.5, 0.5}
text("All In", gray)  <   <                   A  A(    @,C ` C   PeBxBN               9   gray = {1,1,1,0.8}
scale {0.5, 0.5}
text("All Out", gray)   T,   ,                   4C  >C  B  C
               (   (                      C  pA=                (   (                      C  B=               X(   (                      C  %C=               (   (                      C  pC=               (   (                         B=               ,   ,                   pA   AX\C	               <(   (                        C=               t(   (                        C=               T,   ,                   9C   A꼬C	               <   <                   A  A
       @   IN                inp     <   <                   A  A
       @   '+N                inp     L<   <                   A  AD
       @   (ZN                inp     <   <                   A  A	       @   X:N                inp     <   <                   A  A	       @   Y!XN                inp     T<   <                   A  A<	       @   ĢN                inp     <   <                   A  A       @   P0@IN                inp     P$   $                 < VL               ,,   ,                  B  A    H
               h,   ,                 @$v`҈A P  W	               d@   @                 0   0     ?        A,CbB  wWį"C               	  	  	  	  	  	  8   8                   A  A         @Z<0M               4   4                 $   $     ?        ;Ĉ               	  	  	  	  0   0                 L   @  A  *  C	               \0   0                 X   B  A    C
               (   (                      C                x        0   0                              C(                          $   $                 < VL               ,   ,                  B  A    H
               0,   ,                 @$v`҈A P  W	               ,@   @                 0   0     ?        A,CcB  wW^B               	  	  	  	  	  	  8   8                   A  A         @Z<0M               h4   4                 $   $     ?        ;Ĉ               	  	  	  	  0   0                    @  A  *  C	               $0   0                    B  A    C
               T(   (                      C                x       H0   0                              C(                          $   $                 < VL               ,   ,                  B  A    H
               ,   ,                 @$v`҈A P  W	               @   @                 0   0     ?        A,C	A  wWĽzB               	  	  	  	  	  	  \8   8                   A  A         @Z<0M               04   4                 $   $     ?        ;Ĉ               	  	  	  	  
0   0                    @  A  *  C	               
0   0                    B  A    C
               (   (                 (     C                x       0   0                              C(                ?        \<   <                   A  A4        @      N                inp       -- Audulus colors
white = color_paint {.84, .84, .84, 1}
black = color_paint { .05,.05,.06,1}
module = color_paint{ .11,.11,.11,1}

azure = color_paint {0, 0.83, 1, 1}
azure_dark = color_paint {0, 0.61, 0.73, 1}
azure_bkgd = color_paint {0, 0.06, 0.08, 1}

if inp == 1 then 
	paint = azure_dark
else
	paint = black
end


stroke_circle( {12,12}, 11, 4, black)

fill_circle({12,12}, 11, paint) $   $                 < VL               h,   ,                  B  A    H
               ,   ,                 @$v`҈A P  W	               @   @                 0   0     ?        A,CbB  wWįTC               	  	  	  	  	  	  8   8                   A  A         @Z<0M               4   4                 $   $     ?        ;Ĉ               	  	  	  	  X0   0                    @  A  *  C	               0   0                    B  A    C
               (   (                 |     C                x       
0   0                              C(                          T$   $                 < VL               0,   ,                  B  A    H
               l,   ,                 @$v`҈A P  W	               h@   @                 0   0     ?          B        C               {	  |	  ~	  	  	  	  8   8                   A  A         @Z<0M               4   4                 $   $     ?        ;Ĉ               w	  x	  y	  z	   0   0                 H   @  A  *  C	               `0   0                 T   B  A    C
               (   (                      C                x       0   0                              C(                          $   $                 < VL               ,   ,                  B  A    H
               4,   ,                 @$v`҈A P  W	               0@   @                 0   0     ?          B        B               q	  r	  t	  u	  v	  	  8   8                   A  A         @Z<0M               l4   4                 $   $     ?        ;Ĉ               m	  n	  o	  p	  0   0                    @  A  *  C	               (0   0                    B  A    C
               X(   (                      C                x       L0   0                              C(                          $   $                 < VL               ,   ,                  B  A    H
               ,   ,                 @$v`҈A P  W	                @   @                 0   0     ?          C        HB               g	  h	  j	  k	  l	  	  `8   8                   A  A         @Z<0M               44   4                 $   $     ?        ;Ĉ               c	  d	  e	  f	  0   0                    @  A  *  C	               0   0                    B  A    C
                (   (                 $     C                x       0   0                              C(                ?        $   $                 < VL               ,   ,                  B  A    H
               ,   ,                 @$v`҈A P  W	               @   @                 0   0     ?          HB        HC               ]	  ^	  `	  a	  b	  	  (8   8                   A  A         @Z<0M               4   4                 $   $     ?        ;Ĉ               Y	  Z	  [	  \	  x0   0                     @  A  *  C	               0   0                     B  A    C
               (   (                 \     C                x       0   0                              C(                          <0   0                     pA  4B͟Cʉ               1(   (                      B   A	                  Volume Control  (   (                    "Cc                  3.16    H(   (                 t\ /Cny               0   0                 `k       p    ,	               0   0                 hk       =A	               0   0                 tk   C     C  A
               |3(   (                 tk B	               x(   (                 k   4B  0                       Max    Power      Control     K8   8                 k $   $     ?        IԐCn)               P	  Q	  R	  S	  T	  4L8   8                 p   $   $     ?        *C+               '	  (	  )	  *	  2	  3	  =	  F	  J	  K	  L	  M	  O	  U	  V	  W	     Stereo Output Core  0   0                 $         p  C 	                  Right   <0   0                 $     zC  ^)D
                  Right Peak Detector 0   0                 $          C  N	                  Left    0   0                 $     zC     (D  
                  Left Peak Detector  $$   $                 |~jC                ,   ,                         C  TB	               wD   D                 h  0   0     ?        n@'$B   }BDd'               H	  I	  N8   8                   $   $     ?        +CQ               >	  B	  C	  D	  E	  7(   (                 <   @;D;	               !0   0                    C      D 
               (   (                   lD9T                Timer       $   $                 <Dn-               H$   $                 |~jC               $,   ,                         C  TB	               yD   D                 D   0   0     ?        ۻAn$B   BDde               @	  A	  	   Red Light   ,(   (                   LmD;                Audio       lQ8   8                 D   $   $     ?        vC
               1	  9	  :	  ;	  <	     Audio Peak Detector (:(   (                    @;D;	               4$0   0                    C      D 
               d(   (                 ,   lD9T                Timer       	   1-Timer^2   $   $                 <Dn-               (   (                    A                   Audio       O4   4                 0M          C   B               x$   $                   jC                 T,   ,                           XB	               |D   D                  0   0     ?        jR@ӼA  AC&               5	  6	  7	  8	  P$   $                 Dғ2               $(   (                    4x6Dғ               (   (                 ,   LmD;                Audio          (Audio>=1)+(Audio<=-1)  $(   (                    A                   Audio       Q4   4                   {T      C   B               $   $                   jC                 ,   ,                           XB	               D   D                  0   0     ?        AܽA  C_               -	  .	  /	  0	  ,,   ,                 LFA`م@Cߥ	                                  UdCC>               h $                                                                                                h                      mCcl>               $   $                 0Dޥc2               $   $                 fj6Dޥc               ,   ,                 @u@z@A:C&O	               x T   L @ 8 4 0           (                  $                                   K       J                      , x   P                       HB  A        ?         ?7C  z8=C\  Audio Output Tile - v1.0

— — — 


- Controls - 

Volume knob - Controls the output volume. Flashing red lights indicate when clipping occurs. 


- Inputs -

L - Left input

R - Right input


— — — 


The Audio Output tile accepts a left and right channel audio signal and sends them to the system output (speakers, headphones, audio interface, and so on).

Red lights behind the knob will flash if the output level has been exceeded. 

To output a mono signal, simply attach the same audio signal to both the left and right inputs.


— — — 

Version History

1.0 - 2022.07.10 - Created                   &	  +	  ,	  4	  ?	  G	  N	  X	     Audio Output    74   4                      ?n$C DQ:D8               (   (                    QNDX>               (   (                    cODX>               74   4                    (|?g$CDQ:D8               84   4                      ?^$Cbb#DQ:D8               (   (                    QNDX>               (   (                    QNDz>               84   4                      ?+$C  +DQ:Dqt               \z0   0                    BC Dh/:D+P               (   (                    h/ND+V>               (   (                    ND+B>               {0   0                    CDh/:D+<               L{0   0                    HZCv#Dh/:D+(               (   (                    h/ND+.>               (   (                    h/ND+>               {0   0                    "EC  +Dh/:D+               p$   $                 sdDv               p|0   0                    8lB DR8DB               (   (                    RLDBK>                (   (                    LDBK>                }0   0                    0BDR8DB˾               `}0   0                    /B4#DR8DB˖                (   (                    RLDBK>               !(   (                    RLDv>               ~0   0                    PB  +DR8D]               P~0   0                      B D 6D                 !(   (                     JD  >               !(   (                     JD  >                0   0                      B  D 6D  @               @0   0                      B #D 6D  B               "(   (                     JD  pB>                $   $                   D  B                #(   (                     JD  C>               >4   4                    )\<  B  +D 6D  %C               #(   (                    tD|я=               #(   (                    ZpDB @=                60   0                    \C DʏD
               `60   0                     \C  DD1
               @<   <                   pA  B(     pB C       CN                 -- adding removing labels will adjust the table
-- set module width/height to fit

labels = { "→", "→", "→", "→" }

spacing = 30

rotate(math.pi/2)
--translate {0, yspace*8}
translate {2, 25}

for i = 1,#labels do 

translate {0, -spacing}
text(labels[i], {.84,.84,.84,1})

end
  <   <                   B  pA(     A  $B   |ĲBN                 -- adding removing labels will adjust the table
-- set module width/height to fit
labels = { "→", "→", "→", "→" }

yspace = 30

-- spacing to line up with ports
translate {0, yspace*4}

for i = 1,#labels do 

translate {0, -yspace}
text(labels[i], {.84,.84,.84,1})

end
  T4   4                   Ah   C  C|~7.B               4   4                   A$     B  Ci¾B                  C   4   4                   A   B  C     C               (4   4                   A   4B  Ciߍ`C               8D   4  4                  HC  HC        ?          C    4 × 4 Matrix

PORTS: 
· 4 inputs, each input is routed to a row, the level of which can be adjusted. Each row can be muted.
· plus an additional input that goes to all inputs (rows)
· 4 outputs, each column summed. Each column can be muted. 
· plus an additional output that sums all outputs (columns)
· Outputs 1 & 2 (i.e. columns 1 & 2) are internally routed to the main audio out (L R)  
· An additional L R input in the bottom RH corner is directly routed to the main audio out (L R)              %                                 %	  _	  i	  s	  }	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	     Level Matrix 4 × 4 ,   ,                   C  >C  k  \B
               X,   ,                   pA  Bw@s^B	               ,   ,                   pA  Cw@sįYC	               ,   ,                   pB  >C  k  MC
               ,   ,                   pA  Bw@sį'C	               H,   ,                   B  >C  k  B
               ,   ,                   B  >C  k  C
               ,   ,                   pA  4Bw@s^B	               h?0   0                   [C #DLD
               -(   (                    /fnD{=               `7D   D                    0   0     ?          Z h	  ĸ            .                      	  	  	  	  	  	  	  	  	  		  
	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	   	  !	  "	  #	  $	     Grid    @0   0                 L   \C  +D  D  A
               <A0   0                 7   A #DECRI	               |A0   0                 P7   A DECRg	               A0   0                 L   A  +DIACd9	               A0   0                 E   A  DECRX	               (0(   (                     mD   =               L8   8                   A~  'BZB   \DK               ]8   8                    ,
?     HB  BYYD9`               0(   (                    obD.>               <   <                   A  pA~     @  B    'D  N                Toggle       (   (                 D  C                  (   (                    CF               D0   0                 C       p    ,	               HD0   0                 C       =A	               D0   0                 C   C     C  A
               Z(   (                 C B	               (   (                 4D   4B  0                       Max    Power      Control     Ls8   8                 HD $   $     ?        CC                         <p4   4                 Tn   @     瞖CsB               1$   $                   bC  XB               ,   ,                         C  TB	               =D   D                 |n 0   0     ?           A   A  0DK                     t8   8                   $   $     ?          D                       `](   (                 p    wD  p	               lG0   0                 P   B      D  p
               (   (                    D  p                Audio       PL                                      Phasor      4H0   0                 p    C      RC  
               ^(   (                 t    !  	               v8   8                   $   $     ?        =!D*                     (   (                   SB)A                x       M                  勐C<@                x       I0   0                      C      C  @
               _(   (                 $  @	               w8   8                 T  $   $     ?        ߒ!D:                       XJ0   0                 ;       p C  	               J0   0                 ;         C  ,	               7              C%               |u4   4                          C   B               47$   $                 |~jC               	,   ,                         C  TB	               8CD   D                 < 0   0     ?          HB   A  rKDk                     z8   8                   $   $     ?         D  %            	                     b(   (                 0   LD  A	               L0   0                    hC     D  
               M0   0                 ;   B     @PD  PA
               
,   ,                   pB      B    
               l9$   $                         	               {8   8                   $   $     ?          D  aC                   ;(   (                      ,D  p?               ,   ,                   pB      B    
               h:$   $                         	               |8   8                   $   $     ?         C  bC                   (   (                   ]CcB                Toggle      8;$   $                 yC  |L               O0   0                 I       p  !C  	               O0   0                  I         C  A	               ;$   $                  C  AL               4P0   0                        @=  LC  XC	               \~8   8                 Ȁ  $   $     ?         aD              
                       |,   ,                    A  APD               l8   8                    !
>      A  B  C  O                ,   ,                   HB   AND 
               <,   ,                    A   A2DA+	               Ò  @   @                   B  pB<  $   $     ?          A                                             `>$   $                 XڛC               (   (                  ܷUC               ,<   <                    A   AH      B  @   {D8EN                   mode       input         -- HSV to RGB
function hsv(h,s,v)
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end

local function octLight(input, x, y)
	
	local h=(1-((input+5)/10))*.7 -- color shift per octave
	local s=1 -- saturation always 1
	local v=((input+5)-math.floor(input+5))*.9+.1 -- dark to light per octave
	
	local r,g,b = hsv(h,s,v)
	
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	save()
	translate{x,y}
	fill_circle({0,0},9,color_paint{.05,.05,.05,.18})
	fill_circle({0,0},5,color_paint{.05,.05,.05,1})
	
	fill_circle({0,0},9,halo)
	fill_circle({0,0},5,paint)
	
	min, max = text_bounds("A")
	translate{ -(min[1]+max[1])/2, -(min[2]+max[2])/2 }
	text("A", theme.text)
	restore()
	
end

local function modLight(input, x, y)
	if input > 0 and input <= 1 then
		r = input
		g = input*.3
		b = 0
		a = 1
	elseif input > 1 then -- saturate alpha if > 1
		r,g,b,a = 1, .1, 0, math.abs(input)
		
	elseif input <= 0 and input >= -1 then
		r = math.abs(input*.2)
		g = math.abs(input*.3)
		b = math.abs(input)
		a = 1
	elseif input < -1 then -- saturate alpha if < -1
		r,g,b,a = .2, .3, 1, math.abs(input)
	end
	
	save()
	
	translate{x,y}
		fill_circle({0,0}, 5, color_paint{r,g,b,a})
		fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})
		if mode == 1 then 
		min, max = text_bounds("A")
	translate{ -(min[1]+max[1])/2, -(min[2]+max[2])/2 }
	text("A", theme.text)
	restore()
else
	min, max = text_bounds("M")
	translate{ -(min[1]+max[1])/2, -(min[2]+max[2])/2 }
		text("M", theme.text)
	restore()
end	
end


modLight(input, 5, 5)
   ,   ,                       A$DX	               TH(   (                    6D?               d8   8                   Ahf  'BZB   \DK               0   0                     HB  BYYD9`               I(   (                    obD.>                5<   <                   A  pA8   v@ЍB   
.DоN                Toggle         -- This gray matches the default text color

gray = {0.8,0.8,0.8,1}

-- Displays one text option when the Toggle input is 0 and another text option when the Toggle input is not 0.

if Toggle == 0 then 
text("m", gray) else
text("a", gray)
end  (   (                 (  C                 (   (                 pf   CF               $]0   0                 *       p    ,	               d]0   0                 *       =A	               ]0   0                 *   C     C  A
               t(   (                 * B	               (   (                 +   4B  0                       Max    Power      Control     h8   8                 ,+ $   $     ?        CC                         X4   4                 8U   @     瞖CsB               K$   $                   bC  XB               ,   ,                         C  TB	               WD   D                 `U 0   0     ?           A   A  0DK                     8   8                 f  $   $     ?          D                           v(   (                 Li    wD  p	               `0   0                 ,   B    `sDB
               (   (                 f  ]D[                Audio       te                f                      Phasor      Xa0   0                 Lh    C      RC  
               w(   (                 Ph    !  	               8   8                 f  $   $     ?        =!D*                     (   (                 f  SB)A                x       f                f  勐C<@                x       b0   0                 f    C      C  @
               y(   (                  g  @	               8   8                 0g  $   $     ?        ߒ!D:                       |c0   0                 "       p C  	               c0   0                 "         C  ,	               Q              C%               8   8                 h  $   $     ?         D  %            	   u                  z(   (                 $l   LD  A	               d0   0                    hC     D  
               e0   0                 t#   B     @PD  PA
               ",   ,                   pB      B    
               xQ$   $                         	               8   8                 j  $   $     ?          D  aC                    T(   (                      ,D  p?               #,   ,                   pB      B    
               tR$   $                         	               8   8                  j  $   $     ?         C  bC               }  ~   $(   (                 th  ]CcB                Toggle      DS$   $                 yC  |L               g0   0                 1       p  !C  	               g0   0                 1         C  A	               S$   $                  C  AL               @h0   0                 |h       @=  LC  XC	               h8   8                 h  $   $     ?         aD              
   v  w  x  y  z  {  |        |0   0                       A  A:
D                8   8                    \>      A  B  C  O               ',   ,                   4B   AND 
               L',   ,                    A   A2DA+	               gh  @   @                   B  pB,l  $   $   ?*Ĕ_C  HC                 q  r  s  t                      $D<   <                    A  A~    pA  B       CN               pa8   8                       B?  A  B    C               ((   (                 l  |cyC                x       8!4   4                 $   $     ?        q%<PC               j  k  @),   ,                    B        C
               W$   $                 ]MC	               E<   <                    A  At     pA  4B   AaN               F<   <                    A  A(     4B  A   i4N                  

label = "shape"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
    G<   <                    A  A(     4B  4C   yŗLN                  

label = "sync"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
 G<   <                    A  A(     4B  B   jN                  

label = "crossfade"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
    L,(   (                 (   R5zC                x          x-1 %4   4                 $   $     ?        FĕC               b  c  -,   ,                    B        C
                \$   $                 ]MC	               Z@   @                 0   0   34@K΢C  pA  B  *KF               \  ]  ^  _  `  d.,   ,                   B  B  zC  
               \K8   8                   A  A     A  Ao؎M               J<   <                   A  A8     A  A    B N                switch      F  

if switch > 0 then 
	label = "ind"
	circle_color = theme.azureHighlight
	border_color = theme.grooves
	text_color = theme.azureHighlightBackground
else 
	label = "1→2" 
	circle_color = theme.azureHighlightBackground
	border_color = theme.azureHighlight
	text_color = theme.azureHighlight
end

save()
translate{canvas_width/2, canvas_height/2}
stroke_circle( {0,0}, 12, 4, color_paint(border_color))
fill_circle({0,0}, 11.5, color_paint(circle_color))

min, max = text_bounds(label)
scale{.9,.9}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
text(label, text_color)
restore()  0(   (                 X] .BlG                 x       n0   0                          ԷBT(                      tb(   (                    `ŪN?               1(   (                 H{ `zC               N<   <                    A  @Z   B  +C   0N               N<   <                    A  @Y   A  +C   gޙN               0O<   <                    A  A    4B  B   TiםN               |O<   <                   A  A(   SAyC   itАCN                  rotate(math.pi/2)

label = "double hard sync"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
    P<   <                    A  A(     pA  C   YZAN                  

label = "offset"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
   Q<   <                   A  A(   UAʃC      CN                  rotate(math.pi/2)

label = "hard sync"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
   R<   <                    A  @V   A  +C   A JCN               <6(   (                 h gh(O'               t6(   (                 Z   C                     Mod    Slider      0   0                            pC  !               S<   <                   B  AV      A    @D  N                mod     `7(   (                 ,    C?%                   Mod    Slider      X8,   ,                   ?  p D  
               8,   ,                   ?    OC  '	               rD   D                 $Z 0   0     ?          A  4C  2NC               L  M  N  O  P  Q  $4   4                 lZ         C   B               g$   $                 |~jC               9,   ,                         C  TB	               sD   D                 Z 0   0     ?          A   C      pC               H  I  J  X:,   ,                   A   C   *C	               j(   (                    N eB=               4   4                   B\    @  BC               X34   4                 $   $     ?           \               ;  =  B  d;,   ,                   pB   B]pG&
               :(   (                 -   @                  x       r   $   $                                   x;(   (                 $.   @                 hz      ,   ,                 ?C$.                     ,8   8                 `roBc   A TeB   P6sda               @<(   (                 h.   @  H                   thresh  	   syncPulse       4   4                      ?  A   BBł\)               m(   (                    +=               =(   (                 |.                      
   pulseWidth     x       ll$   $                 x4-               =(   (                  ns                x       =(   (                 |.  VcEC                x       74   4                 $   $   [@瀡D!D                  3  4   ?,   ,                   HC  Aǡ!
               04   4                      ?   C  ApA"               >(   (                 |3      pB                   shift      oct     P?(   (                 $      B                o       8@,   ,                   A  A   	               ?(   (                      zC                o       @,   ,                   B     C  B	                ]<   <                    A   A    B  p     C  BN                oct     8{D   D                 ؤ  0   0     ?            A  Z:C               .  -  |v<   <                       ?     A  BTB               4   4                      @ C    @                 D   D  D                  C  pB  (  (  P?hD4AOB  # HardSync VCO

A basic hard sync VCO in which the synced waveform is reset by the syncing oscillator. A bipolar VCA briefly inverts the signal at the sync point in order to reduce transient noise. (This reduction can easily be internally adjusted to suite one’s taste.)

### Controls 

- HardSync Slider – alters the frequency of the synced oscillator, i.e. the position within the synced sweep.
- Offset Knob – sets the base offset for the HardSync Slider 
- Root knob – adjusts the level of the ‘root’ oscillator.

### Ports
- Modulation input for the sync slider – the incoming modulation value is added/subtracted to the value set by the slider
- Shape (0 – 1 modulation) input – adjusts the shape of the saw and square waveforms: 
	- Modulating a saw wave results in a waveshape resembling a supersaw. 
	- Modulating a square wave produces pulsewidth modulation (PWM). 
- O – pitch input in 1/oct scaling. This is the standard in Audulus, where 0 or no cable attached sends 440 Hz to the oscillators.
- A – audio output. Sync (‘root’) and synced oscillators, summed.

### Version History
- 1.0 – 07.04.2024: with fixes to the bipolar VCA and improved gain controls for the root oscillator 
- 0.9 – 30.03.2024: by Jerry Smith and Rudiger Meyer              ,   &  '  (  *  +  ,  /  0  1  2  5  6  7  8  9  :  <  >  ?  @  A  C  D  E  F  G  K  R  S  T  U  i  l  m  n  o      
  5  6  7  <  S     HardSync VCO    \H,   ,                    A   Aź|C	               H,   ,                   HB   A    >C
               0   0                      @ C    C               pH(   (                 (   WMe                x          x/2 le<   <                   HB  HB@     B  HB   xvĒ#N                   m      k         
-- add k and m input ports for knob and modulation

knobSize = 1 -- 1 = standard, 2 = large, 3 = mini
-- make Canvas width/height 50x50, 70x70 for large, 25x25 for mini
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 35 end
if knobSize == 3 then ksize = 12.5 end

-- Knob modulation: this displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off)

-- Audulus colors
white = color_paint {.84, .84, .84, 1}
black = color_paint { .05,.05,.06,1}
module = color_paint{ .11,.11,.11,1}

azure = color_paint {0, 0.83, 1, 1}
azure_dark = color_paint {0, 0.61, 0.73, 1}
azure_bkgd = color_paint {0, 0.06, 0.08, 1}

green = color_paint {0.23, 0.77, 0.33, 1}
green_dark = color_paint {0.15, 0.51, 0.03, 1}
green_bkgd = color_paint {0, 0.08, 0.01, 1}

red = color_paint {1, 0, 0.38, 1}
red_dark = color_paint {0.65, 0, 0.25, 1}
red_bkgd = color_paint {0.11, 0, 0.04, 1}


-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, module)

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, black)

a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a+math.pi/2, a, black)

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

-- change both to some other color (like red) to distinguish port from knob takeover
if m >= 0 then
    mpos = math.max(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, red)
elseif m < 0 then
    mneg = math.min(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, red)
end

-- highlight current position (using stroke_arc aperture)
stroke_arc({ksize,ksize}, ksize-1,3, 2*a-math.pi/2, .03, azure)
 P(   (                 x=   B                  x       Q(   (                 (9 A&٘                x       TQ(   (                 (   OQH                x          x-.5    HR,   ,                   A  Bĸޱ	               h4   4                 XI   H  x    C   B                $   $                 |dCPt<               R,   ,                         B  bB	               $D   D                 PA 0   0     ?          pB   A  WĬ&                     #  (   (                    jF/=               4   4                    >  pB  B&TT;               xS(   (                 @   3^#;                      b      a      x          mix(x, a, b)    S(   (                 LK ōĢR                T(   (                 0=   C                     Mod    Slider      4   4                 dY>           pC  !               hq<   <                   B  A8      A    @D  N                mod     U(   (                 (    C?%                   Mod    Slider      V,   ,                   ?  p D  
               DV,   ,                   ?    OC  '	               lD   D                 t< 0   0     ?          B  4C  5Э                           4   4                 <         C   B               $   $                 |~jC               hW,   ,                         C  TB	               D   D                 < 0   0     ?          B   C  oŬ                     X,   ,                   B   CozŬ	               (   (                    )=               P4   4                 $   $     ?        ޴VA                   	  X,   ,                   pB   B]pG&
               d(   (                    _AĂ">                               1 i|V-                x       X(   (                 PZ tV2                x        Y(   (                   4V                x          $   $                 ޴Vpb               Y(   (                    4VY                hz      ,   ,                 ?C   Vn               P8   8                 `roBxE   A TeB   P6sda               dZ(   (                 D  4V<                   thresh  	   syncPulse       84   4                      ?  A   BBł\)                (   (                    Ĕj'=               <[(   (                 X  5ĭQ                
   pulseWidth     x       $   $                 V
K-               [(   (                  c)K                x       T4   4                 $   $     ?        tVp0                    ],   ,                   HC  AA"
               4   4                    (D?   C  ApA"               \(   (                     A                        b      a      x       4(   (                        =               4   4                  A0     C                 Ġ0   0                          	               `                H-   *                  s                       T-                     m       tq,   ,           H            	               t0   0           A C            pB                 0   0           <U)AQ                           L(   (                      	               (   (              B       pC  
               d0   0           B~@;                            (   (               p       	               ,   ,           $   $     ?        )qĬ`                                         (   (             A      E,
               (   (                   r
	               ,   ,           $   $     ?        tĬ`                                   ) V                x       xa(   (                    oŬ                   shift      oct     a(   (                   n                o       b,   ,                   pB   A`k	               <   <                       C>?     B  BqŨI               4   4                      B C   4V               b(   (                 X< v#B               c(   (                 <.   C                     Mod    Slider      0   0                            pC  !               X<   <                   B  A)      A    @D  N                mod      d(   (                 8     C?%                   Mod    Slider         Slider+Mod
 e,   ,                   ?  p D  
               De,   ,                   ?    OC  '	               lD   D                 t- 0   0     ?          A  4C  2NC                           4   4                 -         C   B               $   $                 |~jC               hf,   ,                         C  TB	               D   D                 - 0   0     ?          A   C      pC                     g,   ,                   A   C   *C	               (   (                    N eB=               4   4                   B$         pBC                  Dual HardSync VCO    `4   4                 $   $     ?           \                     ,h,   ,                   pB   B]pG&
               (   (                    m=>               h                D"  |                  x       8h(   (                 J                     x       |h(   (                 (    @                  x          (x+1)/2   n , (                                                                                                   n      $   $                                   ti(   (                 (   N?                hz         1/hz/2   ,   ,                 ?C                         freq dependent pulsewidth   T8   8                 `roBt5   A TeB   P6sda               hj(   (                 @    @  H                   thresh  	   syncPulse          syncPulse > thresh  T4   4                      ?  A   BBł\)               (   (                    +=               Xk(   (                 <   AĮ                
   pulseWidth     x          x<pulseWidth    $   $                 x4-               k(   (                 o ns                x       <l(   (                 (   @C                x          clamp(x, 0.01, 1)   e4   4                 $   $     ?                              m,   ,                   HC  AA"
               4   4                    (D?   C  ApA"               hm(   (                 @     A                        b      a      x          (1-x)* a + x * b    ؞(   (                        =               4   4                  A0     C                 h0   0                           	                                  *                  s       @                                     m       ,   ,                       	               0   0           A C(             pB                    
Bipolar VCA
Linear 
Crossfade
 |0   0           <U)A<@                           (   (                      	               L(   (              B       pC  
               ,0   0           B~@*                            (   (               p       	               ,   ,           $   $     ?         @q  B                                         p(   (             A      E,
               (   (                   r
	               p,   ,           $   $     ?           4B                   p                                      x       @r(   (                 8       pB                   shift      oct        oct + (shift*24+12)/12  r(   (                 n      B                o       s,   ,                   B  B&u,	               0s(   (                 Dn  AxX$C                o       t,   ,                   B     C  B	               `<   <                    A   A\n    B  p     C  BN                oct     D   D                 xq  0   0     ?            A  {AC                   ܩ<   <                       _>     A  BTB               h 8 4 ,                                                                         +                 h   4   4                      @ C    @                 pD                       C  B      e\?+BDHC  fC  Ã  # DoubleHardSync VCO

A dual hard sync VCO in which the synced waveform is reset by the syncing oscillator. A bipolar VCA briefly inverts the signal at the sync point in order to reduce transient noise. The second hard sync VCO can run independently, parallel to the first, or can be (double)synced from the already synced first VCO. A crossfader adjusts the mix between the two. 

### Controls 

- HardSync Sliders – alter the frequency of the synced oscillator, i.e. the position within the synced sweep.
- Offset Knobs – set the base offsets for the HardSync Sliders
- Crossfade Knob – crossfades between the two hard synced VCOs

### Ports

- Modulation inputs for the sync sliders (M) – the incoming modulation value is added/subtracted to the value set by the sliders
- Shape (0 – 1 modulation) inputs (M) – adjust the shape of the saw and square waveforms: 
	- Modulating a saw wave results in a waveshape resembling a supersaw. 
	- Modulating a square wave produces pulsewidth modulation (PWM).
- Bipolar input (A) – for modulating the Crossfade knob.  
- O – pitch input in 1/oct scaling. This is the standard in Audulus, where 0 or no cable attached sends 440 Hz to the oscillators.
- A – audio output.

### Version History

- 1.0 – 07.04.2024: with fixes to the bipolar VCA and improved gain controls for the root oscillator 
- 0.9 – 30.03.2024: by Jerry Smith and Rudiger Meyer             V                                                                                                                  
                       !  "  $  %  V  W  X  Y  Z  [  a  d  e  f  g  h  
  
  *  .     DoubleHardSync VCO  T},   ,                    A   A(UYC	               },   ,                   B   Ah
               h 4 0 (                                                                                           h   0   0                      @ Cw.C               8   8                   A(   'BZB   \DK                  out 8   8                    8?     HB  BYYD9`               d(   (                    obD.>               P<   <                   A  pA8      @  B    'D  N                Toggle         -- This gray matches the default text color

gray = {0.8,0.8,0.8,1}

-- Displays one text option when the Toggle input is 0 and another text option when the Toggle input is not 0.

if Toggle == 0 then 
text("sin", gray) else
text("tri", gray)
end  (   (                 V  C                 0(   (                     CF                  5.3219  0   0                 l       p    ,	               0   0                 t       =A	               0   0                    C     C  A
               p(   (                  B	               l(   (                    4B  0                       Max    Power      Control     8   8                  $   $     ?        CC                         4   4                    @     瞖CsB               p$   $                   bC  XB               L,   ,                         C  TB	               tD   D                   0   0     ?           A   A  0DK                     @8   8                 <   $   $     ?          D                          Audio to Mod Converter  (   (                     wD  p	               0   0                 m   B      D  p
               4(   (                 ,    D  p                Audio          Audio*0.5+0.5                   ,                       Phasor         cos(Phasor) 0   0                     C      RC  
               \(   (                     !  	               P8   8                 <   $   $     ?        =!D*                        Phasor to Sine Converter    Ѕ(   (                 (   SB)A                x          (x/pi-1)                    (   勐C<@                x       
   abs(x)*2-1  0   0                 $     C      C  @
                  Audio   (   (                    @	                  Phasor  8   8                 @   $   $     ?        ߒ!D:                          Phasor to Triangle Converter    0   0                        p C  	               0   0                          C  ,	               0              C%               4   4                 
         C   B               l$   $                 |~jC               H,   ,                         C  TB	               pD   D                  0   0     ?          HB   A  rKDk               |  }  ~  <8   8                 T   $   $     ?         D  %            	   i  x  y                 Sine/Triangle LFO Core  (   (                    LD  A	               0   0                 g   hC     D  
               X0   0                 ,   B     @PD  PA
               ,,   ,                   pB      B    
               $   $                         	               8   8                   $   $     ?          D  aC               u  v  H(   (                      ,D  p?               (,   ,                   pB      B    
               $   $                         	               8   8                   $   $     ?         C  bC               q  r  H(   (                 ,   ]CcB                Toggle      	   1-Toggle
   $   $                 yC  |L               0   0                        p  !C  	               $0   0                          C  A	               P$   $                  C  AL               0   0                 $        @=  LC  XC	                  Toggle  8   8                 X   $   $     ?         aD              
   j  k  l  m  n  o  p  s  t  w     Spigot Switch   M0   0                       A  APD               8   8                    g>      A  B  C  O               ,   ,                   HB   AND 
               ď,   ,                    A   A2DA+	               lD                       B  pB  p  p    ?          C  G  LFO Tile - v1.0

— — — 


- Controls - 

sin/tri knob - Controls the speed of the LFO from 0 to 20Hz scaled exponentially. 50% = 0.5Hz

out knob - Controls the overall output level of the LFO.

Toggle - Switches between sine and triangle LFO shape.


- Inputs -

S - When pulsed, the sync input will restart the LFO


- Outputs - 

M - Modulation output for the LFO


— — — 


The LFO Tile offers the two most frequently used LFO shapes: sine and triangle.

A sine wave approximates the feeling of a human turning a knob up and down which slows down as it reaches the bottom and top of its travel, whereas a triangle wave has a sharp turn around and a linear response throughout.

The output knob scales down the size of the LFO.

The sync input will restart the LFO.


— — — 

Version History

1.0 - 2022.07.10 - Created                e  f  g  h  z  {                     LFO <   <                    A  @   A  +C   #!ǗN               4   4                 |         C   B               $   $                 |~jC               ,   ,                         C  TB	               D   D                  0   0     ?          A   C  p$%vv               `  a  b  T<   <                   A  A(   QAʄC   &CN                  rotate(math.pi/2)

label = "sub sync"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
    $   $                 f9 ňb               Ԏ4   4                 $   $   @ pE  B6                 [  ܖ,   ,                   HC  A @  
               t(   (                  K  SC                o       (   (                 (      fC                x          x+3 <   <                   A  A4     A  B       DN                k       B  
label = math.floor(k)

save()
translate{canvas_width/2, 5}
scale{1.2,1.2}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()

save()
translate{canvas_width/2, 27}
scale{.75, .75}
min, max = text_bounds("oct")
translate{-(min[1]+max[1])/2, 0}
text("oct", theme.text)
restore()  (   (                 ,       C                count          (count<3)*(count+1) 0   0                             D(                 @    L(   (                 (                      x       
   abs(2*x-1)  (   (                 (      A                x          fract(x/(2*pi)+.25) (   (                    |DMVX=               4(   (                  wDVT                x       t$   $                 2DyhL               $   $                 DDL               (   (                    TD>=               (   (                 (   d|DMo                oct        isinf(2^oct*440)?0:2^oct*440    (   (                  jDY^                x       $   $                 .D\dxL               $   $                 dDyL               ,(   (                 (     D                  x          x/4 0   0                 3    \  *C6D|	               4   4                 $   $   /}?٨±CJD4<q               D  E  F  G  I  J  K  L  M  N  O  <0   0                     B  C  D  
               |0   0                    \  C  WD  	               0   0                 $     \  B*VDDd	                  O   (   (                    rDDd?               ,(   (                 (       A                x          cos(x*2*pi) ,   ,                 4C   m+C^               X   in a practical sense, lpf cutoff only starts to become noticeable when alpha > 0.5 or so    X,   ,                 C   ؛Tsq               4   modify alpha (cutoff) based on resampling sampleRate    ,   ,                 ̗C   [Hd                  calculate resampling sampleRate `                4   ;:                   fs     fc         1-fc/(fs+fc)                    (   oã                fc         fc*2*pi ,   ,                 C   ).A                  The current sample rate node does not adjust for resampling. This means higher resampling rates will produce more high end -- the illusion of more high end in the signal when really just a higher filter cutoff value.    (   (                    7M ;                  8000    $   $                 OB               ((   (                    Xë >               t0   0                 $         (	                  Resampling factor   0   0                    B   kDվ
               8(   (                     &B	                  In  8$   $                 XaCF               l$   $                 :<g1               $   $                 9Cj/               8   8                 l   $   $   ?Jڼ-C  p  C               4  5  6  7  8  9  :  ;  <  =  >  ?  @  A  B     Downsample AA filter     ,   ,                   A  B   D               E8   8                      C$   px/;CC6C                  softSync VCO    8   8                    A  A$    KAC `  N                  

label = "thresh"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
   <   <                    A  A(     pA  B   TqA1CN                  label = "root"

save()
translate{canvas_width/2, 2}
scale{.75, .75}
min, max = text_bounds(label)
translate{-(min[1]+max[1])/2, 0}
text(label, theme.text)
restore()
   A4   4                   0B Q  jAB]A]AC               X0   0                 $     B     C  >D
                  factor  (   (                 (   5B<D                x          2^x $   $                 ̔¼<D               P,   ,                 /C   wD               ?   Change x<1 to x<2 or x<3 to enable to 4× and 8× resampling.   C4   4                    C$    A AnFAD                  resmpl  (   (                    0×FHCF               (   (                    ?"CF               (   (                    FòTBF               <<   <                   A  A4     A  p        %DN                x          



t = {"1×","2×","4×","8×"}



save()
translate{canvas_width/2, 5}
scale{1.2,1.2}
min, max = text_bounds(t[x+1])
translate{-(min[1]+max[1])/2, 0}
text(t[x+1], theme.text)
restore()  (   (                 l RÁD                x       0   0                          Ì%D(                 @    ԫ,   ,                    B  0Ìa%D               D   D                    0   0     ?          4B   ,  C                                  "  #  $  %  &  '  (  )  *  +  ,  -  	   Resampler   ̬,   ,                   B   C  ,C
               `(   (                      C   C=               (   (                 \  ?.\C               (   (                    ;NC@               ,   ,                   @    j  C	               D$   $                 xߖBL               x$   $                     BL               $   $                     HCL               $   $                     CL                               (   !ũv                x          sqrt(x) \$   $                 DF,B               $   $                 vC2 B               4   4                 $   $     ?        };K
ғ                     $   $                 ÉD               L$   $                 kCa6               (   (                   W\                x       p(   (                 S^>};K
ғ               $   $                 #KFC7 C               0$   $                 d|CQyC               d$   $                 ^CC               $   $                 x-C`A               0   0                 D        AL+fD	               4   4                 $   $     ?        ӟ^Ĝ|C                                      	                H,   ,                   \B  4  C   
               (   (                      C  =               (   (                      C               L(   (                      4  C@               0   0                          i  	               0   0                 4       p  j  B	               0   0                          i  -C	               (   (                 D    j  C	               |$   $                  qAL               $   $                 ArCL               $   $                 pB!iCL               $   $                 @EBz5CL                  ,   <                    <   dD$8CO            count            trigger     -  
local n = 2

local Count = 0
local prevTrig = 0
local loadState = true
local saveState = false

function process(frames)
    if loadState then
        Count = storage[1] or 0
        loadState = false
    end	
		
    if trigger[1] > 0 and prevTrig == 0 then
        Count = (Count + 1) % n  -- Loop counter from 0 to (n-1)
        -- Count = Count % n + 1  -- Loop counter from 1 to n
        saveState = true
    end
    prevTrig = trigger[1]

    fill(count, Count)

    if saveState then
        storage[1] = Count
        saveState = false
    end
end
   ,   ,                   A  pAGLD*C                 j @ < 4                 ,                    (                               $   3                 j   <                            A  HB      t DrCN   b   canvas_height = 30
canvas_width = 50
height = 10
stroke = 0.7
w = 1
waveform = 0
width = 15
x = 3
               waveform          azure = color_paint{0,.831,.1,1}
azure_dk = color_paint{0,.608,.729,1}
azure_bkgd = color_paint{0,.059,.078,1}

green = color_paint{.231,.769,.333,1}
green_dk = color_paint{.149,.502,.216,1}
green_bkgd = color_paint{0,.078,.012,1}

red = color_paint{1,0,.384,1}
red_dk = color_paint{.651,.081,.251,1}
red_bkgd = color_paint{.110,0,.043,1}

text_color = color_paint{.839,.839,.839,1}



-- cover trigger node
fill_circle({canvas_width/2, canvas_height/2}, 16, color_paint{.12,.12,.12,1})
fill_rect({0,0}, {50,30}, 8, azure_bkgd)


function sine(width, height, stroke, paint)
	stroke_bezier({0,0},{0,height/2},{width*.25,height/2},stroke,paint)
	stroke_bezier({width*.25,height/2},{width*.5,height/2},{width*.5,0},stroke,paint)
	stroke_bezier({width*.5,0},{width*.5,-height/2},{width*.75,-height/2},stroke,paint)
	stroke_bezier({width*.75,-height/2},{width,-height/2},{width,0},stroke,paint)
end

function triangle(width, height, stroke, paint)
	stroke_bezier({0,-height/2},{width*.25,-.01},{width*.5,height/2},stroke,paint)
	stroke_bezier({width*.5,height/2},{width*.75,-.01},{width,-height/2},stroke,paint)
end

function square(width, height, stroke, paint)
	stroke_bezier({0,0},{0.01,height/4},{0,height/2},stroke,paint)
	stroke_bezier({0,height/2},{width/4,height/2-.01},{width/2,height/2},stroke,paint)
	stroke_bezier({width/2,height/2},{width/2-.01,0},{width/2,-height/2},stroke,paint)
	stroke_bezier({width/2,-height/2},{width*.75,-height/2+.01},{width,-height/2},stroke,paint)
	stroke_bezier({width,-height/2},{width-.01,0},{width,0},stroke,paint)
end

function saw(width, height, stroke, paint)
	stroke_bezier({0,-height/2},{0.01,0},{0,height/2},stroke,paint)
	stroke_bezier({0,height/2},{width/2,-0.01},{width,-height/2},stroke,paint)
	--stroke_bezier({width,-height/2},{width,0},{width,0},stroke,paint)
end

function sawInv(width, height, stroke, paint)
	stroke_bezier({0,0},{0,-height/2},{0,-height/2},stroke,paint)
	stroke_bezier({0,-height/2},{width,height/2},{width,height/2},stroke,paint)
	stroke_bezier({width,height/2},{width,0},{width,0},stroke,paint)
end

function rdm(width, height, stroke, paint)
	stroke_bezier({0,0},{0,-height/4},{0,-height/4},stroke,paint)
	stroke_bezier({0,-height/4},{width/4,-height/4},{width/4,-height/4},stroke,paint)
	stroke_bezier({width/4,-height/4},{width/4,height/2},{width/4,height/2},stroke,paint)
	stroke_bezier({width/4,height/2},{width/2,height/2},{width/2,height/2},stroke,paint)
	stroke_bezier({width/2,height/2},{width/2,height/5},{width/2,height/5},stroke,paint)
	stroke_bezier({width/2,height/5},{width*.75,height/5},{width*.75,height/5},stroke,paint)
	stroke_bezier({width*.75,height/5},{width*.75,-height/2},{width*.75,-height/2},stroke,paint)
	stroke_bezier({width*.75,-height/2},{width,-height/2},{width,-height/2},stroke,paint)
	stroke_bezier({width,-height/2},{width,0},{width,0},stroke,paint)
end



x = 3
function wave(x, width, height, stroke, paint) 

--translate{0,50}
	
if x == 1 then 
return sine (width, height, stroke, paint) 
elseif x == 2 then
return triangle (width, height, stroke, paint)
end
end

w = math.floor(waveform)+1
--wave(w)
width = 15
height = 10
stroke = .7
save()
translate{18,15}
wave(w, width, height, stroke, green_dk)
restore()

   x D   < 0 ( $                                                                            ;                        x   @   @                 0   0     ?              C   =_UC                       t,   ,                   B  pAƄDVǀC
               (   (                       C                x       h < 8 0 (       $                                                              #                  h   8   8                       Q?  A  B     B               $   $                 ,cC%               4(   (                      RC                x       x(   (                 (       pC                x          abs(x/pi-1) (   (                  Cф                   Mod    Slider      @@0   0                          }QvC;!               <   <                   B  A8      A    @D  N                mod     \,   ,                   ?  pJDY1
               ,   ,                   ?  )C8wd	               D   D                   0   0     ?          A  4C  7!xB                             4   4                 $   $     ?                                 ,   ,                   B  Cа
               h8   8                 `roB(   o@C   _Nx               
   synced lvl  h @ < 4 ,       $           +                                                  #                  h   <   <                       =      C  A                  @(   (                 <   P|Tw$                   k   	   syncPulse          syncPulse >=1+k (   (                 4    C                   oct    x          x+oct   ,   ,                   A   Cl&ʨ	               04   4                 $   $     ?        };K
ғ                     $   $                 ÉD               $   $                 kCa6                (   (                 (   W\                x          floor(x * 3)    h , (                                                                                             h   (   (                 S^>};K
ғ               $   $                 #KFC7 C               ($   $                 d|CQyC               \$   $                 ^CC               $   $                 x-C`A               (   (                       B>                (   (                 ,    @  A                flip           flip>0?1:-1 X(   (                 0      HB             
   syncPhasor         syncPhasor < 1   (   (                       >                0   0                 $         AL+fD	                  sel $4   4                 $   $     ?         ^                                                         p,   ,                   \B  4  C   
               (   (                      C  =               @(   (                      C               t(   (                      4  C@               0   0                 r         i  	                0   0                 d       p  j  B	               @0   0                          i  -C	               +(   (                      j  C	                  0   $   $                  qAL               $   $                 ArCL               $   $                 pB!iCL               H$   $                 @EBz5CL               (   (                 (   
H(                x          tanh(x*2.3) ;,   ,                 XC   =IC                  a static lpf and a dynamic antialiasing lpf? probably not necessary, esp. from a dsp pov -- just choose a good setting for the anti-aliasing lpf.   ;,   ,                   IC   ]cB               "   derive sine and triangle waveforms  H<,   ,                 B   ϭC                  triangle core   H4   4                 $   $     ?           f                   P,   ,                          C
               $   $                 ]MC	               4   4                 $   $     ?          /  C                   ,   ,                    B        C
               $   $                 ]MC	               4   4                 $   $     ?                                   D0   0                 $         A    	                  flip    0   0                 $     B  A    
                  flop    ?,   ,                 ?C   |"N               5   short sync pulse summed with target triangle waveform   ?,   ,                 psC       C               (   derive short sync pulse from sync source    $   $                    B%               (   (                 H                     x       $$   $                    B%               @,   ,                 pC                        alternate sync and reverse  @,   ,                 ܘC    @  pB                  syncPulse = SYNC target + narrow pulse from SYNC source.

Compare to reference level:
syncPulse > refLevel ? sync : reverse (where reverse means reversing the direction of the waveform with -freq)
   A,   ,                 LC   lSHĲ                 1. the synced oscillator produces a triangle wave 
2. To this triangle waveform a narrow pulse from the syncing oscillator is added. 
3. The sum is compared to a reference level. If the sum exceeds this reference level, the synced oscillator is reset, or the triangle wave reversed. 

The probability of a syncronization event being created can be seen to be related to the amplitude of the syncing pulse as well as the amplitude of the triangle wave output of the synced oscillator.

If the syncing pulse has a low amplitude, then syncing will occur only if the syncing pulse happens very close in time to the peak of the triangle waveform. Otherwise no syncing will occur. 

At the other extreme, if the syncing pulse has a very large amplitude, then syncing will occur on every pulse, no matter what the phase of the triangle waveform. In this case, the sync action will be that of regular hard-sync. 

By adjusting the amplitude of the syncing pulse one can vary the sync effect from soft to hard.   (F,   ,                 C   SŲC                  From Nord Modular archives, courtesy of Rudiger Meyer

This soft-sync technique was used in the RMS (Rivera Music Systems) synthesizer as well as in the Wiard synthesizers.    (   (                 h T;ğV                x       $   $                 *(               P(   (                        >               x{4   4                   lB A?/C&Ż.               (   (                        =               (   (                 l      4C                o       L(   (                 (      C                o          2^o*440 @,   ,                   B     C  B	               <   <                    A   A4     B  p     C  BN                oct       -- HSV to RGB
function hsv(h,s,v)
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end

local function octLight(v,y)
	
	local octh = ((v+5)/10)
	local h=(1-octh)*.7
	local s=1
	
	local octv=(v+5)-math.floor(v+5)
	local v=octv*.9+.1
	local r,g,b = hsv(h,s,v)
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	fill_circle({5,y},9,color_paint{.05,.05,.05,.18})
	fill_circle({5,y},5,color_paint{.05,.05,.05,1})
	
	fill_circle({5,y},9,halo)
	fill_circle({5,y},5,paint)
	
	translate{1.25,.8}
	text("O", theme.text)
	end
	
		
octLight(oct,5) D   D                 D   0   0     ?            A   6  C                      1/oct meter h < 8 0 (                   '                                                                     h   8   8                    U?     A  C.               l'D   |  |                  C  pBt  `  `  ;?D  C  6  # SubSync VCO
## A Subharmonic SoftSync VCO

A soft-sync VCO in which the synced waveform is reversed following trigger points derived from both the syncing and synced oscillators. This results in a form of soft sync in which the nodes of a subharmonic series (in relation to the syncing oscillator) are brought into focus without the root syncing pitch being present (as is the case with regular hard and soft forms of syncing). 
Since the ‘root’ isn’t directly present in the sound a second oscillator, which can set to different octaves within the sync range, can be mixed in to fill out its place.  

### Controls 

- SoftSync Slider – alters the frequency of the synced oscillator, i.e. the position within the synced sweep.
- Oct Button – selects the octave of the ‘root’ oscillator that can be mixed in. (See note below.)
- Root knob – adjusts the level of the ‘root’ oscillator.
- Oversampling Button – selects 1, 2, or 4x oversampling.   

### Ports

- Modulation input for the subSync slider – the incoming modulation value is added/subtracted to the value set by the slider 
- O – pitch input in 1/oct scaling. This is the standard in Audulus, where 0 or no cable attached sends 440 Hz to the oscillators.
- A – audio output. Sync (‘root’) and synced oscillators, summed.

### Notes
 
The range of subharmonics in a full sweep covers 3 octaves – the (sub)harmonic nodes 1 – 8.  

Strictly speaking the sync (root) is at the top of the sweep (since we are dealing with subharmonics), but since seems more intuitive to have the incoming octave note (from one’s sequencer/keyboard etc. ) at the bottom of the sweep, an internal offset has been implemented so that the subharmonics are calculated (down) from 3 octaves up. 

That way with the sync slider set right to the bottom one hears the pitch one would expect to hear – and then the other nodes appear as one moves up. With regular hard sync the available nodes are more dense at the top of the sweep (following the harmonic series), whereas here they’re more dense at the bottom (following the subharmonic mirroring).

*Independently of the above* further timbral possibilities are opened up by mixing in a ‘root’ oscillator that can be placed at any of the octaves within the range. Again it seems most intuitive to start at the bottom with ‘0’ corresponding to the incoming ‘octave’ signal, and then the overall timbre can be altered by changing the octave of the mixed in oscillator – like stops on an organ. 

The waveforms are derived from the phasor node, with 2 – 4x oversampling and light anti-aliasing using a one-pole low pass filter. 

### Version History

- 1.0 – 19.04.2024: Added ‘tanh’ waveform graphic 
- 0.9.1 – 07.04.2024: Improved gain controls for the root oscillator 
- 0.9 – 30.03.2024: Jerry Smith and Rudiger Meyer              B                                                                                   
    !  .  /  0  1  3  C  T  U  Y  Z  \  ]  ^  _  c  
  
  
  
  /  0  1  Z     SubSync VCO ,   ,                    A   A  4  C	               ,   ,                   HB   A  p  C
               D  <   <                   B  B8     B  RC   O.Ħ߉DN                input         
-- knob pointer

input = math.floor(input*12)/12

stroke_circle({canvas_width/2, canvas_height/2}, 34, 3, color_paint{.12,.12,.12,1})

stroke_circle({canvas_width/2, canvas_height/2}, 34, 2, color_paint(theme.grooves))

rotation = input * math.pi - math.pi/2
aperture = input * math.pi


--arc_paint = linear_gradient({0,0}, {0,canvas_height}, {1, 0, .384, .5}, {0, .831, 1, .5})
arc_paint = linear_gradient({10,0}, {0,canvas_height}, theme.redHighlightDark, theme.azureHighlightDark)
stroke_arc({canvas_width/2, canvas_height/2}, 34, 2, rotation, aperture, arc_paint)


local function pointer(x, y, rot)
size = 3
color = color_paint(theme.text)
save()
translate{canvas_width/2, canvas_height/2}
	save()
	translate{x,y}
		save()
		rotate(rot)
		move_to{-size,size}
		line_to{size,size}
		line_to{0,0}
		line_to{-size,size}
--		fill(color)
		restore()
	restore()
restore()
end


local radius = 40
     


px = radius * math.cos(input * math.pi*2 + math.pi/2)
py = -radius * math.sin(input * math.pi*2 + math.pi/2)
pointer(px, py, -input * math.pi*2)




  ;0   0                 $     pA  pAPD 	                  root    `;0   0                 $     pA  4B&ND,FiB	                  scl R|D   (  (                      A  B(    @  B   raDq<N   (  Note = 8
Scales = {}
Scales[1] = {}
Scales[1]["label"] = "Chromatic"
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[2] = {}
Scales[2]["label"] = "Ionian"
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[3] = {}
Scales[3]["label"] = "Dorian"
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[4] = {}
Scales[4]["label"] = "Phrygian"
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[5] = {}
Scales[5]["label"] = "Lydian"
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[6] = {}
Scales[6]["label"] = "Mixolydian"
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[7] = {}
Scales[7]["label"] = "Aeolian"
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[8] = {}
Scales[8]["label"] = "Locrian"
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[9] = {}
Scales[9]["label"] = "1/2 Diminished"
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 5
Scales[9]["notes"][5] = 6
Scales[9]["notes"][6] = 8
Scales[9]["notes"][7] = 10
Scales[10] = {}
Scales[10]["label"] = "Spanish"
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 1
Scales[10]["notes"][3] = 4
Scales[10]["notes"][4] = 5
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 8
Scales[10]["notes"][7] = 10
Scales[11] = {}
Scales[11]["label"] = "Gypsy Major/Arab"
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 1
Scales[11]["notes"][3] = 4
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 7
Scales[11]["notes"][6] = 8
Scales[11]["notes"][7] = 11
Scales[12] = {}
Scales[12]["label"] = "Gypsy Minor"
Scales[12]["notes"] = {}
Scales[12]["notes"][1] = 0
Scales[12]["notes"][2] = 2
Scales[12]["notes"][3] = 3
Scales[12]["notes"][4] = 6
Scales[12]["notes"][5] = 7
Scales[12]["notes"][6] = 8
Scales[12]["notes"][7] = 11
Scales[13] = {}
Scales[13]["label"] = "Harmonic Minor"
Scales[13]["notes"] = {}
Scales[13]["notes"][1] = 0
Scales[13]["notes"][2] = 2
Scales[13]["notes"][3] = 3
Scales[13]["notes"][4] = 5
Scales[13]["notes"][5] = 7
Scales[13]["notes"][6] = 8
Scales[13]["notes"][7] = 11
Scales[14] = {}
Scales[14]["label"] = "Ukranian"
Scales[14]["notes"] = {}
Scales[14]["notes"][1] = 0
Scales[14]["notes"][2] = 2
Scales[14]["notes"][3] = 3
Scales[14]["notes"][4] = 6
Scales[14]["notes"][5] = 7
Scales[14]["notes"][6] = 8
Scales[14]["notes"][7] = 10
Scales[15] = {}
Scales[15]["label"] = "Blues Major"
Scales[15]["notes"] = {}
Scales[15]["notes"][1] = 0
Scales[15]["notes"][2] = 2
Scales[15]["notes"][3] = 3
Scales[15]["notes"][4] = 4
Scales[15]["notes"][5] = 7
Scales[15]["notes"][6] = 9
Scales[16] = {}
Scales[16]["label"] = "Blues Minor"
Scales[16]["notes"] = {}
Scales[16]["notes"][1] = 0
Scales[16]["notes"][2] = 3
Scales[16]["notes"][3] = 5
Scales[16]["notes"][4] = 6
Scales[16]["notes"][5] = 7
Scales[16]["notes"][6] = 10
Scales[17] = {}
Scales[17]["label"] = "Major Pentatonic"
Scales[17]["notes"] = {}
Scales[17]["notes"][1] = 0
Scales[17]["notes"][2] = 2
Scales[17]["notes"][3] = 4
Scales[17]["notes"][4] = 7
Scales[17]["notes"][5] = 9
Scales[18] = {}
Scales[18]["label"] = "Susp/Egyptian P"
Scales[18]["notes"] = {}
Scales[18]["notes"][1] = 0
Scales[18]["notes"][2] = 2
Scales[18]["notes"][3] = 5
Scales[18]["notes"][4] = 7
Scales[18]["notes"][5] = 10
Scales[19] = {}
Scales[19]["label"] = "Minor Blues P"
Scales[19]["notes"] = {}
Scales[19]["notes"][1] = 0
Scales[19]["notes"][2] = 3
Scales[19]["notes"][3] = 5
Scales[19]["notes"][4] = 8
Scales[19]["notes"][5] = 10
Scales[20] = {}
Scales[20]["label"] = "Major Blues/Yo"
Scales[20]["notes"] = {}
Scales[20]["notes"][1] = 0
Scales[20]["notes"][2] = 2
Scales[20]["notes"][3] = 5
Scales[20]["notes"][4] = 7
Scales[20]["notes"][5] = 9
Scales[21] = {}
Scales[21]["label"] = "Minor Pentatonic"
Scales[21]["notes"] = {}
Scales[21]["notes"][1] = 0
Scales[21]["notes"][2] = 3
Scales[21]["notes"][3] = 5
Scales[21]["notes"][4] = 7
Scales[21]["notes"][5] = 10
Scales[22] = {}
Scales[22]["label"] = "Ryūkyū"
Scales[22]["notes"] = {}
Scales[22]["notes"][1] = 0
Scales[22]["notes"][2] = 4
Scales[22]["notes"][3] = 5
Scales[22]["notes"][4] = 7
Scales[22]["notes"][5] = 11
Scales[23] = {}
Scales[23]["label"] = "In Pentatonic"
Scales[23]["notes"] = {}
Scales[23]["notes"][1] = 0
Scales[23]["notes"][2] = 1
Scales[23]["notes"][3] = 5
Scales[23]["notes"][4] = 7
Scales[23]["notes"][5] = 8
Scales[24] = {}
Scales[24]["label"] = "Hirajoshi"
Scales[24]["notes"] = {}
Scales[24]["notes"][1] = 0
Scales[24]["notes"][2] = 2
Scales[24]["notes"][3] = 3
Scales[24]["notes"][4] = 7
Scales[24]["notes"][5] = 8
Scales[25] = {}
Scales[25]["label"] = "Pelog"
Scales[25]["notes"] = {}
Scales[25]["notes"][1] = 0
Scales[25]["notes"][2] = 1
Scales[25]["notes"][3] = 3
Scales[25]["notes"][4] = 7
Scales[25]["notes"][5] = 8
Scales[26] = {}
Scales[26]["label"] = "Whole Tone"
Scales[26]["notes"] = {}
Scales[26]["notes"][1] = 0
Scales[26]["notes"][2] = 2
Scales[26]["notes"][3] = 4
Scales[26]["notes"][4] = 6
Scales[26]["notes"][5] = 8
Scales[26]["notes"][6] = 10
Scales[27] = {}
Scales[27]["label"] = "Octatonic"
Scales[27]["notes"] = {}
Scales[27]["notes"][1] = 0
Scales[27]["notes"][2] = 1
Scales[27]["notes"][3] = 3
Scales[27]["notes"][4] = 4
Scales[27]["notes"][5] = 6
Scales[27]["notes"][6] = 7
Scales[27]["notes"][7] = 9
Scales[27]["notes"][8] = 10
Scales[28] = {}
Scales[28]["label"] = "Messiaen 3rd"
Scales[28]["notes"] = {}
Scales[28]["notes"][1] = 0
Scales[28]["notes"][2] = 2
Scales[28]["notes"][3] = 3
Scales[28]["notes"][4] = 4
Scales[28]["notes"][5] = 6
Scales[28]["notes"][6] = 7
Scales[28]["notes"][7] = 8
Scales[28]["notes"][8] = 10
Scales[28]["notes"][9] = 11
Scales[29] = {}
Scales[29]["label"] = "Messiaen 4th"
Scales[29]["notes"] = {}
Scales[29]["notes"][1] = 0
Scales[29]["notes"][2] = 1
Scales[29]["notes"][3] = 2
Scales[29]["notes"][4] = 5
Scales[29]["notes"][5] = 6
Scales[29]["notes"][6] = 7
Scales[29]["notes"][7] = 8
Scales[29]["notes"][8] = 11
Scales[30] = {}
Scales[30]["label"] = "Messiaen 5th"
Scales[30]["notes"] = {}
Scales[30]["notes"][1] = 0
Scales[30]["notes"][2] = 1
Scales[30]["notes"][3] = 5
Scales[30]["notes"][4] = 6
Scales[30]["notes"][5] = 7
Scales[30]["notes"][6] = 11
Scales[31] = {}
Scales[31]["label"] = "Messiaen 6th"
Scales[31]["notes"] = {}
Scales[31]["notes"][1] = 0
Scales[31]["notes"][2] = 2
Scales[31]["notes"][3] = 4
Scales[31]["notes"][4] = 5
Scales[31]["notes"][5] = 6
Scales[31]["notes"][6] = 8
Scales[31]["notes"][7] = 10
Scales[31]["notes"][8] = 11
Scales[32] = {}
Scales[32]["label"] = "Messiaen 7th"
Scales[32]["notes"] = {}
Scales[32]["notes"][1] = 0
Scales[32]["notes"][2] = 1
Scales[32]["notes"][3] = 2
Scales[32]["notes"][4] = 3
Scales[32]["notes"][5] = 5
Scales[32]["notes"][6] = 6
Scales[32]["notes"][7] = 7
Scales[32]["notes"][8] = 8
Scales[32]["notes"][9] = 9
Scales[32]["notes"][10] = 11
Scales[33] = {}
Scales[33]["label"] = "Min 3rd"
Scales[33]["notes"] = {}
Scales[33]["notes"][1] = 0
Scales[33]["notes"][2] = 3
Scales[33]["notes"][3] = 6
Scales[33]["notes"][4] = 9
Scales[34] = {}
Scales[34]["label"] = "Maj 3rd"
Scales[34]["notes"] = {}
Scales[34]["notes"][1] = 0
Scales[34]["notes"][2] = 4
Scales[34]["notes"][3] = 8
Scales[35] = {}
Scales[35]["label"] = "Fourth"
Scales[35]["notes"] = {}
Scales[35]["notes"][1] = 0
Scales[35]["notes"][2] = 5
Scales[36] = {}
Scales[36]["label"] = "Fifth"
Scales[36]["notes"] = {}
Scales[36]["notes"][1] = 0
Scales[36]["notes"][2] = 7
canvas_height = 10
canvas_width = 110
currentNote = 6
currentRoot = 0
currentScale = 12
fill_color = {}
fill_color[1] = 0
fill_color[2] = 0.608
fill_color[3] = 0.729
fill_color[4] = 0.4
h2 = 5
highlight = {}
highlight[0] = 1
highlight[2] = 1
highlight[3] = 1
highlight[6] = 1
highlight[7] = 1
highlight[8] = 1
highlight[11] = 1
iLength = 12
input = 0
kern_table = {}
kern_table[1] = 0
kern_table[2] = 0
kern_table[3] = 0.5
kern_table[4] = 0.5
kern_table[5] = 0
kern_table[6] = 0.5
kern_table[7] = 0
kern_table[8] = 0.5
kern_table[9] = 0.5
kern_table[10] = 0
kern_table[11] = 0.5
kern_table[12] = 0
largeRadius = 34
max = {}
max[1] = 66.263999938965
max[2] = 8.3999996185303
min = {}
min[1] = 0.83999997377396
min[2] = -2.1240000724792
n = 12
noteLabel = {}
noteLabel[1] = "A"
noteLabel[2] = "#"
noteLabel[3] = "B"
noteLabel[4] = "C"
noteLabel[5] = "#"
noteLabel[6] = "D"
noteLabel[7] = "#"
noteLabel[8] = "E"
noteLabel[9] = "F"
noteLabel[10] = "#"
noteLabel[11] = "G"
noteLabel[12] = "#"
noteTranspose = 15
octave = 24
qNote = 0.66666668653488
radius = 7.5
root = 0
rootId = 1
rootName = {}
rootName[1] = "A"
rootName[2] = "A#"
rootName[3] = "B"
rootName[4] = "C"
rootName[5] = "C#"
rootName[6] = "D"
rootName[7] = "D#"
rootName[8] = "E"
rootName[9] = "F"
rootName[10] = "F#"
rootName[11] = "G"
rootName[12] = "G#"
scl = 12
shift_text = 0
stroke = 0.5
stroke_color = {}
stroke_color[1] = 0.8
stroke_color[2] = 0.8
stroke_color[3] = 0.8
stroke_color[4] = 1
text_color = {}
text_color[1] = 0.839
text_color[2] = 0.839
text_color[3] = 0.839
text_color[4] = 1
txt = "#"
w2 = 55
x = -17
y = 29.444863728671
                     root       scl    qNote       	  
-- Quantizer visualizer
-- Jerry Smith :: 2023
-- Expanded scales by Rudiger Meier

-------------------------------------------------------------
Scales = {
{ label = "Chromatic", 	    	notes = { 0,1,2,3,4,5,6,7,8,9,10,11 } },
{ label = "Ionian", 	    	notes = { 0,2,4,5,7,9,11 } },
{ label = "Dorian", 	    	notes = { 0,2,3,5,7,9,10 } },
{ label = "Phrygian", 	    	notes = { 0,1,3,5,7,8,10 } },
{ label = "Lydian", 	    	notes = { 0,2,4,6,7,9,11 } },
{ label = "Mixolydian",     	notes = { 0,2,4,5,7,9,10 } },
{ label = "Aeolian", 	    	notes = { 0,2,3,5,7,8,10 } },
{ label = "Locrian", 	    	notes = { 0,1,3,5,6,8,10 } },
{ label = "1/2 Diminished", 	notes = { 0,2,3,5,6,8,10 } },
{ label = "Spanish", 	    	notes = { 0,1,4,5,7,8,10 } },
{ label = "Gypsy Major/Arab", 	notes = { 0,1,4,5,7,8,11 } },
{ label = "Gypsy Minor", 	    notes = { 0,2,3,6,7,8,11 } },
{ label = "Harmonic Minor", 	notes = { 0,2,3,5,7,8,11 } },
{ label = "Ukranian", 	    	notes = { 0,2,3,6,7,8,10 } },
{ label = "Blues Major", 	    notes = { 0,2,3,4,7,9 } },
{ label = "Blues Minor", 	    notes = { 0,3,5,6,7,10 } },
{ label = "Major Pentatonic", 	notes = { 0,2,4,7,9 } },
{ label = "Susp/Egyptian P",	notes = { 0,2,5,7,10 } },
{ label = "Minor Blues P", 		notes = { 0,3,5,8,10 } },
{ label = "Major Blues/Yo", 	notes = { 0,2,5,7,9 } },
{ label = "Minor Pentatonic", 	notes = { 0,3,5,7,10 } },
{ label = "Ryūkyū", 	        notes = { 0,4,5,7,11 } },
{ label = "In Pentatonic", 	    notes = { 0,1,5,7,8 } },
{ label = "Hirajoshi", 	    	notes = { 0,2,3,7,8 } },
{ label = "Pelog", 	        	notes = { 0,1,3,7,8 } },
{ label = "Whole Tone", 	    notes = { 0,2,4,6,8,10 } },
{ label = "Octatonic", 	    	notes = { 0,1,3,4,6,7,9,10 } },
{ label = "Messiaen 3rd", 		notes = { 0,2,3,4,6,7,8,10,11 } },
{ label = "Messiaen 4th", 		notes = { 0,1,2,5,6,7,8,11 } },
{ label = "Messiaen 5th", 		notes = { 0,1,5,6,7,11 } },
{ label = "Messiaen 6th", 		notes = { 0,2,4,5,6,8,10,11 } },
{ label = "Messiaen 7th", 		notes = { 0,1,2,3,5,6,7,8,9,11 } },
{ label = "Min 3rd", 	    	notes = { 0,3,6,9 } },
{ label = "Maj 3rd", 	    	notes = { 0,4,8 } },
{ label = "Fourth", 		    notes = { 0,5 } },
{ label = "Fifth", 		    	notes = { 0,7 } },
}
--------------------------------------------------------


rootName = { "A","A#","B","C","C#","D","D#","E","F","F#","G","G#" }

currentRoot = root
currentScale = math.max(scl, 1)
-- currentScale = math.floor(scl * (#Scales - 0.01)) + 1

Note = math.floor((qNote + .01) * 12) -- compensate for canvas node rounding weirdness

-- graphics for a single note
local function draw_note(x, y, txt, shift_text, radius, stroke, fill_color, stroke_color, text_color)
	save()
	translate{x,y}
		save()
		
		fill_circle( {0, 0}, radius, color_paint(fill_color))
		stroke_circle( {0, 0}, radius, stroke, color_paint(stroke_color))
		
			save()
			min, max = text_bounds(txt)
			translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
			text(txt, text_color)
			restore()
		
		restore()
	restore()
end


------- GRAPHICS --------
w2 = canvas_width/2
h2 = canvas_height/2

save()
translate{w2,h2+10}

noteLabel = { "A","#","B","C","#","D","#","E","F","#","G","#" }
iLength = 12


for i = 0, iLength-1 do

	-- circle color
	if i == Note%12 then 
		fill_color = {.8,.8,.8,1}
	else 
		fill_color = {0, 0.608, 0.729, .4}
	end

		
	-- highlight notes in current scale		
	highlight = {}
	highlight[i] = 0
		for _, i in pairs(Scales[currentScale].notes) do
			highlight[(i+currentRoot)%12] = 1
		end
	
		if i == Note%12 then 
			text_color = {0,0,0,1}
			stroke_color = {.8,.8,.8,1}
		elseif highlight[i] == 1 then 	
			text_color = theme.text
			stroke_color = {.8,.8,.8,1}
		elseif highlight[i] == 0 then
			text_color = {0,0,0,1}
			stroke_color = theme.grooves
		end

	-- parameters
	radius = 7.5
	largeRadius = 34
	stroke = .5
	txt = noteLabel[i+1]
	x = largeRadius*math.cos(i/iLength*math.pi*2-math.pi/2) 
	y = -largeRadius*math.sin(i/iLength*math.pi*2-math.pi/2)
	
	kern_table = { 0,0,.5,.5,0,.5,0,.5,.5,0,.5,0 }
	shift_text = kern_table[i+1]

	--draw_note(x, y, txt, shift_text, radius, stroke, fill_color, stroke_color, text_color)

end
restore()

-- TEXT DISPLAY --
save()
translate{w2, 0}
	save()
	scale{1.2, 1.2}
	min, max = text_bounds(Scales[currentScale].label)
	translate{-(min[1] + max[1])/2, 0}
	text(Scales[currentScale].label, theme.text) 
	restore()
restore()

   ,   \                       ߉D)sO      $            Root       Scale      qNote      0                root       scl    octave     input         -- Quantizer
-- Jerry Smith :: 2023
-- Expanded scales by Rudiger Meier


-------------------------------------------------------------
Scales = {
{ 	label = "Chromatic", 	    
	notes = { 0,1,2,3,4,5,6,7,8,9,10,11 }, 	
	map = { 0,1,2,3,4,5,6,7,8,9,10,11 } 
},
{ 	label = "Ionian", 	    
	notes = { 0,2,4,5,7,9,11 },				
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Dorian", 	    
	notes = { 0,2,3,5,7,9,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Phrygian", 	    
	notes = { 0,1,3,5,7,8,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Lydian", 	    
	notes = { 0,2,4,6,7,9,11 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Mixolydian",     
	notes = { 0,2,4,5,7,9,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Aeolian", 	    
	notes = { 0,2,3,5,7,8,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Locrian", 	    
	notes = { 0,1,3,5,6,8,10 }, 			
	map = { 0,1,1,2,2,3,4,4,5,5,6,6 } 
},
{ 	label = "1/2 Dimin", 	    
	notes = { 0,2,3,5,6,8,10 }, 			
	map = { 0,1,1,2,2,3,4,4,5,5,6,6 } 
},
{ 	label = "Spanish", 	    
	notes = { 0,1,4,5,7,8,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Gyp Maj/Arab", 	
	notes = { 0,1,4,5,7,8,11 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Gypsy Minor", 	
	notes = { 0,2,3,6,7,8,11 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Harmonic Min", 	
	notes = { 0,2,3,5,7,8,11 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Ukranian", 	    
	notes = { 0,2,3,6,7,8,10 }, 			
	map = { 0,1,1,2,2,3,3,4,5,5,6,6 } 
},
{ 	label = "Blues Maj", 	    
	notes = { 0,2,3,4,7,9 }, 				
	map = { 0,1,1,2,3,3,4,4,5,5,6,6 } 
},
{ 	label = "Blues Min", 	    
	notes = { 0,3,5,6,7,10 }, 				
	map = { 0,0,1,1,1,2,3,4,4,5,5,5 } 
}, 
{ 	label = "Maj Penta", -- 17 remap note 12 up an octave	    
	notes = { 0,2,4,7,9 }, 					
	map = { 0,1,1,2,2,2,3,3,4,4,4,0 } 
},
{ 	label = "Susp/Egyp P",	
	notes = { 0,2,5,7,10 }, 				
	map = { 0,1,1,1,2,2,2,3,3,4,4,4 } 
},
{ 	label = "Min Blues P", -- 19 remap note 12
	notes = { 0,3,5,8,10 }, 				
	map = { 0,0,1,1,1,2,2,3,3,3,4,0 } 
},
{ 	label = "Maj Blues/Yo", -- 20 remap note 12 	
	notes = { 0,2,5,7,9 }, 					
	map = { 0,1,1,1,2,2,2,3,4,4,4,0 } 
},
{ 	label = "Min Penta", 	    
	notes = { 0,3,5,7,10 }, 				
	map = { 0,0,1,1,1,2,2,3,3,4,4,4 } 
},
{ 	label = "Ryūkyū", 	    
	notes = { 0,4,5,7,11 }, 				
	map = { 0,0,1,1,1,2,2,3,3,4,4,4 } 
},
{ 	label = "In Penta", -- 23 remap note 12	    
	notes = { 0,1,5,7,8 }, 					
	map = { 0,1,1,1,2,2,2,3,4,4,4,0 } 
},
{ 	label = "Hirajoshi", -- 24 remap note 12	    
	notes = { 0,2,3,7,8 }, 					
	map = { 0,1,1,2,2,2,3,3,4,4,4,0 } 
}, 
{ 	label = "Pelog", -- 25 remap note 12	        
	notes = { 0,1,3,7,8 }, 					
	map = { 0,1,1,2,2,2,3,3,4,4,4,0 } 
}, 
{ 	label = "Whole Tone", 	
	notes = { 0,2,4,6,8,10 }, 				
	map = { 0,0,1,1,2,2,3,3,4,4,5,5 } 
},
{ 	label = "Octatonic", 	    
	notes = { 0,1,3,4,6,7,9,10 }, 			
	map = { 0,1,1,2,3,4,4,5,6,6,7,7 } 
},
{ 	label = "Messiaen 3rd", 	
	notes = { 0,2,3,4,6,7,8,10,11 }, 		
	map = { 0,1,1,2,3,4,4,5,6,6,7,8 } 
},
{ 	label = "Messiaen 4th", 	
	notes = { 0,1,2,5,6,7,8,11 }, 			
	map = { 0,1,2,2,3,3,4,5,6,6,7,7 } 
},
{ 	label = "Messiaen 5th", 	
	notes = { 0,1,5,6,7,11 },	 			
	map = { 0,1,1,2,2,2,3,4,4,5,5,5 } 
},
{ 	label = "Messiaen 6th", 	
	notes = { 0,2,4,5,6,8,10,11 }, 			
	map = { 0,1,1,2,2,3,4,4,5,5,6,7 } 
},
{ 	label = "Messiaen 7th", 	
	notes = { 0,1,2,3,5,6,7,8,9,11 }, 		
	map = { 0,1,2,3,3,4,5,6,7,8,9,9 } 
},
{ 	label = "Min 3rd", -- 33 remap note 12 	    
	notes = { 0,3,6,9 }, 					
	map = { 0,0,1,1,1,2,2,2,3,3,3,0 } 
},
{ 	label = "Maj 3rd", -- 34 remap note 12	    
	notes = { 0,4,8 }, 						
	map = { 0,0,1,1,1,1,2,2,2,2,0,0 } 
}, 
{ 	label = "Fourth", 		
	notes = { 0,5 }, 						
	map = { 0,0,0,1,1,1,1,1,2,2,2,2 } 
},
{ 	label = "Fifth", -- 36 remap note 12		    
	notes = { 0,7 }, 						
	map = { 0,0,0,0,1,1,1,1,1,1,1,0 } 
}, 
}
--------------------------------------------------------

function fract(x) return x - math.floor(x) end

function process(frames)
    local currentRoot = math.floor(root[1] * 11.99)
    local currentScale = math.floor(scl[1] * (#Scales - 0.01)) + 1
    local currentMapping = math.floor(fract(input[1]) * 11.99) + 1
    
    local qMap = Scales[currentScale].map[currentMapping] + 1
    local qScale = Scales[currentScale].notes[qMap]
	
	-- Remap the 12th note up an octave for the scales in this list
    local transposeNote12 = { 17, 19, 20, 23, 24, 25, 33, 34, 36 }
    for _, scale in ipairs(transposeNote12) do
        if currentScale == scale and currentMapping == 12 then
            qScale = qScale + 12
            break
        end
    end
    	
	local quantizedNote = (math.floor(input[1] + octave[1]) * 12 + currentRoot + qScale) / 12
	
    fill(qNote, quantizedNote)
    fill(Root, currentRoot)
    fill(Scale, currentScale)
end ,   ,                  C   KPDB               q   Canvas node list of scales need to match the Scales in the Scales module in order for the display to be accurate.   t,   ,                   ]C    D  C               7  Note Quantizer

Constrain input to the selected musical scale. General purpose note quantizer using the Canvas node to display scale and root.

Accepts any input in 1v/octave CV range (for example, -5 to 5 is a 10 octave range) and applies a scale to it. Compare to something like the Intellijel Scales module.
 TI,   ,                   pA  pqLD`C	               I,   ,                   B  pDB
               x L   D 8 0 , (                                                                  C       B                      $ x   H                             ?          B C    A  WD  Quantizer Tile - v2.0

— — — 


- Controls - 

Root Note knob - Controls and displays the root note of the scale

scl knob - Switches between scales (detailed below).


- Inputs -

O - Octave signal to be quantized


- Outputs - 

O - Quantized octave signal


— — — 


The Quantizer Tile takes an octave input and snaps it to one of 36 scales or 4 interval/chord patterns.

1. Chromatic    { 0,1,2,3,4,5,6,7,8,9,10,11 }
2. Ionian    { 0,2,4,5,7,9,11 }
3. Dorian    { 0,2,3,5,7,9,10 }
4. Phrygian    { 0,1,3,5,7,8,10 }
5. Lydian    { 0,2,4,6,7,9,11 }
6. Mixolydian    { 0,2,4,5,7,9,10 }
7. Aeolian    { 0,2,3,5,7,8,10 }
8. Locrian    { 0,1,3,5,6,8,10 }
9. 1/2 Diminished    { 0,2,3,5,6,8,10 }
10. Spanish    { 0,1,4,5,7,8,10 }
11. Gyp Maj/Arabic    { 0,1,4,5,7,8,11 }
12. Gypsy Minor    { 0,2,3,6,7,8,11 } }
13. Harmonic Minor    { 0,2,3,5,7,8,11 }
14. Ukranian    { 0,2,3,6,7,8,10 }
15. Blues Maj    { 0,2,3,4,7,9 }
16. Blues Min    { 0,3,5,6,7,10 }
17. Maj Pentatonic    { 0,2,4,7,9 }
18. Susp/Egyptian Penta    { 0,2,5,7,10 }
19. Min Blues Penta    { 0,3,5,8,10 }
20. Maj Blues/Yo Penta    { 0,2,5,7,9 }
21. Min Pentatonic    { 0,3,5,7,10 }
22. Ryūkyū    { 0,4,5,7,11 }
23. In Pent    { 0,1,5,7,8 }
24. Hirajoshi    { 0,2,3,7,8 }
25. Pelog    { 0,1,3,7,8 }
26. Whole Tone    { 0,2,4,6,8,10 }
27. Octatonic    { 0,1,3,4,6,7,9,10 }
28. Messiaen 3rd    { 0,2,3,4,6,7,8,10,11 }
29. Messiaen 4th    { 0,1,2,5,6,7,8,11 }
30. Messiaen 5th    { 0,1,5,6,7,11 }
31. Messiaen 6th    { 0,2,4,5,6,8,10,11 }
32. Messiaen 7th    { 0,1,2,3,5,6,7,8,9,11 }
33. Min 3rd    { 0,3,6,9 }
34. Maj 3rd    { 0,4,8 }
35. Fourth    { 0,5 }
36. Fifth    { 0,7 }




The Root Note knob selects the root note of the scale, and scl or Scale knob switches between the scales.

Typically this module will be wired between a sequencer or some other modulation source and a VCO.


— — — 

Version History

1.0 - 2022.26.06 - Created
2.0 - 2023.11.14 - DSP node version                                   	   Quantizer   J4   4                 $   $     ?        \NCGC                   R,   ,                    B     \C  
               `$   $                   C  	                4   4                 ]   @     瞖CsB               ؁$   $                   bC  XB               S,   ,                         C  TB	               ܍D   D                  0   0     ?          HC   B  [\D                     TT,   ,                   HC   BfD
               (                       ϬDnO      P   <   (            active  
   oldestNote  
   lowestNote     highestNote 
   newestNote     X   L   @   4   (               g4     g3     g2     g1     p4     p3     p2     p1        
currNoteId = 1
inputHistory = {}
active = 0

function updateActiveGate()
    for j = 1, 4 do
        if gates[j][1] == 1 then
            fill(active, 1)
            return
        end
    end
    fill(active, 0)
end

function process(frames)
    inputs = {p1, p2, p3, p4}
    gates = {g1, g2, g3, g4}
   
    local noteChanged = false
    
    for j = 1, 4 do
        if inputs[j][1] ~= inputHistory[j] then
            currNoteId = j
            noteChanged = true
            inputHistory[j] = inputs[j][1]        
        end
    end
     
    if noteChanged then
        fill(newestNote, inputs[currNoteId][1])
    end
    
    local highest = inputs[currNoteId][1]
    local lowest = inputs[currNoteId][1]

    for j = 1, 4 do
        local note = inputs[j][1]
        if note > highest then
            highest = note
        end
        if note < lowest then
            lowest = note
        end
    end
    
    fill(highestNote, highest)
    fill(lowestNote, lowest)
    
    
    updateActiveGate()
    lastActiveGate = active[1]
end
 Q4   4                 $   $     ?        D`A                           Z,   ,                   B  AY  C
               4   4                    ?  B    C  C               X4   4                    u>  B  @  C  C               4   4                    %?  B  B  C  D               4   4                    =  B  B  C  D               (   (                    /!WCB                ,   ,                  9C     D  \D               @   Resets if all notes are released.

More for midi keyboard input.    T,   |                       !lDԡrCO      @   ,         
   oldestNote  
   lowestNote     highestNote 
   newestNote     (               p4     p3     p2     p1        
currNoteId = 1
inputHistory = {}

function process(frames)
    inputs = {p1, p2, p3, p4}
   
    local noteChanged = false
    
    for j = 1, 4 do
        if inputs[j][1] ~= inputHistory[j] then
            currNoteId = j
            noteChanged = true
            inputHistory[j] = inputs[j][1]        
        end
    end
     
    if noteChanged then
        fill(newestNote, inputs[currNoteId][1])
    end
    
    local highest = inputs[currNoteId][1]
    local lowest = inputs[currNoteId][1]

    for j = 1, 4 do
        local note = inputs[j][1]
        if note > highest then
            highest = note
        end
        if note < lowest then
            lowest = note
        end
    end
    
    fill(highestNote, highest)
    fill(lowestNote, lowest)
end
  <0   0                 $     C   Dl.D
                  oldest  0   0                 $     C   qxDg?D
                  lowest  Ԣ0   0                 $     C  AMDOD
                  highest $   $                 ܯDaC               `,   ,                   C    D  C               @8   8                   A  A  B   A   QDC               أ0   0                 $     C    D  C
                  active  h 0 , $                                                                                           h   ,                          %DxNDO      `   L   8   $            active     index   
   oldestNote  
   lowestNote     highestNote 
   newestNote     X   L   @   4   (               g4     g3     g2     g1     p4     p3     p2     p1      (  
-- Tracks note activity from midi keyboard node and outputs newest, higest, lowest and oldest

voiceStack = {}
unsortedVoiceStack = {}
currentVoice = 1
prevGate = {}
active = 0
lastActiveGate = 0
highestNoteValue = -10
lowestNoteValue = 10
prevReset = 0
oldestNoteValue = 0
prevActive = 0


function updateVoiceStack(voice)
    table.insert(voiceStack, 1, voice)
    table.insert(unsortedVoiceStack, 1, voice)
    if #voiceStack > 4 then
        table.remove(voiceStack)
    end
    if #unsortedVoiceStack > 4 then
        table.remove(unsortedVoiceStack)
    end
    currentVoice = voice
end

function updateActiveGate()
    for j = 1, 4 do
        if gates[j][1] == 1 then
            fill(active, 1)
            return
        end
    end
    fill(active, 0)
end

function process(frames)
    if active[1] == 0 and prevActive == 1 then
        highestNoteValue = -10
        lowestNoteValue = 10
        if oldestNoteValue ~= 0 then
            oldestNoteValue = 0
        end
    end

    inputs = {p1, p2, p3, p4}
    gates = {g1, g2, g3, g4}

    local noteChanged = false
    local gateChanged = false

    for j = 1, 4 do
        if gates[j][1] == 1 and gates[j][1] ~= prevGate[j] then
            currGateId = j
            gateChanged = true
            break
        end
    end

    if gateChanged then
        updateVoiceStack(currGateId)
        
        if active[1] == 0 then
        	fill(newestNote, inputs[currGateId][1])
        	fill(highestNote, inputs[currGateId][1])
        	fill(lowestNote, inputs[currGateId][1])
            oldestNoteValue = inputs[currGateId][1]
        end
    end

    if gates[currentVoice][1] == 1 then
        fill(newestNote, inputs[currentVoice][1])
        fill(oldestNote, oldestNoteValue)
        
    else
        table.remove(unsortedVoiceStack, 1)
        if #unsortedVoiceStack > 0 then
            currentVoice = unsortedVoiceStack[1]
            fill(newestNote, inputs[currentVoice][1])
        end
        if #unsortedVoiceStack == 1 and active[1] == 0 then
            fill(oldestNote, inputs[currGateId][1])
        end
    end

    if active[1] == 1 then
        local sortedStack = {}
        for i, v in ipairs(voiceStack) do
            table.insert(sortedStack, inputs[v][1])
        end
        table.sort(sortedStack)
        local newHighest = sortedStack[#sortedStack]
        local newLowest = sortedStack[1]

        if newHighest > highestNoteValue then
            highestNoteValue = newHighest
        end
        if newLowest < lowestNoteValue then
            lowestNoteValue = newLowest
        end
        fill(highestNote, highestNoteValue)
        fill(lowestNote, lowestNoteValue)
    end

    fill(index, currentVoice)
    updateActiveGate()
    lastActiveGate = active[1]
    prevActive = active[1]

    for j = 1, 4 do
        prevGate[j] = gates[j][1]
    end
end
    (   (                    *?kD@aCA               (   (                    TDCA               Ģ(   \                    KʎDUfDO      $            active     index      currentNote    X   L   @   4   (               g4     g3     g2     g1     p4     p3     p2     p1        -- Detect input change and output index for most recent

prevNote = {0, 0, 0, 0}
currNoteId = 0
prevGate = {0, 0, 0, 0}
currGateId = 0

function process(frames)
	inputs = {p1, p2, p3, p4}
	gates = {g1, g2, g3, g4}

	local noteChanged = false
	local gateChanged = false

    for j = 1, 4 do
		if gates[j][1] ~= prevGate[j] then
			currGateId = j
			currNoteId = j
			--noteChanged = true
			gateChanged = true
        	break
		end
	end
	
	if gateChanged then
    	for j = 1, 4 do
        	prevNote[j] = inputs[j][1]
        	prevGate[j] = gates[j][1]
        end
    end

    id = currGateId
    gateId = currGateId
    
    index[1] = currGateId
	currentNote[1] = inputs[id][1]
end   8   8                 x   $   $     ?        D?C               }  ~                                     Note    T0   0                 m        HBFDw>D	               0   0                 =       A*5D$C	               Ե0   0                 $     C  HBzDEaD
                  newest  D   #  #                      A   B$    B  pC   CaDYCN   X#  Note = -16
Scales = {}
Scales[1] = {}
Scales[1]["label"] = "Chromatic"
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[2] = {}
Scales[2]["label"] = "Ionian"
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[3] = {}
Scales[3]["label"] = "Dorian"
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[4] = {}
Scales[4]["label"] = "Phrygian"
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[5] = {}
Scales[5]["label"] = "Lydian"
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[6] = {}
Scales[6]["label"] = "Mixolydian"
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[7] = {}
Scales[7]["label"] = "Aeolian"
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[8] = {}
Scales[8]["label"] = "Locrian"
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[9] = {}
Scales[9]["label"] = "1/2 Dimin"
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 5
Scales[9]["notes"][5] = 6
Scales[9]["notes"][6] = 8
Scales[9]["notes"][7] = 10
Scales[10] = {}
Scales[10]["label"] = "Spanish"
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 1
Scales[10]["notes"][3] = 4
Scales[10]["notes"][4] = 5
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 8
Scales[10]["notes"][7] = 10
Scales[11] = {}
Scales[11]["label"] = "Gyp Maj/Arab"
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 1
Scales[11]["notes"][3] = 4
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 7
Scales[11]["notes"][6] = 8
Scales[11]["notes"][7] = 11
Scales[12] = {}
Scales[12]["label"] = "Gypsy Minor"
Scales[12]["notes"] = {}
Scales[12]["notes"][1] = 0
Scales[12]["notes"][2] = 2
Scales[12]["notes"][3] = 3
Scales[12]["notes"][4] = 6
Scales[12]["notes"][5] = 7
Scales[12]["notes"][6] = 8
Scales[12]["notes"][7] = 11
Scales[13] = {}
Scales[13]["label"] = "Harmonic Min"
Scales[13]["notes"] = {}
Scales[13]["notes"][1] = 0
Scales[13]["notes"][2] = 2
Scales[13]["notes"][3] = 3
Scales[13]["notes"][4] = 5
Scales[13]["notes"][5] = 7
Scales[13]["notes"][6] = 8
Scales[13]["notes"][7] = 11
Scales[14] = {}
Scales[14]["label"] = "Ukranian"
Scales[14]["notes"] = {}
Scales[14]["notes"][1] = 0
Scales[14]["notes"][2] = 2
Scales[14]["notes"][3] = 3
Scales[14]["notes"][4] = 6
Scales[14]["notes"][5] = 7
Scales[14]["notes"][6] = 8
Scales[14]["notes"][7] = 10
Scales[15] = {}
Scales[15]["label"] = "Blues Maj"
Scales[15]["notes"] = {}
Scales[15]["notes"][1] = 0
Scales[15]["notes"][2] = 2
Scales[15]["notes"][3] = 3
Scales[15]["notes"][4] = 4
Scales[15]["notes"][5] = 7
Scales[15]["notes"][6] = 9
Scales[16] = {}
Scales[16]["label"] = "Blues Min"
Scales[16]["notes"] = {}
Scales[16]["notes"][1] = 0
Scales[16]["notes"][2] = 3
Scales[16]["notes"][3] = 5
Scales[16]["notes"][4] = 6
Scales[16]["notes"][5] = 7
Scales[16]["notes"][6] = 10
Scales[17] = {}
Scales[17]["label"] = "Maj Pent"
Scales[17]["notes"] = {}
Scales[17]["notes"][1] = 0
Scales[17]["notes"][2] = 2
Scales[17]["notes"][3] = 4
Scales[17]["notes"][4] = 7
Scales[17]["notes"][5] = 9
Scales[18] = {}
Scales[18]["label"] = "Susp/Egyp P"
Scales[18]["notes"] = {}
Scales[18]["notes"][1] = 0
Scales[18]["notes"][2] = 2
Scales[18]["notes"][3] = 5
Scales[18]["notes"][4] = 7
Scales[18]["notes"][5] = 10
Scales[19] = {}
Scales[19]["label"] = "Min Blues P"
Scales[19]["notes"] = {}
Scales[19]["notes"][1] = 0
Scales[19]["notes"][2] = 3
Scales[19]["notes"][3] = 5
Scales[19]["notes"][4] = 8
Scales[19]["notes"][5] = 10
Scales[20] = {}
Scales[20]["label"] = "Maj Blues/Yo"
Scales[20]["notes"] = {}
Scales[20]["notes"][1] = 0
Scales[20]["notes"][2] = 2
Scales[20]["notes"][3] = 5
Scales[20]["notes"][4] = 7
Scales[20]["notes"][5] = 9
Scales[21] = {}
Scales[21]["label"] = "Min Pent"
Scales[21]["notes"] = {}
Scales[21]["notes"][1] = 0
Scales[21]["notes"][2] = 3
Scales[21]["notes"][3] = 5
Scales[21]["notes"][4] = 7
Scales[21]["notes"][5] = 10
Scales[22] = {}
Scales[22]["label"] = "Ryūkyū"
Scales[22]["notes"] = {}
Scales[22]["notes"][1] = 0
Scales[22]["notes"][2] = 4
Scales[22]["notes"][3] = 5
Scales[22]["notes"][4] = 7
Scales[22]["notes"][5] = 11
Scales[23] = {}
Scales[23]["label"] = "In Pent"
Scales[23]["notes"] = {}
Scales[23]["notes"][1] = 0
Scales[23]["notes"][2] = 1
Scales[23]["notes"][3] = 5
Scales[23]["notes"][4] = 7
Scales[23]["notes"][5] = 8
Scales[24] = {}
Scales[24]["label"] = "Hirajoshi"
Scales[24]["notes"] = {}
Scales[24]["notes"][1] = 0
Scales[24]["notes"][2] = 2
Scales[24]["notes"][3] = 3
Scales[24]["notes"][4] = 7
Scales[24]["notes"][5] = 8
Scales[25] = {}
Scales[25]["label"] = "Pelog"
Scales[25]["notes"] = {}
Scales[25]["notes"][1] = 0
Scales[25]["notes"][2] = 1
Scales[25]["notes"][3] = 3
Scales[25]["notes"][4] = 7
Scales[25]["notes"][5] = 8
Scales[26] = {}
Scales[26]["label"] = "Whole Tone"
Scales[26]["notes"] = {}
Scales[26]["notes"][1] = 0
Scales[26]["notes"][2] = 2
Scales[26]["notes"][3] = 4
Scales[26]["notes"][4] = 6
Scales[26]["notes"][5] = 8
Scales[26]["notes"][6] = 10
Scales[27] = {}
Scales[27]["label"] = "Octatonic"
Scales[27]["notes"] = {}
Scales[27]["notes"][1] = 0
Scales[27]["notes"][2] = 1
Scales[27]["notes"][3] = 3
Scales[27]["notes"][4] = 4
Scales[27]["notes"][5] = 6
Scales[27]["notes"][6] = 7
Scales[27]["notes"][7] = 9
Scales[27]["notes"][8] = 10
Scales[28] = {}
Scales[28]["label"] = "Messiaen 3rd"
Scales[28]["notes"] = {}
Scales[28]["notes"][1] = 0
Scales[28]["notes"][2] = 2
Scales[28]["notes"][3] = 3
Scales[28]["notes"][4] = 4
Scales[28]["notes"][5] = 6
Scales[28]["notes"][6] = 7
Scales[28]["notes"][7] = 8
Scales[28]["notes"][8] = 10
Scales[28]["notes"][9] = 11
Scales[29] = {}
Scales[29]["label"] = "Messiaen 4th"
Scales[29]["notes"] = {}
Scales[29]["notes"][1] = 0
Scales[29]["notes"][2] = 1
Scales[29]["notes"][3] = 2
Scales[29]["notes"][4] = 5
Scales[29]["notes"][5] = 6
Scales[29]["notes"][6] = 7
Scales[29]["notes"][7] = 8
Scales[29]["notes"][8] = 11
Scales[30] = {}
Scales[30]["label"] = "Messiaen 5th"
Scales[30]["notes"] = {}
Scales[30]["notes"][1] = 0
Scales[30]["notes"][2] = 1
Scales[30]["notes"][3] = 5
Scales[30]["notes"][4] = 6
Scales[30]["notes"][5] = 7
Scales[30]["notes"][6] = 11
Scales[31] = {}
Scales[31]["label"] = "Messiaen 6th"
Scales[31]["notes"] = {}
Scales[31]["notes"][1] = 0
Scales[31]["notes"][2] = 2
Scales[31]["notes"][3] = 4
Scales[31]["notes"][4] = 5
Scales[31]["notes"][5] = 6
Scales[31]["notes"][6] = 8
Scales[31]["notes"][7] = 10
Scales[31]["notes"][8] = 11
Scales[32] = {}
Scales[32]["label"] = "Messiaen 7th"
Scales[32]["notes"] = {}
Scales[32]["notes"][1] = 0
Scales[32]["notes"][2] = 1
Scales[32]["notes"][3] = 2
Scales[32]["notes"][4] = 3
Scales[32]["notes"][5] = 5
Scales[32]["notes"][6] = 6
Scales[32]["notes"][7] = 7
Scales[32]["notes"][8] = 8
Scales[32]["notes"][9] = 9
Scales[32]["notes"][10] = 11
Scales[33] = {}
Scales[33]["label"] = "Min 3rd"
Scales[33]["notes"] = {}
Scales[33]["notes"][1] = 0
Scales[33]["notes"][2] = 3
Scales[33]["notes"][3] = 6
Scales[33]["notes"][4] = 9
Scales[34] = {}
Scales[34]["label"] = "Maj 3rd"
Scales[34]["notes"] = {}
Scales[34]["notes"][1] = 0
Scales[34]["notes"][2] = 4
Scales[34]["notes"][3] = 8
Scales[35] = {}
Scales[35]["label"] = "Fourth"
Scales[35]["notes"] = {}
Scales[35]["notes"][1] = 0
Scales[35]["notes"][2] = 5
Scales[36] = {}
Scales[36]["label"] = "Fifth"
Scales[36]["notes"] = {}
Scales[36]["notes"][1] = 0
Scales[36]["notes"][2] = 7
active = 1
canvas_height = 10
canvas_width = 40
highest = -1.3333332538605
input = -1.3333332538605
mode = 0
newest = -1.3333332538605
octaves = 1
root = 0
scl = 0.31317275762558
shift = -2
text_color = {}
text_color[1] = 0.839
text_color[2] = 0.839
text_color[3] = 0.839
text_color[4] = 1
           p   `   P   D   4   $            mode       active     octaves    shift      scl    root       highest    newest      =+  
-- Musical note text display by Jerry Smith and Rudiger Meyer, 2023
	
Scales = {
{ label = "Chromatic", 	    notes = { 0,1,2,3,4,5,6,7,8,9,10,11 } },
{ label = "Ionian", 	    notes = { 0,2,4,5,7,9,11 } },
{ label = "Dorian", 	    notes = { 0,2,3,5,7,9,10 } },
{ label = "Phrygian", 	    notes = { 0,1,3,5,7,8,10 } },
{ label = "Lydian", 	    notes = { 0,2,4,6,7,9,11 } },
{ label = "Mixolydian",     notes = { 0,2,4,5,7,9,10 } },
{ label = "Aeolian", 	    notes = { 0,2,3,5,7,8,10 } },
{ label = "Locrian", 	    notes = { 0,1,3,5,6,8,10 } },
{ label = "1/2 Dimin", 	    notes = { 0,2,3,5,6,8,10 } },
{ label = "Spanish", 	    notes = { 0,1,4,5,7,8,10 } },
{ label = "Gyp Maj/Arab", 	notes = { 0,1,4,5,7,8,11 } },
{ label = "Gypsy Minor", 	notes = { 0,2,3,6,7,8,11 } },
{ label = "Harmonic Min", 	notes = { 0,2,3,5,7,8,11 } },
{ label = "Ukranian", 	    notes = { 0,2,3,6,7,8,10 } },
{ label = "Blues Maj", 	    notes = { 0,2,3,4,7,9 } },
{ label = "Blues Min", 	    notes = { 0,3,5,6,7,10 } },
{ label = "Maj Pent", 	    notes = { 0,2,4,7,9 } },
{ label = "Susp/Egyp P",	notes = { 0,2,5,7,10 } },
{ label = "Min Blues P", 	notes = { 0,3,5,8,10 } },
{ label = "Maj Blues/Yo", 	notes = { 0,2,5,7,9 } },
{ label = "Min Pent", 	    notes = { 0,3,5,7,10 } },
{ label = "Ryūkyū", 	    notes = { 0,4,5,7,11 } },
{ label = "In Pent", 	    notes = { 0,1,5,7,8 } },
{ label = "Hirajoshi", 	    notes = { 0,2,3,7,8 } },
{ label = "Pelog", 	        notes = { 0,1,3,7,8 } },
{ label = "Whole Tone", 	notes = { 0,2,4,6,8,10 } },
{ label = "Octatonic", 	    notes = { 0,1,3,4,6,7,9,10 } },
{ label = "Messiaen 3rd", 	notes = { 0,2,3,4,6,7,8,10,11 } },
{ label = "Messiaen 4th", 	notes = { 0,1,2,5,6,7,8,11 } },
{ label = "Messiaen 5th", 	notes = { 0,1,5,6,7,11 } },
{ label = "Messiaen 6th", 	notes = { 0,2,4,5,6,8,10,11 } },
{ label = "Messiaen 7th", 	notes = { 0,1,2,3,5,6,7,8,9,11 } },
{ label = "Min 3rd", 	    notes = { 0,3,6,9 } },
{ label = "Maj 3rd", 	    notes = { 0,4,8 } },
{ label = "Fourth", 		notes = { 0,5 } },
{ label = "Fifth", 		    notes = { 0,7 } },
}

function drawNotes(name)
local accidentals = { -- uses "×" for double sharp
    {"A", "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"},
    {"A#", "B", "B#", "C#", "C×", "D#", "D#", "E#", "F#", "F×", "G#", "G×"},
    {"Bb", "Cb", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A"},
    {"B", "C", "C#", "D", "D#", "E", "E#", "F#", "G", "G#", "A", "A#"},
    {"C", "Db", "D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B"},
    {"C#", "D", "D#", "E", "E#", "F#", "F×", "G#", "A", "A#", "B", "B#"},
    {"Db", "Ebb", "Eb", "Fb", "F", "Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C"},
    {"D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B", "C", "C#"},
    {"D#", "E", "E#", "F#", "F×", "G#", "G×", "A#", "B", "B#", "C#", "C×"},
    {"Eb", "Fb", "F", "Gb", "G", "Ab", "A", "Bb", "Cb", "C", "Db", "D"},
    {"E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"},
    {"F", "Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E"},
    {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "E#"},
    {"Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C", "Db", "Ebb", "Eb", "Fb", "F"},
    {"G", "Ab", "A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#"},
    {"G#", "A", "A#", "B", "B#", "C#", "C×", "D#", "E", "E#", "F#", "F×"},
    {"Ab", "Bbb", "Bb", "Cb", "C", "Db", "D", "Eb", "Fb", "F", "Gb", "G"}
}

local accidentals_flat5 = {
-- for scales with the flattened 5th
	{"A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#"},
    {"A#", "B", "B#", "C#", "C×", "D#", "E", "E#", "F#", "F×", "G#", "G×"},
    {"Bb", "Cb", "C", "Db", "D", "Eb", "Fb", "F", "Gb", "G", "Ab", "A"},
    {"B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"},
    {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"},
    {"C#", "D", "D#", "E", "E#", "F#", "G", "G#", "A", "A#", "B", "B#"},
    {"Db", "Ebb", "Eb", "Fb", "F", "Gb", "Abb", "Ab", "Bbb", "Bb", "Cb", "C"},
    {"D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B", "C", "C#"},
    {"D#", "E", "E#", "F#", "F×", "G#", "A", "A#", "B", "B#", "C#", "C×"},
    {"Eb", "Fb", "F", "Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C", "Db", "D"},
    {"E", "F", "F#", "G", "G#", "A", "Bb", "B", "C", "C#", "D", "D#"},
    {"F", "Gb", "G", "Ab", "A", "Bb", "Cb", "C", "Db", "D", "Eb", "E"},
    {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "E#"},
    {"Gb", "G", "Ab", "Bbb", "Bb", "Cb", "Dbb", "Db", "Ebb", "Eb", "Fb", "F"},
    {"G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "F#"},
    {"G#", "A", "A#", "B", "B#", "C#", "D", "D#", "E", "E#", "F#", "F×"},
    {"Ab", "Bbb", "Bb", "Cb", "C", "Db", "Ebb", "Eb", "Fb", "F", "Gb", "G"}
}

local accidentals_chromatic = {
-- for the chromatic scale, wholetone + Messiaen 6th mode
	{"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"},
	{"A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A"},
	{"Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A"},
	{"B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"},
	{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"},
	{"C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C"},	
	{"Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "C"},
	{"D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#"},
	{"D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D"},
	{"Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D"},
	{"E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"},
	{"F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E"},
	{"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F"},		
	{"Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F"},
	{"G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#"},
	{"G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G"},
	{"Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G"}
}

local rootNote = {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11}
local rootDisplay = {1,1,2,3,4,4,5,5,6,7,8,8,9,10,11,11,12,12,13,14,15,15,16,17}
local rootId = rootDisplay[math.floor(root * 23.99) + 1]
local Root = rootNote[math.floor(root * 23.99) + 1]
text_color = theme.text

function flatSymbol()
	paint = color_paint(text_color)
	stroke = .85
	segments = 16 -- segments in curve
	
	save()
	translate{0,0}
	stroke_segment( {0, 0}, {0, 8}, stroke, paint)
	
	-- cubic bezier control points
	P0 = {-.5, stroke*.5}
	P1 = {5.5, 0}
	P2 = {5.5, 7}
	P3 = {0.2, 4}
		
	axy = {0, stroke*.5}
   	for i = 1, segments do
    	t = i/segments
    	px = (1-t)^3*P0[1] + 3*(1-t)^2 * t*P1[1] + 3*(1-t) * t^2*P2[1] + t^3*P3[1]
    	py = (1-t)^3*P0[2] + 3*(1-t)^2 * t*P1[2] + 3*(1-t) * t^2*P2[2] + t^3*P3[2]
   	    bxy = {px, py}
    	stroke_segment(axy, bxy, stroke, paint)
    	fill_circle(bxy, stroke*.49, paint)
       	axy = bxy		
    end	
	restore()
end
	
	
local function sharpSymbol()
    local w, h = 5.5, 7.5
    local vstroke = .8
    local hstroke = .9
    local vspread = 1.1
   	local hspread = 1.3
    local shear = 1

   	local function shearY(x, y)
       	return x, y + (x * shear * hspread/w)
   	end

   	save()
   	translate{0,-.25}
   	local function drawRect(x1, y1, x2, y2)
       	move_to{shearY(x1, y1)}        	
       	line_to{shearY(x2, y1)}
        line_to{shearY(x2, y2)}
       	line_to{shearY(x1, y2)}
       	line_to{shearY(x1, y1)}
       	fill(color_paint(text_color))
   	end

   	drawRect(0, h/2 - hspread - hstroke/2, w, h/2 - hspread + hstroke/2) -- Top
   	drawRect(0, h/2 + vspread - hstroke/2, w, h/2 + vspread + hstroke/2) -- Bottom
   	drawRect(w/2 - vspread - vstroke/2, 0, w/2 - vspread + vstroke/2, h) -- Left
   	drawRect(w/2 + vspread - vstroke/2, 0, w/2 + vspread + vstroke/2, h) -- Right
   	restore()
end


local function doubleSharpSymbol()
	local w = 5
	local h = 5
	local rSize = 1.5
	local cRad = 0

	paint = color_paint(text_color)
	save()
	translate{w/4,h/3}
	fill_rect({0, 0}, {rSize, rSize}, cRad, paint)
	fill_rect({w - rSize, 0}, {w, rSize}, cRad, paint)
	fill_rect({0, h - rSize}, {rSize, h}, cRad, paint)
	fill_rect({w - rSize, h - rSize}, {w, h}, cRad, paint)

	stroke_segment({rSize/2, rSize/2}, {w - rSize/2, h - rSize/2}, rSize/1.8, paint)
	stroke_segment({w - rSize/2, rSize/2}, {rSize/2, h - rSize/2}, rSize/1.8, paint)
	restore()
end

local function fract(x)
  	if x >= 0 then
  		return x - math.floor(x)
  	elseif x < 0 then
  		return 1-(math.abs(x) - math.abs(math.floor(x) + 1))
	end
end

if mode == 1 then 
input = newest
else
input = highest
end

Note = math.floor(input * 12 + 0.001)
 -- note = inputs
 
local Octave = math.floor(Note / 12)  + 4


local noteInScale = math.floor(fract((Note - Root)/12 - shift) * 12 + .001)
local NoteLabel = noteInScale + 1

local currentScale = math.floor(scl*35.99)+1

-- designate accidentals
local noteName
	if currentScale == 8 
	or currentScale == 9 
	or currentScale == 27 
	or currentScale == 29 
	or currentScale == 30 
	or currentScale == 32 
	then noteName = accidentals_flat5[rootId]
elseif currentScale == 1 
	or currentScale == 26 
	or currentScale == 31 
	then noteName = accidentals_chromatic[rootId]
else
	noteName = accidentals[rootId]
end

local flatNote = noteName[NoteLabel]:gsub("b", "") -- Remove "b"
local isFlat = #flatNote < #noteName[NoteLabel] -- Is the note a flat?

local doubleFlatNote = noteName[NoteLabel]:gsub("bb", "") -- Remove "bb"
local isDoubleFlat = #doubleFlatNote < #noteName[NoteLabel] -- Is the note a double flat?

local sharpNote = noteName[NoteLabel]:gsub("#", "") -- Remove "#"
local isSharp = #sharpNote < #noteName[NoteLabel] -- Is the note a sharp?

local doubleSharpNote = noteName[NoteLabel]:gsub("×", "") -- Remove "×"
local isDoubleSharp = #doubleSharpNote < #noteName[NoteLabel] -- Is the note a double sharp?

-- Draw -------------------
save()
translate{canvas_width/2, canvas_height/2}
scale{1.2, 1.2}
local min, max = text_bounds(noteName[NoteLabel] .. Octave)
	
	if isDoubleFlat then
    save()
    translate{-max[1]/2, -max[2]/2}
    text(doubleFlatNote, text_color)
    translate{8.5, 0}
    flatSymbol()
    translate{4.2, 0}
    flatSymbol()
    translate{5.5, 0}
    text(Octave, theme.text)
    restore()
	elseif isFlat then    
    save()
    translate{-max[1]/2, -max[2]/2}
    text(flatNote, theme.text)
    translate{8.5, 0}
    flatSymbol()
    translate{5.5, 0}
    text(Octave, theme.text)
    restore()
	elseif isSharp then    
    save()
    translate{-max[1]/2, -max[2]/2}
    text(sharpNote, theme.text)
    translate{8, 0}
    sharpSymbol()
    translate{6.5, 0}
    text(Octave, theme.text)
    restore()
	elseif isDoubleSharp then    
    save()
    translate{-max[1]/2, -max[2]/2}
    text(doubleSharpNote, theme.text)
    translate{6.5, 0}
    doubleSharpSymbol()
    translate{7, 0}
    text(Octave, theme.text)
   	restore()
	else
    save()
    translate{-max[1]/2, -max[2]/2}
    text(noteName[NoteLabel] .. Octave, theme.text)
    restore()
	end
	
restore()
end
----
if active == 1 then
drawNotes(name)
end   0   0                 $          @D	                  mode    $   $                   C  (               d8   8                   A  A     @  p    /DM               <   <                   A  A8     @  p   NDDN                switch      D  

if switch > 0 then 
	label = "Kbd"
	circle_color = theme.azureHighlight
	border_color = theme.grooves
	text_color = theme.azureHighlightBackground
else 
	label = "Mod" 
	circle_color = theme.azureHighlightBackground
	border_color = theme.azureHighlight
	text_color = theme.azureHighlight
end

save()
translate{canvas_width/2, canvas_height/2}
stroke_circle( {0,0}, 13, 4, color_paint(border_color))
fill_circle({0,0}, 12.5, color_paint(circle_color))

min, max = text_bounds(label)
scale{.9,.9}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
text(label, text_color)
restore()    $   $                 *8?K               <   <                    A   B             <N       
   x   l   `   T   H   <   0   $            mode       voices     in7    in6    in5    in4    in3    in2    in1    in0       

local function gateLight(input, x, y, text_on, ring_on)
	
	col = theme.azureHighlight
	black = theme.grooves
	
	if input > 0 then
		text_color = {.5,.5,.5,1}
	else
		text_color = theme.text
	end
	
	save()
	translate{x,y}
		if ring_on > 0 then
		fill_rect({-1,-5},{1,5}, 1, color_paint{.11,.11,.118,1})
		stroke_rect({-1,-5},{1,5}, 1, 1, color_paint{black[1], black[2], black[3], 1-input})
		end
		fill_rect({-1,-5},{1,5}, 1, color_paint{col[1], col[2], col[3], input})
		fill_rect({-2,-6},{2,6}, 2, color_paint{col[1], col[2], col[3], input*.2})
	restore()
end


if mode == 0 then

save()
	translate{ 10, canvas_height/2 }
	fill_circle({-5,0}, 5, color_paint(theme.grooves))
	--fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})
	--scale{.75,.75}
	save()
	min, max = text_bounds("G")
	translate{ -(min[1]+max[1])/2 - 5, -(max[2]+min[2])/2 }
	text("G", {.11,.11,.118,1})
	restore()
restore()
else

save()
	translate{ 10, canvas_height/2 }
	fill_circle({-5,0}, 5, color_paint(theme.grooves))
	--fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})
	--scale{.75,.75}
	save()
	min, max = text_bounds("G")
	translate{ -(min[1]+max[1])/2 - 5, -(max[2]+min[2])/2 }
	text("G", theme.text)
	restore()
restore()

t = {in0,in1,in2,in3,in4,in5,in6,in7}

translate{15,0}
for i = 1, voices do
gateLight(t[i], 5, 5, 1, 1)

save()
scale{.4,.4}
min, max = text_bounds(i)
translate{ -(min[1]+max[1])/2 + 13, -(max[2]+min[2])/2 - 8 }
text(i, {.5,.5,.5,1})
restore()
translate{4, 0}
end

end   @   @                 0   0     ?          C   B    p 6D               s  t  v  w  {  ,   ,                       WBByv6	               T(   (                    :A               @<   <                    A   AH     @  @   b;lDN                   mode       input       q  -- HSV to RGB
function hsv(h,s,v)
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end

local function octLight(input, x, y)
	
	local h=(1-((input+5)/10))*.7 -- color shift per octave
	local s=1 -- saturation always 1
	local v=((input+5)-math.floor(input+5))*.9+.1 -- dark to light per octave
	
	local r,g,b = hsv(h,s,v)
	
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	save()
	translate{x,y}
	fill_circle({0,0},9,color_paint{.05,.05,.05,.18})
	fill_circle({0,0},5,color_paint{.05,.05,.05,1})
	
	fill_circle({0,0},9,halo)
	fill_circle({0,0},5,paint)
	
	min, max = text_bounds("O")
	translate{ -(min[1]+max[1])/2, -(min[2]+max[2])/2 }
	text("O", theme.text)
	restore()
	
end

local function modLight(input, x, y)
	if input > 0 and input <= 1 then
		r = input
		g = input*.3
		b = 0
		a = 1
	elseif input > 1 then -- saturate alpha if > 1
		r,g,b,a = 1, .1, 0, math.abs(input)
		
	elseif input <= 0 and input >= -1 then
		r = math.abs(input*.2)
		g = math.abs(input*.3)
		b = math.abs(input)
		a = 1
	elseif input < -1 then -- saturate alpha if < -1
		r,g,b,a = .2, .3, 1, math.abs(input)
	end
	
	save()
	translate{x,y}
		fill_circle({0,0}, 5, color_paint{r,g,b,a})
		fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})
	min, max = text_bounds("M")
	translate{ -(min[1]+max[1])/2, -(min[2]+max[2])/2 }
		text("M", theme.text)
	restore()
	
end

if mode>0 then
octLight(input, 5, 5)
else
modLight(input, 5, 5)
end   p(   (                    IQUDD=               (   (                 4   íF0C                   oct    k          k*oct   0   0                 $     p  ²KcC	                  Octave  T(   (                 8   ~%A                   root       o          (o*12-root)/12  (   (                 ,   u> T7>                root           floor(root*11.99)   (   (                 (   Fz=A                x          x+0.01  |0   0                 $     p  aĀ	                  Root    (   (                     P wB>               $   $                     L                $   $                     \L               X(   (                 ,     H                  voices      	   voices==4   (   (                 ,     C  4                voices      	   voices==2   	(   (                    `/ A               <$   $                 `/ L               p$   $                 `/ 8BL               	(   (                    `/ 8BA               (   (                 ,   @(| p6C                vioces         vioces == 1 4$   $                 ^" pVBL               h
(   (                      \  H=               $   $                      K               
(   (                    ` pBB               K8   8                    $   $     ?          C  HD               Q  R  S  T  U  V  W  X  Y  Z  [  ]  ^  _  `  a  b  c  d  e  f  g  h  i  j  z     Active voices   0   0                 $    B  A     H
               (0   0                 `            	               h0   0                         A    \	               (   (                 (                       x          x>0 
$   $                     L               $   $                     L               H$   $                     L               |(   (                        A               $   $                     L               (   (                      k  B                (   (                        A               l 0   0                    B     C  C
               (   (                      B  C?                0   0                 t   p  A    C	               $!0   0                 H   B   },BL}3D
               d!0   0                 $     p   º!B	                  Kbd (   (                      D                x       0   0                          4-}-D(                      D   D                  0   0     ?              B  AWHD               B  C  D  E  F  G  H  J  K  L  M  N  O  P  k  l  m  n  o  p  x  y  "0   0                 $     B  A.%C3C
                  M/O (   (                    6XCKhwC=               X(   (                      C               (   (                        C@               #0   0                    p   )à}JC	               $   $                 xAUCL               8$   $                 xAʒCL               l(   (                     D DA               L,   ,                    A   BQaD	               (   (                      \C JD=                 j @ < 4 ,               (                    $                                                      j   <   k  k                  B  Bk    B  RCvDN   |k  py = -33
size = 3
notesInCurr = 12
rootSig = 9
notName = {}
notName[1] = "A"
notName[2] = "A#"
notName[3] = "B"
notName[4] = "C"
notName[5] = "C#"
notName[6] = "D"
notName[7] = "D#"
notName[8] = "E"
notName[9] = "F"
notName[10] = "F#"
notName[11] = "G"
notName[12] = "G#"
y = 0
rootS = {}
rootS[1] = "A"
rootS[2] = "A#"
rootS[3] = "B"
rootS[4] = "C"
rootS[5] = "C#"
rootS[6] = "D"
rootS[7] = "D#"
rootS[8] = "E"
rootS[9] = "F"
rootS[10] = "F#"
rootS[11] = "G"
rootS[12] = "G#"
currentRoot = 4
notesIn = 12
width = 8.3333333333333
showKnob = 0
n = 12
NotesInScale = 10
sharpId = {}
sharpId[1] = 1
sharpId[2] = 3
sharpId[3] = 5
sharpId[4] = 7
sharpId[5] = 9
sharpId[6] = 11
sharpId[7] = 13
sharpId[8] = 15
sharpId[9] = 17
sharpId[10] = 19
sharpId[11] = 21
sharpId[12] = 23
note = 12
gap = 0.005
Notelo = 13
currOct = 4
canvas_height = 90
noteName = "B"
flatNoteInds = {}
flatNotes = {}
octave = 0
rootDisp = {}
rootDisp[1] = 1
rootDisp[2] = 1
rootDisp[3] = 2
rootDisp[4] = 3
rootDisp[5] = 4
rootDisp[6] = 4
rootDisp[7] = 5
rootDisp[8] = 5
rootDisp[9] = 6
rootDisp[10] = 7
rootDisp[11] = 8
rootDisp[12] = 8
rootDisp[13] = 9
rootDisp[14] = 10
rootDisp[15] = 11
rootDisp[16] = 11
rootDisp[17] = 12
rootDisp[18] = 12
rootDisp[19] = 13
rootDisp[20] = 14
rootDisp[21] = 15
rootDisp[22] = 15
rootDisp[23] = 16
rootDisp[24] = 17
accidentalschromatic = {}
accidentalschromatic[1] = "A"
accidentalschromatic[2] = "A#"
accidentalschromatic[3] = "B"
accidentalschromatic[4] = "C"
accidentalschromatic[5] = "C#"
accidentalschromatic[6] = "D"
accidentalschromatic[7] = "D#"
accidentalschromatic[8] = "E"
accidentalschromatic[9] = "F"
accidentalschromatic[10] = "F#"
accidentalschromatic[11] = "G"
accidentalschromatic[12] = "G#"
totalLength = 10
rootId = 6
lrootsKnob = {}
lrootsKnob[1] = 1
lrootsKnob[2] = 1
lrootsKnob[3] = 2
lrootsKnob[4] = 3
lrootsKnob[5] = 4
lrootsKnob[6] = 4
lrootsKnob[7] = 5
lrootsKnob[8] = 5
lrootsKnob[9] = 6
lrootsKnob[10] = 7
lrootsKnob[11] = 8
lrootsKnob[12] = 8
lrootsKnob[13] = 9
lrootsKnob[14] = 10
lrootsKnob[15] = 11
lrootsKnob[16] = 11
lrootsKnob[17] = 12
lrootsKnob[18] = 12
lrootsKnob[19] = 13
lrootsKnob[20] = 14
lrootsKnob[21] = 15
lrootsKnob[22] = 15
lrootsKnob[23] = 16
lrootsKnob[24] = 17
shaNoteIndex = {}
shaNoteIndex[1] = 1
shaNoteIndex[2] = 4
shaNoteIndex[3] = 5
shaNoteIndex[4] = 7
shaNoteIndex[5] = 10
shaNoteIndex[6] = 11
shaNoteIndex[7] = 14
shaNoteIndex[8] = 15
shaNoteIndex[9] = 17
shaNoteIndex[10] = 20
shaNoteIndex[11] = 21
shaNoteIndex[12] = 24
sharpNoteIndex = {}
sharpNoteIndex[1] = 1
sharpNoteIndex[2] = 4
sharpNoteIndex[3] = 5
sharpNoteIndex[4] = 7
sharpNoteIndex[5] = 10
sharpNoteIndex[6] = 11
sharpNoteIndex[7] = 14
sharpNoteIndex[8] = 15
sharpNoteIndex[9] = 17
sharpNoteIndex[10] = 20
sharpNoteIndex[11] = 21
sharpNoteIndex[12] = 24
ext = 0
c2_stroke = {}
c2_stroke[1] = 1.4518953061548
c2_stroke[2] = 0.71605322650299
c2_stroke[3] = 1.0839742663289
c2_stroke[4] = 0.7
min = {}
min[1] = 0.83999997377396
min[2] = 0
max = {}
max[1] = 12.852000236511
max[2] = 8.3999996185303
knob = 0
length = 1
currentRootDispl = 1
iNote = 6
sharpIde = {}
sharpIde[1] = 1
sharpIde[2] = 3
sharpIde[3] = 5
sharpIde[4] = 7
sharpIde[5] = 9
sharpIde[6] = 11
sharpIde[7] = 13
sharpIde[8] = 15
sharpIde[9] = 17
sharpIde[10] = 19
sharpIde[11] = 21
sharpIde[12] = 23
currentRootD = 1
loaccidentalschromatic = {}
loaccidentalschromatic[1] = "A"
loaccidentalschromatic[2] = "A#"
loaccidentalschromatic[3] = "B"
loaccidentalschromatic[4] = "C"
loaccidentalschromatic[5] = "C#"
loaccidentalschromatic[6] = "D"
loaccidentalschromatic[7] = "D#"
loaccidentalschromatic[8] = "E"
loaccidentalschromatic[9] = "F"
loaccidentalschromatic[10] = "F#"
loaccidentalschromatic[11] = "G"
loaccidentalschromatic[12] = "G#"
notesInCurrentScale = 5
notesInCurrentSc = 12
h = 2
clamp = 1
no = 12
b = 0
rootShi = {}
rootShi[1] = "A"
rootShi[2] = "A#"
rootShi[3] = "B"
rootShi[4] = "C"
rootShi[5] = "C#"
rootShi[6] = "D"
rootShi[7] = "D#"
rootShi[8] = "E"
rootShi[9] = "F"
rootShi[10] = "F#"
rootShi[11] = "G"
rootShi[12] = "G#"
Notelow = 13
s = 0.5
totalWidth = 200
Notelowhi = 13
NotesinS = 10
flatNoteIndexs = {}
rootDisplay = {}
rootDisplay[1] = 1
rootDisplay[2] = 1
rootDisplay[3] = 2
rootDisplay[4] = 3
rootDisplay[5] = 4
rootDisplay[6] = 4
rootDisplay[7] = 5
rootDisplay[8] = 5
rootDisplay[9] = 6
rootDisplay[10] = 7
rootDisplay[11] = 8
rootDisplay[12] = 8
rootDisplay[13] = 9
rootDisplay[14] = 10
rootDisplay[15] = 11
rootDisplay[16] = 11
rootDisplay[17] = 12
rootDisplay[18] = 12
rootDisplay[19] = 13
rootDisplay[20] = 14
rootDisplay[21] = 15
rootDisplay[22] = 15
rootDisplay[23] = 16
rootDisplay[24] = 17
currentScale = 23
rootShift = {}
rootShift[1] = "A"
rootShift[2] = "A#"
rootShift[3] = "B"
rootShift[4] = "C"
rootShift[5] = "C#"
rootShift[6] = "D"
rootShift[7] = "D#"
rootShift[8] = "E"
rootShift[9] = "F"
rootShift[10] = "F#"
rootShift[11] = "G"
rootShift[12] = "G#"
notesInCurre = 12
flatNId = {}
flatNId[1] = 1
flatNId[2] = 4
flatNId[3] = 5
flatNId[4] = 7
flatNId[5] = 10
flatNId[6] = 11
flatNId[7] = 14
flatNId[8] = 15
flatNId[9] = 17
flatNId[10] = 20
flatNId[11] = 21
flatNId[12] = 24
octAdd = 12
c2_fill = {}
c2_fill[1] = 0.72594765307739
c2_fill[2] = 0.71605322650299
c2_fill[3] = 1.0839742663289
c2_fill[4] = 0.7
xoct = 1.0349996089935
Notelowhig = 13
flatNoteId = {}
flatNoteId[1] = 1
flatNoteId[2] = 4
flatNoteId[3] = 5
flatNoteId[4] = 7
flatNoteId[5] = 10
flatNoteId[6] = 11
flatNoteId[7] = 14
flatNoteId[8] = 15
flatNoteId[9] = 17
flatNoteId[10] = 20
flatNoteId[11] = 21
flatNoteId[12] = 24
inorm = 1.1111111111111
input = 0.07500147074461
notesInCurrentSca = 12
Notes = 10
locaaccidentalschromatic = {}
locaaccidentalschromatic[1] = "A"
locaaccidentalschromatic[2] = "A#"
locaaccidentalschromatic[3] = "B"
locaaccidentalschromatic[4] = "C"
locaaccidentalschromatic[5] = "C#"
locaaccidentalschromatic[6] = "D"
locaaccidentalschromatic[7] = "D#"
locaaccidentalschromatic[8] = "E"
locaaccidentalschromatic[9] = "F"
locaaccidentalschromatic[10] = "F#"
locaaccidentalschromatic[11] = "G"
locaaccidentalschromatic[12] = "G#"
arc_aperture = 0.30915926535898
locarootsKnob = {}
locarootsKnob[1] = 1
locarootsKnob[2] = 1
locarootsKnob[3] = 2
locarootsKnob[4] = 3
locarootsKnob[5] = 4
locarootsKnob[6] = 4
locarootsKnob[7] = 5
locarootsKnob[8] = 5
locarootsKnob[9] = 6
locarootsKnob[10] = 7
locarootsKnob[11] = 8
locarootsKnob[12] = 8
locarootsKnob[13] = 9
locarootsKnob[14] = 10
locarootsKnob[15] = 11
locarootsKnob[16] = 11
locarootsKnob[17] = 12
locarootsKnob[18] = 12
locarootsKnob[19] = 13
locarootsKnob[20] = 14
locarootsKnob[21] = 15
locarootsKnob[22] = 15
locarootsKnob[23] = 16
locarootsKnob[24] = 17
sharpIdex = {}
sharpIdex[1] = 1
sharpIdex[2] = 3
sharpIdex[3] = 5
sharpIdex[4] = 7
sharpIdex[5] = 9
sharpIdex[6] = 11
sharpIdex[7] = 13
sharpIdex[8] = 15
sharpIdex[9] = 17
sharpIdex[10] = 19
sharpIdex[11] = 21
sharpIdex[12] = 23
a = 0.31415926535898
notesInCu = 12
Notesin = 10
knob_color = {}
knob_color[1] = 0.7
knob_color[2] = 0.7
knob_color[3] = 0.7
knob_color[4] = 1
flats = {}
notesInCurrentS = 12
arc_rotation = 4.7123889803847
sharpNotIndex = {}
sharpNotIndex[1] = 1
sharpNotIndex[2] = 4
sharpNotIndex[3] = 5
sharpNotIndex[4] = 7
sharpNotIndex[5] = 10
sharpNotIndex[6] = 11
sharpNotIndex[7] = 14
sharpNotIndex[8] = 15
sharpNotIndex[9] = 17
sharpNotIndex[10] = 20
sharpNotIndex[11] = 21
sharpNotIndex[12] = 24
rootShif = {}
rootShif[1] = "A"
rootShif[2] = "A#"
rootShif[3] = "B"
rootShif[4] = "C"
rootShif[5] = "C#"
rootShif[6] = "D"
rootShif[7] = "D#"
rootShif[8] = "E"
rootShif[9] = "F"
rootShif[10] = "F#"
rootShif[11] = "G"
rootShif[12] = "G#"
canvas_width = 90
Not = 10
Notelowhigh = 17
flatNoteIn = {}
flatNoteIn[1] = 1
flatNoteIn[2] = 4
flatNoteIn[3] = 5
flatNoteIn[4] = 7
flatNoteIn[5] = 10
flatNoteIn[6] = 11
flatNoteIn[7] = 14
flatNoteIn[8] = 15
flatNoteIn[9] = 17
flatNoteIn[10] = 20
flatNoteIn[11] = 21
flatNoteIn[12] = 24
octaves = 2
rootDispl = {}
rootDispl[1] = 1
rootDispl[2] = 1
rootDispl[3] = 2
rootDispl[4] = 3
rootDispl[5] = 4
rootDispl[6] = 4
rootDispl[7] = 5
rootDispl[8] = 5
rootDispl[9] = 6
rootDispl[10] = 7
rootDispl[11] = 8
rootDispl[12] = 8
rootDispl[13] = 9
rootDispl[14] = 10
rootDispl[15] = 11
rootDispl[16] = 11
rootDispl[17] = 12
rootDispl[18] = 12
rootDispl[19] = 13
rootDispl[20] = 14
rootDispl[21] = 15
rootDispl[22] = 15
rootDispl[23] = 16
rootDispl[24] = 17
height = 50
Notel = 13
flatNoteI = {}
flatNoteI[1] = 1
flatNoteI[2] = 4
flatNoteI[3] = 5
flatNoteI[4] = 7
flatNoteI[5] = 10
flatNoteI[6] = 11
flatNoteI[7] = 14
flatNoteI[8] = 15
flatNoteI[9] = 17
flatNoteI[10] = 20
flatNoteI[11] = 21
flatNoteI[12] = 24
root = 0
noteTranspose = 1
text_color = {}
text_color[1] = 0.84
text_color[2] = 0.84
text_color[3] = 0.84
text_color[4] = 1
rootDis = {}
rootDis[1] = 1
rootDis[2] = 1
rootDis[3] = 2
rootDis[4] = 3
rootDis[5] = 4
rootDis[6] = 4
rootDis[7] = 5
rootDis[8] = 5
rootDis[9] = 6
rootDis[10] = 7
rootDis[11] = 8
rootDis[12] = 8
rootDis[13] = 9
rootDis[14] = 10
rootDis[15] = 11
rootDis[16] = 11
rootDis[17] = 12
rootDis[18] = 12
rootDis[19] = 13
rootDis[20] = 14
rootDis[21] = 15
rootDis[22] = 15
rootDis[23] = 16
rootDis[24] = 17
mode = 0
sharNoteIndex = {}
sharNoteIndex[1] = 1
sharNoteIndex[2] = 4
sharNoteIndex[3] = 5
sharNoteIndex[4] = 7
sharNoteIndex[5] = 10
sharNoteIndex[6] = 11
sharNoteIndex[7] = 14
sharNoteIndex[8] = 15
sharNoteIndex[9] = 17
sharNoteIndex[10] = 20
sharNoteIndex[11] = 21
sharNoteIndex[12] = 24
touch = 0
flatNoteIndes = {}
flatId = {}
flatId[1] = 1
flatId[2] = 4
flatId[3] = 5
flatId[4] = 7
flatId[5] = 10
flatId[6] = 11
flatId[7] = 14
flatId[8] = 15
flatId[9] = 17
flatId[10] = 20
notesInCurren = 12
NotesinSc = 10
localaccidentalschromatic = {}
localaccidentalschromatic[1] = "A"
localaccidentalschromatic[2] = "A#"
localaccidentalschromatic[3] = "B"
localaccidentalschromatic[4] = "C"
localaccidentalschromatic[5] = "C#"
localaccidentalschromatic[6] = "D"
localaccidentalschromatic[7] = "D#"
localaccidentalschromatic[8] = "E"
localaccidentalschromatic[9] = "F"
localaccidentalschromatic[10] = "F#"
localaccidentalschromatic[11] = "G"
localaccidentalschromatic[12] = "G#"
notesInCur = 12
currentNote = 2
NotesinScale = 10
sharpIndex = {}
sharpIndex[1] = 1
sharpIndex[2] = 3
sharpIndex[3] = 5
sharpIndex[4] = 7
sharpIndex[5] = 9
sharpIndex[6] = 11
sharpIndex[7] = 13
sharpIndex[8] = 15
sharpIndex[9] = 17
sharpIndex[10] = 19
sharpIndex[11] = 21
sharpIndex[12] = 23
scl = 0.55123448371887
w = 4.5
N = 10
k = 0
v = 0.5
rootName2 = {}
rootName2[1] = "A"
rootName2[2] = "A#"
rootName2[3] = "B"
rootName2[4] = "C"
rootName2[5] = "C#"
rootName2[6] = "D"
rootName2[7] = "D#"
rootName2[8] = "E"
rootName2[9] = "F"
rootName2[10] = "F#"
rootName2[11] = "G"
rootName2[12] = "G#"
Notesi = 10
rootDi = {}
rootDi[1] = 1
rootDi[2] = 1
rootDi[3] = 2
rootDi[4] = 3
rootDi[5] = 4
rootDi[6] = 4
rootDi[7] = 5
rootDi[8] = 5
rootDi[9] = 6
rootDi[10] = 7
rootDi[11] = 8
rootDi[12] = 8
rootDi[13] = 9
rootDi[14] = 10
rootDi[15] = 11
rootDi[16] = 11
rootDi[17] = 12
rootDi[18] = 12
rootDi[19] = 13
rootDi[20] = 14
rootDi[21] = 15
rootDi[22] = 15
rootDi[23] = 16
rootDi[24] = 17
flatNoteInd = {}
flatNoteInd[1] = 1
flatNoteInd[2] = 4
flatNoteInd[3] = 5
flatNoteInd[4] = 7
flatNoteInd[5] = 10
flatNoteInd[6] = 11
flatNoteInd[7] = 14
flatNoteInd[8] = 15
flatNoteInd[9] = 17
flatNoteInd[10] = 20
flatNoteInd[11] = 21
flatNoteInd[12] = 24
oct = 2
flatNotId = {}
flatNotId[1] = 1
flatNotId[2] = 4
flatNotId[3] = 5
flatNotId[4] = 7
flatNotId[5] = 10
flatNotId[6] = 11
flatNotId[7] = 14
flatNotId[8] = 15
flatNotId[9] = 17
flatNotId[10] = 20
flatNotId[11] = 21
flatNotId[12] = 24
radius = 34
locaccidentalschromatic = {}
locaccidentalschromatic[1] = "A"
locaccidentalschromatic[2] = "A#"
locaccidentalschromatic[3] = "B"
locaccidentalschromatic[4] = "C"
locaccidentalschromatic[5] = "C#"
locaccidentalschromatic[6] = "D"
locaccidentalschromatic[7] = "D#"
locaccidentalschromatic[8] = "E"
locaccidentalschromatic[9] = "F"
locaccidentalschromatic[10] = "F#"
locaccidentalschromatic[11] = "G"
locaccidentalschromatic[12] = "G#"
Notelowh = 13
rootSh = {}
rootSh[1] = "A"
rootSh[2] = "A#"
rootSh[3] = "B"
rootSh[4] = "C"
rootSh[5] = "C#"
rootSh[6] = "D"
rootSh[7] = "D#"
rootSh[8] = "E"
rootSh[9] = "F"
rootSh[10] = "F#"
rootSh[11] = "G"
rootSh[12] = "G#"
flatNoteInde = {}
flatNoteInde[1] = 1
flatNoteInde[2] = 4
flatNoteInde[3] = 5
flatNoteInde[4] = 7
flatNoteInde[5] = 10
flatNoteInde[6] = 11
flatNoteInde[7] = 14
flatNoteInde[8] = 15
flatNoteInde[9] = 17
flatNoteInde[10] = 20
flatNoteInde[11] = 21
flatNoteInde[12] = 24
NotesinSca = 10
notesInCurrentScal = 12
keySigRoot = 8
px = 2.0206672185931e-15
sharpNoIndex = {}
sharpNoIndex[1] = 1
sharpNoIndex[2] = 4
sharpNoIndex[3] = 5
sharpNoIndex[4] = 7
sharpNoIndex[5] = 10
sharpNoIndex[6] = 11
sharpNoIndex[7] = 14
sharpNoIndex[8] = 15
sharpNoIndex[9] = 17
sharpNoIndex[10] = 20
sharpNoIndex[11] = 21
sharpNoIndex[12] = 24
lorootsKnob = {}
lorootsKnob[1] = 1
lorootsKnob[2] = 1
lorootsKnob[3] = 2
lorootsKnob[4] = 3
lorootsKnob[5] = 4
lorootsKnob[6] = 4
lorootsKnob[7] = 5
lorootsKnob[8] = 5
lorootsKnob[9] = 6
lorootsKnob[10] = 7
lorootsKnob[11] = 8
lorootsKnob[12] = 8
lorootsKnob[13] = 9
lorootsKnob[14] = 10
lorootsKnob[15] = 11
lorootsKnob[16] = 11
lorootsKnob[17] = 12
lorootsKnob[18] = 12
lorootsKnob[19] = 13
lorootsKnob[20] = 14
lorootsKnob[21] = 15
lorootsKnob[22] = 15
lorootsKnob[23] = 16
lorootsKnob[24] = 17
notesInCurrent = 12
rotation = 1.8849555921539
currentRootDispla = 1
octShift = 0
noName = {}
noName[1] = "A"
noName[2] = "A#"
noName[3] = "B"
noName[4] = "C"
noName[5] = "C#"
noName[6] = "D"
noName[7] = "D#"
noName[8] = "E"
noName[9] = "F"
noName[10] = "F#"
noName[11] = "G"
noName[12] = "G#"
Note = 13
currentRootDisplay = 6
rootsKnob = {}
rootsKnob[1] = 1
rootsKnob[2] = 1
rootsKnob[3] = 2
rootsKnob[4] = 3
rootsKnob[5] = 4
rootsKnob[6] = 4
rootsKnob[7] = 5
rootsKnob[8] = 5
rootsKnob[9] = 6
rootsKnob[10] = 7
rootsKnob[11] = 8
rootsKnob[12] = 8
rootsKnob[13] = 9
rootsKnob[14] = 10
rootsKnob[15] = 11
rootsKnob[16] = 11
rootsKnob[17] = 12
rootsKnob[18] = 12
rootsKnob[19] = 13
rootsKnob[20] = 14
rootsKnob[21] = 15
rootsKnob[22] = 15
rootsKnob[23] = 16
rootsKnob[24] = 17
NotesinScal = 10
x = 0.43999981880188
flatNoteIs = {}
notesI = 12
currNoteName = 2
localrootsKnob = {}
localrootsKnob[1] = 1
localrootsKnob[2] = 1
localrootsKnob[3] = 2
localrootsKnob[4] = 3
localrootsKnob[5] = 4
localrootsKnob[6] = 4
localrootsKnob[7] = 5
localrootsKnob[8] = 5
localrootsKnob[9] = 6
localrootsKnob[10] = 7
localrootsKnob[11] = 8
localrootsKnob[12] = 8
localrootsKnob[13] = 9
localrootsKnob[14] = 10
localrootsKnob[15] = 11
localrootsKnob[16] = 11
localrootsKnob[17] = 12
localrootsKnob[18] = 12
localrootsKnob[19] = 13
localrootsKnob[20] = 14
localrootsKnob[21] = 15
localrootsKnob[22] = 15
localrootsKnob[23] = 16
localrootsKnob[24] = 17
shift = 0
currentRootDis = 1
rootName = {}
rootName[1] = "A"
rootName[2] = "A#"
rootName[3] = "B"
rootName[4] = "C"
rootName[5] = "C#"
rootName[6] = "D"
rootName[7] = "D#"
rootName[8] = "E"
rootName[9] = "F"
rootName[10] = "F#"
rootName[11] = "G"
rootName[12] = "G#"
currentRootDisp = 1
laccidentalschromatic = {}
laccidentalschromatic[1] = "A"
laccidentalschromatic[2] = "A#"
laccidentalschromatic[3] = "B"
laccidentalschromatic[4] = "C"
laccidentalschromatic[5] = "C#"
laccidentalschromatic[6] = "D"
laccidentalschromatic[7] = "D#"
laccidentalschromatic[8] = "E"
laccidentalschromatic[9] = "F"
laccidentalschromatic[10] = "F#"
laccidentalschromatic[11] = "G"
laccidentalschromatic[12] = "G#"
sNoteIndex = {}
sNoteIndex[1] = 1
sNoteIndex[2] = 4
sNoteIndex[3] = 5
sNoteIndex[4] = 7
sNoteIndex[5] = 10
sNoteIndex[6] = 11
sNoteIndex[7] = 14
sNoteIndex[8] = 15
sNoteIndex[9] = 17
sNoteIndex[10] = 20
sNoteIndex[11] = 21
sNoteIndex[12] = 24
NotesnScale = 10
notesInC = 12
flatNoteIndex = {}
flatNoteIndex[1] = 1
flatNoteIndex[2] = 4
flatNoteIndex[3] = 5
flatNoteIndex[4] = 7
flatNoteIndex[5] = 10
flatNoteIndex[6] = 11
flatNoteIndex[7] = 14
flatNoteIndex[8] = 15
flatNoteIndex[9] = 17
flatNoteIndex[10] = 20
flatNoteIndex[11] = 21
flatNoteIndex[12] = 24
stroke = 0.9
locrootsKnob = {}
locrootsKnob[1] = 1
locrootsKnob[2] = 1
locrootsKnob[3] = 2
locrootsKnob[4] = 3
locrootsKnob[5] = 4
locrootsKnob[6] = 4
locrootsKnob[7] = 5
locrootsKnob[8] = 5
locrootsKnob[9] = 6
locrootsKnob[10] = 7
locrootsKnob[11] = 8
locrootsKnob[12] = 8
locrootsKnob[13] = 9
locrootsKnob[14] = 10
locrootsKnob[15] = 11
locrootsKnob[16] = 11
locrootsKnob[17] = 12
locrootsKnob[18] = 12
locrootsKnob[19] = 13
locrootsKnob[20] = 14
locrootsKnob[21] = 15
locrootsKnob[22] = 15
locrootsKnob[23] = 16
locrootsKnob[24] = 17
flatNoteIns = {}
c1_stroke = {}
c1_stroke[1] = 1.4518953061548
c1_stroke[2] = 0.71605322650299
c1_stroke[3] = 1.0839742663289
c1_stroke[4] = 0.5
nName = {}
nName[1] = "A"
nName[2] = "A#"
nName[3] = "B"
nName[4] = "C"
nName[5] = "C#"
nName[6] = "D"
nName[7] = "D#"
nName[8] = "E"
nName[9] = "F"
nName[10] = "F#"
nName[11] = "G"
nName[12] = "G#"
Scales = {}
Scales[1] = {}
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[1]["label"] = "Chromatic"
Scales[2] = {}
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[2]["label"] = "Ionian"
Scales[3] = {}
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[3]["label"] = "Dorian"
Scales[4] = {}
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[4]["label"] = "Phrygian"
Scales[5] = {}
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[5]["label"] = "Lydian"
Scales[6] = {}
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[6]["label"] = "Mixolydian"
Scales[7] = {}
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[7]["label"] = "Aeolian"
Scales[8] = {}
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[8]["label"] = "Locrian"
Scales[9] = {}
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 5
Scales[9]["notes"][5] = 6
Scales[9]["notes"][6] = 8
Scales[9]["notes"][7] = 10
Scales[9]["label"] = "1/2 Diminished"
Scales[10] = {}
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 1
Scales[10]["notes"][3] = 4
Scales[10]["notes"][4] = 5
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 8
Scales[10]["notes"][7] = 10
Scales[10]["label"] = "Spanish"
Scales[11] = {}
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 1
Scales[11]["notes"][3] = 4
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 7
Scales[11]["notes"][6] = 8
Scales[11]["notes"][7] = 11
Scales[11]["label"] = "Gypsy Maj/Arab"
Scales[12] = {}
Scales[12]["notes"] = {}
Scales[12]["notes"][1] = 0
Scales[12]["notes"][2] = 2
Scales[12]["notes"][3] = 3
Scales[12]["notes"][4] = 6
Scales[12]["notes"][5] = 7
Scales[12]["notes"][6] = 8
Scales[12]["notes"][7] = 11
Scales[12]["label"] = "Gypsy Minor"
Scales[13] = {}
Scales[13]["notes"] = {}
Scales[13]["notes"][1] = 0
Scales[13]["notes"][2] = 2
Scales[13]["notes"][3] = 3
Scales[13]["notes"][4] = 5
Scales[13]["notes"][5] = 7
Scales[13]["notes"][6] = 8
Scales[13]["notes"][7] = 11
Scales[13]["label"] = "Harmonic Minor"
Scales[14] = {}
Scales[14]["notes"] = {}
Scales[14]["notes"][1] = 0
Scales[14]["notes"][2] = 2
Scales[14]["notes"][3] = 3
Scales[14]["notes"][4] = 6
Scales[14]["notes"][5] = 7
Scales[14]["notes"][6] = 8
Scales[14]["notes"][7] = 10
Scales[14]["label"] = "Ukranian"
Scales[15] = {}
Scales[15]["notes"] = {}
Scales[15]["notes"][1] = 0
Scales[15]["notes"][2] = 2
Scales[15]["notes"][3] = 3
Scales[15]["notes"][4] = 4
Scales[15]["notes"][5] = 7
Scales[15]["notes"][6] = 9
Scales[15]["label"] = "Blues Major"
Scales[16] = {}
Scales[16]["notes"] = {}
Scales[16]["notes"][1] = 0
Scales[16]["notes"][2] = 3
Scales[16]["notes"][3] = 5
Scales[16]["notes"][4] = 6
Scales[16]["notes"][5] = 7
Scales[16]["notes"][6] = 10
Scales[16]["label"] = "Blues Minor"
Scales[17] = {}
Scales[17]["notes"] = {}
Scales[17]["notes"][1] = 0
Scales[17]["notes"][2] = 2
Scales[17]["notes"][3] = 4
Scales[17]["notes"][4] = 7
Scales[17]["notes"][5] = 9
Scales[17]["label"] = "Major Pent"
Scales[18] = {}
Scales[18]["notes"] = {}
Scales[18]["notes"][1] = 0
Scales[18]["notes"][2] = 2
Scales[18]["notes"][3] = 5
Scales[18]["notes"][4] = 7
Scales[18]["notes"][5] = 10
Scales[18]["label"] = "Susp/Egyptian"
Scales[19] = {}
Scales[19]["notes"] = {}
Scales[19]["notes"][1] = 0
Scales[19]["notes"][2] = 3
Scales[19]["notes"][3] = 5
Scales[19]["notes"][4] = 8
Scales[19]["notes"][5] = 10
Scales[19]["label"] = "Minor Blues P"
Scales[20] = {}
Scales[20]["notes"] = {}
Scales[20]["notes"][1] = 0
Scales[20]["notes"][2] = 2
Scales[20]["notes"][3] = 5
Scales[20]["notes"][4] = 7
Scales[20]["notes"][5] = 9
Scales[20]["label"] = "Major Blues/Yo"
Scales[21] = {}
Scales[21]["notes"] = {}
Scales[21]["notes"][1] = 0
Scales[21]["notes"][2] = 3
Scales[21]["notes"][3] = 5
Scales[21]["notes"][4] = 7
Scales[21]["notes"][5] = 10
Scales[21]["label"] = "Min Pent"
Scales[22] = {}
Scales[22]["notes"] = {}
Scales[22]["notes"][1] = 0
Scales[22]["notes"][2] = 4
Scales[22]["notes"][3] = 5
Scales[22]["notes"][4] = 7
Scales[22]["notes"][5] = 11
Scales[22]["label"] = "Ryūkyū"
Scales[23] = {}
Scales[23]["notes"] = {}
Scales[23]["notes"][1] = 0
Scales[23]["notes"][2] = 1
Scales[23]["notes"][3] = 5
Scales[23]["notes"][4] = 7
Scales[23]["notes"][5] = 8
Scales[23]["label"] = "In Pentatonic"
Scales[24] = {}
Scales[24]["notes"] = {}
Scales[24]["notes"][1] = 0
Scales[24]["notes"][2] = 2
Scales[24]["notes"][3] = 3
Scales[24]["notes"][4] = 7
Scales[24]["notes"][5] = 8
Scales[24]["label"] = "Hirajoshi"
Scales[25] = {}
Scales[25]["notes"] = {}
Scales[25]["notes"][1] = 0
Scales[25]["notes"][2] = 1
Scales[25]["notes"][3] = 3
Scales[25]["notes"][4] = 7
Scales[25]["notes"][5] = 8
Scales[25]["label"] = "Pelog"
Scales[26] = {}
Scales[26]["notes"] = {}
Scales[26]["notes"][1] = 0
Scales[26]["notes"][2] = 2
Scales[26]["notes"][3] = 4
Scales[26]["notes"][4] = 6
Scales[26]["notes"][5] = 8
Scales[26]["notes"][6] = 10
Scales[26]["label"] = "Whole Tone"
Scales[27] = {}
Scales[27]["notes"] = {}
Scales[27]["notes"][1] = 0
Scales[27]["notes"][2] = 1
Scales[27]["notes"][3] = 3
Scales[27]["notes"][4] = 4
Scales[27]["notes"][5] = 6
Scales[27]["notes"][6] = 7
Scales[27]["notes"][7] = 9
Scales[27]["notes"][8] = 10
Scales[27]["label"] = "Octatonic"
Scales[28] = {}
Scales[28]["notes"] = {}
Scales[28]["notes"][1] = 0
Scales[28]["notes"][2] = 2
Scales[28]["notes"][3] = 3
Scales[28]["notes"][4] = 4
Scales[28]["notes"][5] = 6
Scales[28]["notes"][6] = 7
Scales[28]["notes"][7] = 8
Scales[28]["notes"][8] = 10
Scales[28]["notes"][9] = 11
Scales[28]["label"] = "Messiaen 3rd"
Scales[29] = {}
Scales[29]["notes"] = {}
Scales[29]["notes"][1] = 0
Scales[29]["notes"][2] = 1
Scales[29]["notes"][3] = 2
Scales[29]["notes"][4] = 5
Scales[29]["notes"][5] = 6
Scales[29]["notes"][6] = 7
Scales[29]["notes"][7] = 8
Scales[29]["notes"][8] = 11
Scales[29]["label"] = "Messiaen 4th"
Scales[30] = {}
Scales[30]["notes"] = {}
Scales[30]["notes"][1] = 0
Scales[30]["notes"][2] = 1
Scales[30]["notes"][3] = 5
Scales[30]["notes"][4] = 6
Scales[30]["notes"][5] = 7
Scales[30]["notes"][6] = 11
Scales[30]["label"] = "Messiaen 5th"
Scales[31] = {}
Scales[31]["notes"] = {}
Scales[31]["notes"][1] = 0
Scales[31]["notes"][2] = 2
Scales[31]["notes"][3] = 4
Scales[31]["notes"][4] = 5
Scales[31]["notes"][5] = 6
Scales[31]["notes"][6] = 8
Scales[31]["notes"][7] = 10
Scales[31]["notes"][8] = 11
Scales[31]["label"] = "Messiaen 6th"
Scales[32] = {}
Scales[32]["notes"] = {}
Scales[32]["notes"][1] = 0
Scales[32]["notes"][2] = 1
Scales[32]["notes"][3] = 2
Scales[32]["notes"][4] = 3
Scales[32]["notes"][5] = 5
Scales[32]["notes"][6] = 6
Scales[32]["notes"][7] = 7
Scales[32]["notes"][8] = 8
Scales[32]["notes"][9] = 9
Scales[32]["notes"][10] = 11
Scales[32]["label"] = "Messiaen 7th"
Scales[33] = {}
Scales[33]["notes"] = {}
Scales[33]["notes"][1] = 0
Scales[33]["notes"][2] = 3
Scales[33]["notes"][3] = 6
Scales[33]["notes"][4] = 9
Scales[33]["label"] = "Min 3rd"
Scales[34] = {}
Scales[34]["notes"] = {}
Scales[34]["notes"][1] = 0
Scales[34]["notes"][2] = 4
Scales[34]["notes"][3] = 8
Scales[34]["label"] = "Maj 3rd"
Scales[35] = {}
Scales[35]["notes"] = {}
Scales[35]["notes"][1] = 0
Scales[35]["notes"][2] = 5
Scales[35]["label"] = "Fourth"
Scales[36] = {}
Scales[36]["notes"] = {}
Scales[36]["notes"][1] = 0
Scales[36]["notes"][2] = 7
Scales[36]["label"] = "Fifth"
currentRootDi = 1
rootD = {}
rootD[1] = 1
rootD[2] = 1
rootD[3] = 2
rootD[4] = 3
rootD[5] = 4
rootD[6] = 4
rootD[7] = 5
rootD[8] = 5
rootD[9] = 6
rootD[10] = 7
rootD[11] = 8
rootD[12] = 8
rootD[13] = 9
rootD[14] = 10
rootD[15] = 11
rootD[16] = 11
rootD[17] = 12
rootD[18] = 12
rootD[19] = 13
rootD[20] = 14
rootD[21] = 15
rootD[22] = 15
rootD[23] = 16
rootD[24] = 17
notes = 12
c1_fill = {}
c1_fill[1] = 0.72594765307739
c1_fill[2] = 0.71605322650299
c1_fill[3] = 1.0839742663289
c1_fill[4] = 0.05
rootDispla = {}
rootDispla[1] = 1
rootDispla[2] = 1
rootDispla[3] = 2
rootDispla[4] = 3
rootDispla[5] = 4
rootDispla[6] = 4
rootDispla[7] = 5
rootDispla[8] = 5
rootDispla[9] = 6
rootDispla[10] = 7
rootDispla[11] = 8
rootDispla[12] = 8
rootDispla[13] = 9
rootDispla[14] = 10
rootDispla[15] = 11
rootNote = {}
rootNote[1] = 0
rootNote[2] = 0
rootNote[3] = 1
rootNote[4] = 1
rootNote[5] = 2
rootNote[6] = 2
rootNote[7] = 3
rootNote[8] = 3
rootNote[9] = 4
rootNote[10] = 4
rootNote[11] = 5
rootNote[12] = 5
rootNote[13] = 6
rootNote[14] = 6
rootNote[15] = 7
rootNote[16] = 7
rootNote[17] = 8
cmode = 0
flatNoId = {}
flatNoId[1] = 1
flatNoId[2] = 4
flatNoId[3] = 5
flatNoId[4] = 7
flatNoId[5] = 10
flatNoId[6] = 11
flatNoId[7] = 14
flatNoId[8] = 15
flatNoId[9] = 17
flatNoId[10] = 20
flatNoId[11] = 21
flatNoId[12] = 24
shNoteIndex = {}
shNoteIndex[1] = 1
shNoteIndex[2] = 4
shNoteIndex[3] = 5
shNoteIndex[4] = 7
shNoteIndex[5] = 10
shNoteIndex[6] = 11
shNoteIndex[7] = 14
shNoteIndex[8] = 15
shNoteIndex[9] = 17
shNoteIndex[10] = 20
shNoteIndex[11] = 21
shNoteIndex[12] = 24
No = 10
m = 0
sharpNIndex = {}
sharpNIndex[1] = 1
sharpNIndex[2] = 4
sharpNIndex[3] = 5
sharpNIndex[4] = 7
sharpNIndex[5] = 10
sharpNIndex[6] = 11
sharpNIndex[7] = 14
sharpNIndex[8] = 15
sharpNIndex[9] = 17
sharpNIndex[10] = 20
sharpNIndex[11] = 21
sharpNIndex[12] = 24
                 input         
-- knob pointer

local function pointer(x, y, rot)
size = 3
color = color_paint(theme.text)
save()
translate{canvas_width/2, canvas_height/2}
	save()
	translate{x,y}
		save()
		rotate(rot)
		move_to{-size,size}
		line_to{size,size}
		line_to{0,0}
		line_to{-size,size}
		fill(color)
		restore()
	restore()
restore()
end


local radius = 34
     
px = radius * math.cos(input * math.pi*2 + math.pi/2)
py = -radius * math.sin(input * math.pi*2 + math.pi/2)
pointer(px, py, -input * math.pi*2)




    \(   (                     B=               <Q,   ,                       V R	               P(   (                   `À                   m      k       m<   <                    A   A    C  B   TrN                mod      R,   ,                   C  B  U?	               (   (                     D EDA               $   $                 -C4t-DK               n<   <                   A  A@     pA       orN                   m      k       
  
-- Knob graphics

-- add k and m input ports for knob and modulation

knobSize = 2 -- 1 = standard, 2 = mini, 3 = large
-- make Canvas width/height 50x50, 20x20 for mini, 70x70 for large

  
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 12.5 end
if knobSize == 3 then ksize = 35 end




-- Knob modulation: displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off, see below)

function clamp(x,a,b)
return math.max(math.min(x, a), b)
end

save()
translate{-2.5, -2.5} -- uncomment for mini (requires an extra translate to center)
-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, color_paint{.11,.11,.12,1})

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, color_paint(theme.grooves))


if knobStyle == 1 then

-- get knob and modulation values and scale for stroke_arc
a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, color_paint(theme.azureHighlight))

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

	-- change both to some other color (like red) to distinguish port from knob takeover
	if m >= 0 then
    	mpos = math.max(0,c)
    	stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, color_paint(theme.azureHighlight))
	elseif m < 0 then
    	mneg = math.min(0,c)
    	stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, color_paint(theme.grooves))
	end
end
	
if knobStyle == 2 then

-- get knob and modulation values and scale for stroke_arc
a = math.pi * (k-.5)
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
--stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, azure)

if k >= .5 then
	stroke_arc({ksize,ksize}, ksize-1, 2, a+math.pi/2, a, color_paint(theme.azureHighlight))
elseif k < .5 then
	stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, color_paint(theme.azureHighlight))
end
	
end
restore()

save()
translate{canvas_width/2,canvas_height/2}
scale{.75,.75}
min, max = text_bounds("Shift")
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
translate{-.5, 25}
text("Shift", theme.text)
restore()

save()
translate{canvas_width/2, canvas_height/2-5}
--scale{.75,.75}
min, max = text_bounds(math.floor(k*6.99-3))
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
text(math.floor(k*6.99-3), theme.text)
restore()

-- highlight current position (using stroke_arc aperture)
--stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2, .03, color_paint(theme.azureHighlight))   (z<   <                    A   A\    B  B   eeBN                mod     t^,   ,                   B  B B	               z<   <                    A   A     B  B   ep;CN                mod     _,   ,                   B  B pwC	               P{<   <                    A   A4     pA  C       CN                mod     c  
-- Bipolar modulation meter LED light

channels = 2

local function modLight(input, x, y)
	if mod > 0 and mod <= 1 then
		r = input
		g = input*.1
		b = 0
		a = 1
	elseif input > 1 then
		r,g,b,a = 1,.1,0,math.abs(input)
		
	elseif input <= 0 and mod >= -1 then
		r = math.abs(input*.2)
		g = math.abs(input*.3)
		b = math.abs(input)
		a = 1
	elseif input < -1 then
		r,g,b,a = .2,.3,1,math.abs(input)
	end
	
	save()
	translate{x,y}
		fill_circle({0,0}, 5, color_paint{r,g,b,a})
		fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})

	translate{-5,-4}
		text("M", theme.text)
	restore()
	
end

modLight(mod, 5, 5)
 b,   ,                   A   C   C	               ,   ,                 C   ~yCC                  invert for drawbar style    a(   (                 (   dbuCPC                k          clamp(1-k,0,1)   <   <                   B  A@     pA  B   w CB͏N                   m      k         -- Slider takeover - uses the same graphic style as the slider module, adds bipolar and drawbar styles



-- types: 1 = unipolar (standard), 2 = bipolar, 3 = drawbar
-- note: for drawbar type inverted slider (1-k) before input to Canvas

type = 1



-- Color is set up for linear gradient
color1 = theme.azureHighlight -- Dark
color2 = theme.azureHighlight






-- Draw graphics

save()
translate{10,4}
-- slider circle
	if type == 1 or type == 2 then
		fill_circle( {0, k*110},  9, color_paint{.12, .12, .13, 1})
	end
		
	if type == 3 then -- drawbar
		fill_circle( {0, (1-k)*110},  9, color_paint{.12, .12, .13, 1})
	end

-- background and slider groove
fill_rect( {-1.5, -0.5}, {1.5, 110.5}, 0, color_paint{.12, .12, .13, 1})
fill_rect( {-1, 0}, {1, 110}, 0, color_paint(theme.grooves))
		
if type == 1 then -- unipolar
	slider_color = linear_gradient({0,0}, {0,110}, color1, color2)
	stroke_segment( {0, 0}, {0, (m)*110}, 2, slider_color)
end
		
if type == 2 then -- bipolar
	if k >= .5 then
		slider_color = linear_gradient({0,55}, {0,110}, color1, color2)
		stroke_segment( {0, 55}, {0, (m)*110}, 2, slider_color)
	elseif k < .5 then
		slider_color = linear_gradient({0,0}, {0,55}, color2, color1)
		stroke_segment( {0, 55}, {0, (m)*110}, 2, slider_color)
	end
end
		
	if type == 3 then -- drawbar
	slider_color = linear_gradient({0,0}, {0,110}, color2, color1)
		stroke_segment( {0, 110}, {0, (1-(m))*110}, 2, slider_color)
	end
		
		
	-- slider circle
	if type == 1 or type == 2 then
		fill_circle( {0, (m) * 110},  9, color_paint {.84, .84, .84, .18})
	end
		
	if type == 3 then -- drawbar
		fill_circle( {0, (1-(m))*110},  9, color_paint {.84, .84, .84, .18})
	end
restore()


    Ti(   (                 (     wC  C                k          clamp(k,0,1)    (   (                     tB  C=               h , (                                                                                              h   (   (           .X>  A  pBļLq!               X$   $             A   A<C1^C
               $   $             A   BfùC	               x @   8 , $                                                                    7       6                          x   <   <           & 0   0     ?            B  "BvD               *  -  (  )  +  ,  .  /  xl,   ,                   p   A    p	               l(   (                    Xã_                   m      k       m,   ,                         4	               l(   (                 4                           m      k          clamp(k+m,0,1)  D   |  |                      A  Ad     A C   @$DN   6  Scales = {}
Scales[1] = {}
Scales[1]["label"] = "Chromatic"
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[2] = {}
Scales[2]["label"] = "Ionian"
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[3] = {}
Scales[3]["label"] = "Dorian"
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[4] = {}
Scales[4]["label"] = "Phrygian"
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[5] = {}
Scales[5]["label"] = "Lydian"
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[6] = {}
Scales[6]["label"] = "Mixolydian"
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[7] = {}
Scales[7]["label"] = "Aeolian"
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[8] = {}
Scales[8]["label"] = "Locrian"
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[9] = {}
Scales[9]["label"] = "1/2 Dimin"
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 5
Scales[9]["notes"][5] = 6
Scales[9]["notes"][6] = 8
Scales[9]["notes"][7] = 10
Scales[10] = {}
Scales[10]["label"] = "Spanish"
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 1
Scales[10]["notes"][3] = 4
Scales[10]["notes"][4] = 5
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 8
Scales[10]["notes"][7] = 10
Scales[11] = {}
Scales[11]["label"] = "Gyp Maj/Arab"
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 1
Scales[11]["notes"][3] = 4
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 7
Scales[11]["notes"][6] = 8
canvas_height = 10
canvas_width = 20
currentRoot = 0
currentScale = 1
input = 0
max = {}
max[1] = 28.295999526978
max[2] = 8.3999996185303
min = {}
min[1] = 0.83999997377396
min[2] = 0
root = 0
rootId = 1
rootName = {}
rootName[1] = "A"
rootName[2] = "A#"
rootName[3] = "B"
rootName[4] = "C"
rootName[5] = "C#"
rootName[6] = "D"
rootName[7] = "D#"
rootName[8] = "E"
rootName[9] = "F"
rootName[10] = "F#"
rootName[11] = "G"
rootName[12] = "G#"
scl = 0
                 

save()
translate{canvas_width/2, canvas_height/2}
min, max = text_bounds("Scale")
--scale{.75,.75}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2-2.5}
text("Scale", theme.text)
restore()  P(   (                      C  D=               {(   (                 ,   ҈AQC                shift          floor(shift*6.99-3) {(   (                 ,   TB                fine           (fine-.5)/12  j H D < 0               ,                    (                               $   ;                 j   D   A  A                     C  ChB    \B  /C     RD  CN   pA  Note = -16
P0 = {}
P0[1] = -0.5
P0[2] = 0.425
P1 = {}
P1[1] = 5.5
P1[2] = 0
P2 = {}
P2[1] = 5.5
P2[2] = 7
P3 = {}
P3[1] = 0.2
P3[2] = 4
Radius = 34
Scales = {}
Scales[1] = {}
Scales[1]["label"] = "Chromatic"
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[2] = {}
Scales[2]["label"] = "Ionian"
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[3] = {}
Scales[3]["label"] = "Dorian"
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[4] = {}
Scales[4]["label"] = "Phrygian"
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[5] = {}
Scales[5]["label"] = "Lydian"
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[6] = {}
Scales[6]["label"] = "Mixolydian"
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[7] = {}
Scales[7]["label"] = "Aeolian"
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[8] = {}
Scales[8]["label"] = "Locrian"
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[9] = {}
Scales[9]["label"] = "1/2 Dimin"
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 5
Scales[9]["notes"][5] = 6
Scales[9]["notes"][6] = 8
Scales[9]["notes"][7] = 10
Scales[10] = {}
Scales[10]["label"] = "Spanish"
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 1
Scales[10]["notes"][3] = 4
Scales[10]["notes"][4] = 5
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 8
Scales[10]["notes"][7] = 10
Scales[11] = {}
Scales[11]["label"] = "Gyp Maj/Arab"
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 1
Scales[11]["notes"][3] = 4
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 7
Scales[11]["notes"][6] = 8
Scales[11]["notes"][7] = 11
Scales[12] = {}
Scales[12]["label"] = "Gypsy Minor"
Scales[12]["notes"] = {}
Scales[12]["notes"][1] = 0
Scales[12]["notes"][2] = 2
Scales[12]["notes"][3] = 3
Scales[12]["notes"][4] = 6
Scales[12]["notes"][5] = 7
Scales[12]["notes"][6] = 8
Scales[12]["notes"][7] = 11
Scales[13] = {}
Scales[13]["label"] = "Harmonic Min"
Scales[13]["notes"] = {}
Scales[13]["notes"][1] = 0
Scales[13]["notes"][2] = 2
Scales[13]["notes"][3] = 3
Scales[13]["notes"][4] = 5
Scales[13]["notes"][5] = 7
Scales[13]["notes"][6] = 8
Scales[13]["notes"][7] = 11
Scales[14] = {}
Scales[14]["label"] = "Ukranian"
Scales[14]["notes"] = {}
Scales[14]["notes"][1] = 0
Scales[14]["notes"][2] = 2
Scales[14]["notes"][3] = 3
Scales[14]["notes"][4] = 6
Scales[14]["notes"][5] = 7
Scales[14]["notes"][6] = 8
Scales[14]["notes"][7] = 10
Scales[15] = {}
Scales[15]["label"] = "Blues Maj"
Scales[15]["notes"] = {}
Scales[15]["notes"][1] = 0
Scales[15]["notes"][2] = 2
Scales[15]["notes"][3] = 3
Scales[15]["notes"][4] = 4
Scales[15]["notes"][5] = 7
Scales[15]["notes"][6] = 9
Scales[16] = {}
Scales[16]["label"] = "Blues Min"
Scales[16]["notes"] = {}
Scales[16]["notes"][1] = 0
Scales[16]["notes"][2] = 3
Scales[16]["notes"][3] = 5
Scales[16]["notes"][4] = 6
Scales[16]["notes"][5] = 7
Scales[16]["notes"][6] = 10
Scales[17] = {}
Scales[17]["label"] = "Maj Pent"
Scales[17]["notes"] = {}
Scales[17]["notes"][1] = 0
Scales[17]["notes"][2] = 2
Scales[17]["notes"][3] = 4
Scales[17]["notes"][4] = 7
Scales[17]["notes"][5] = 9
Scales[18] = {}
Scales[18]["label"] = "Susp/Egyp P"
Scales[18]["notes"] = {}
Scales[18]["notes"][1] = 0
Scales[18]["notes"][2] = 2
Scales[18]["notes"][3] = 5
Scales[18]["notes"][4] = 7
Scales[18]["notes"][5] = 10
Scales[19] = {}
Scales[19]["label"] = "Min Blues P"
Scales[19]["notes"] = {}
Scales[19]["notes"][1] = 0
Scales[19]["notes"][2] = 3
Scales[19]["notes"][3] = 5
Scales[19]["notes"][4] = 8
Scales[19]["notes"][5] = 10
Scales[20] = {}
Scales[20]["label"] = "Maj Blues/Yo"
Scales[20]["notes"] = {}
Scales[20]["notes"][1] = 0
Scales[20]["notes"][2] = 2
Scales[20]["notes"][3] = 5
Scales[20]["notes"][4] = 7
Scales[20]["notes"][5] = 9
Scales[21] = {}
Scales[21]["label"] = "Min Pent"
Scales[21]["notes"] = {}
Scales[21]["notes"][1] = 0
Scales[21]["notes"][2] = 3
Scales[21]["notes"][3] = 5
Scales[21]["notes"][4] = 7
Scales[21]["notes"][5] = 10
Scales[22] = {}
Scales[22]["label"] = "Ryūkyū"
Scales[22]["notes"] = {}
Scales[22]["notes"][1] = 0
Scales[22]["notes"][2] = 4
Scales[22]["notes"][3] = 5
Scales[22]["notes"][4] = 7
Scales[22]["notes"][5] = 11
Scales[23] = {}
Scales[23]["label"] = "In Pent"
Scales[23]["notes"] = {}
Scales[23]["notes"][1] = 0
Scales[23]["notes"][2] = 1
Scales[23]["notes"][3] = 5
Scales[23]["notes"][4] = 7
Scales[23]["notes"][5] = 8
Scales[24] = {}
Scales[24]["label"] = "Hirajoshi"
Scales[24]["notes"] = {}
Scales[24]["notes"][1] = 0
Scales[24]["notes"][2] = 2
Scales[24]["notes"][3] = 3
Scales[24]["notes"][4] = 7
Scales[24]["notes"][5] = 8
Scales[25] = {}
Scales[25]["label"] = "Pelog"
Scales[25]["notes"] = {}
Scales[25]["notes"][1] = 0
Scales[25]["notes"][2] = 1
Scales[25]["notes"][3] = 3
Scales[25]["notes"][4] = 7
Scales[25]["notes"][5] = 8
Scales[26] = {}
Scales[26]["label"] = "Whole Tone"
Scales[26]["notes"] = {}
Scales[26]["notes"][1] = 0
Scales[26]["notes"][2] = 2
Scales[26]["notes"][3] = 4
Scales[26]["notes"][4] = 6
Scales[26]["notes"][5] = 8
Scales[26]["notes"][6] = 10
Scales[27] = {}
Scales[27]["label"] = "Octatonic"
Scales[27]["notes"] = {}
Scales[27]["notes"][1] = 0
Scales[27]["notes"][2] = 1
Scales[27]["notes"][3] = 3
Scales[27]["notes"][4] = 4
Scales[27]["notes"][5] = 6
Scales[27]["notes"][6] = 7
Scales[27]["notes"][7] = 9
Scales[27]["notes"][8] = 10
Scales[28] = {}
Scales[28]["label"] = "Messiaen 3rd"
Scales[28]["notes"] = {}
Scales[28]["notes"][1] = 0
Scales[28]["notes"][2] = 2
Scales[28]["notes"][3] = 3
Scales[28]["notes"][4] = 4
Scales[28]["notes"][5] = 6
Scales[28]["notes"][6] = 7
Scales[28]["notes"][7] = 8
Scales[28]["notes"][8] = 10
Scales[28]["notes"][9] = 11
Scales[29] = {}
Scales[29]["label"] = "Messiaen 4th"
Scales[29]["notes"] = {}
Scales[29]["notes"][1] = 0
Scales[29]["notes"][2] = 1
Scales[29]["notes"][3] = 2
Scales[29]["notes"][4] = 5
Scales[29]["notes"][5] = 6
Scales[29]["notes"][6] = 7
Scales[29]["notes"][7] = 8
Scales[29]["notes"][8] = 11
Scales[30] = {}
Scales[30]["label"] = "Messiaen 5th"
Scales[30]["notes"] = {}
Scales[30]["notes"][1] = 0
Scales[30]["notes"][2] = 1
Scales[30]["notes"][3] = 5
Scales[30]["notes"][4] = 6
Scales[30]["notes"][5] = 7
Scales[30]["notes"][6] = 11
Scales[31] = {}
Scales[31]["label"] = "Messiaen 6th"
Scales[31]["notes"] = {}
Scales[31]["notes"][1] = 0
Scales[31]["notes"][2] = 2
Scales[31]["notes"][3] = 4
Scales[31]["notes"][4] = 5
Scales[31]["notes"][5] = 6
Scales[31]["notes"][6] = 8
Scales[31]["notes"][7] = 10
Scales[31]["notes"][8] = 11
Scales[32] = {}
Scales[32]["label"] = "Messiaen 7th"
Scales[32]["notes"] = {}
Scales[32]["notes"][1] = 0
Scales[32]["notes"][2] = 1
Scales[32]["notes"][3] = 2
Scales[32]["notes"][4] = 3
Scales[32]["notes"][5] = 5
Scales[32]["notes"][6] = 6
Scales[32]["notes"][7] = 7
Scales[32]["notes"][8] = 8
Scales[32]["notes"][9] = 9
Scales[32]["notes"][10] = 11
Scales[33] = {}
Scales[33]["label"] = "Min 3rd"
Scales[33]["notes"] = {}
Scales[33]["notes"][1] = 0
Scales[33]["notes"][2] = 3
Scales[33]["notes"][3] = 6
Scales[33]["notes"][4] = 9
Scales[34] = {}
Scales[34]["label"] = "Maj 3rd"
Scales[34]["notes"] = {}
Scales[34]["notes"][1] = 0
Scales[34]["notes"][2] = 4
Scales[34]["notes"][3] = 8
Scales[35] = {}
Scales[35]["label"] = "Fourth"
Scales[35]["notes"] = {}
Scales[35]["notes"][1] = 0
Scales[35]["notes"][2] = 5
Scales[36] = {}
Scales[36]["label"] = "Fifth"
Scales[36]["notes"] = {}
Scales[36]["notes"][1] = 0
Scales[36]["notes"][2] = 7
_color = {}
_color[1] = 0.051
_color[2] = 0.051
_color[3] = 0.051
_color[4] = 0.5
_y = 44.432588009297
a = 1
a2 = 0.5
aRadius = 34
a_text_lines = 0.5
accId = 12
agap = 0.005
an = -1.5707963267949
ang = -1.5707963267949
angl = -1.5707963267949
angle = 1.5707963267949
arRadius = 34
arcGap = 0.008
arcRadius = 42
arcWidth = 15
arc_gap = 0.01
arcgap = 0.005
argap = 0.005
ax = -8.7998475334857
axy = {}
axy[1] = 0.2
axy[2] = 4
ay = 32.841478093828
b = -11.905676074716
bx = -10.870399894306
bxy = {}
bxy[1] = 0.2
bxy[2] = 4
by = 40.568884704141
canvas_height = 140
canvas_width = 140
circle_color = {}
circle_color[1] = 0.8
circle_color[2] = 0.8
circle_color[3] = 0.8
circle_color[4] = 0
circle_radius = 0.5
circle_stroke_color = {}
circle_stroke_color[1] = 0.05
circle_stroke_color[2] = 0.05
circle_stroke_color[3] = 0.05
circle_stroke_color[4] = 0
cosx = 0.25881904510252
currentNote = 4
currentOctave = 4
currentRoot = 3
currentScale = 9
cxy = {}
cxy[1] = 95.7
cxy[2] = 0
f_color = {}
f_color[1] = 0.051
f_color[2] = 0.051
f_color[3] = 0.051
f_color[4] = 0.5
fi_color = {}
fi_color[1] = 0.051
fi_color[2] = 0.051
fi_color[3] = 0.051
fi_color[4] = 0.5
fil_color = {}
fil_color[1] = 0.051
fil_color[2] = 0.051
fil_color[3] = 0.051
fil_color[4] = 0.5
fill_color = {}
fill_color[1] = 0.16
fill_color[2] = 0.112
fill_color[3] = 0.136
fill_color[4] = 1
gap = 0.5
gate = {}
gate[1] = 1
gate[2] = 1
gate[3] = 1
gate[4] = 1
gate0 = 1
gate1 = 1
gate2 = 1
gate3 = 1
gates = {}
gates[1] = 0
gates[2] = 0
gates[3] = 0
gates[4] = 0
h = 0.91666666666667
h2 = 8
hi = 0
high = 0
highl = 0
highli = 0
highligh = 0
highlight = {}
highlight[0] = 1
highlight[2] = 1
highlight[3] = 1
highlight[6] = 1
highlight[7] = 1
highlight[8] = 1
highlight[11] = 1
highlightN = 0
highlightNo = 0
highlightNot = 0
highlightNote = -24
i = 1
iLength = 12
input = 1.0749994516373
input0 = -1.3333332538605
input1 = -1.3333332538605
input2 = -1.3333332538605
input3 = -1.3333332538605
ins = {}
ins[1] = -1.3333332538605
ins[2] = -1.3333332538605
ins[3] = -1.3333332538605
ins[4] = -1.3333332538605
kern_table = {}
kern_table[1] = 0
kern_table[2] = 0
kern_table[3] = 0.5
kern_table[4] = 0.5
kern_table[5] = 0
kern_table[6] = 0.5
kern_table[7] = 0
kern_table[8] = 0.5
kern_table[9] = 0.5
kern_table[10] = 0
kern_table[11] = 0.5
kern_table[12] = 0
lRadius = 34
laRadius = 34
laccId = 12
larRadius = 34
larcGap = 0.008
larcRadius = 42
larcWidth = 15
largRadius = 34
largeRadius = 34
lcircle_radius = 0.5
lcosx = 0.25881904510252
lcurrentNote = 4
lcurrentRoot = 3
lcurrentScale = 21
length = 70
lgap = 0.5
liLength = 12
lineRadius = 48
lineRadius0 = 15
lineRadius1 = 50
line_color = {}
line_color[1] = 0.839
line_color[2] = 0.839
line_color[3] = 0.839
line_color[4] = 1
line_color0 = {}
line_color0[1] = 0.11
line_color0[2] = 0.11
line_color0[3] = 0.11
line_color0[4] = 1
line_color1 = {}
line_color1[1] = 0.5
line_color1[2] = 0.5
line_color1[3] = 0.5
line_color1[4] = 0.5
line_stroke = 0.5
linput0 = 0.70250022411346
llineRadius0 = 15
llineRadius1 = 50
lline_stroke = 0.5
lnoteCircle_stroke = 0.25
loaccId = 12
loarcGap = 0.008
loarcRadius = 42
loarcWidth = 15
locaccId = 12
locacosx = 0.25881904510252
locacurrentNote = 4
localaccId = 12
localcosx = 0.25881904510252
localcurrentNote = 4
localcurrentRoot = 3
localcurrentScale = 21
localiLength = 12
localinput0 = 0.70250022411346
localrootId = 10
localsiny = -0.96592582628907
localsize = 3
localtextRadius = 57
locarcGap = 0.008
locarcRadius = 42
locarcWidth = 15
loccircle_radius = 0.5
loccosx = 0.25881904510252
loccurrentNote = 4
loccurrentRoot = 3
loccurrentScale = 21
locgap = 0.5
lociLength = 12
locinput0 = 0.70250022411346
locircle_radius = 0.5
loclineRadius0 = 15
loclineRadius1 = 50
locline_stroke = 0.5
locnoteCircle_stroke = 0.25
locosx = 0.25881904510252
locpointer_radius = 30
locrootDisplay = {}
locrootDisplay[1] = 1
locrootDisplay[2] = 1
locrootDisplay[3] = 2
locrootDisplay[4] = 3
locrootDisplay[5] = 4
locrootDisplay[6] = 4
locrootId = 10
locsiny = -0.96592582628907
locsize = 3
locteardropRadius = 39
loctextRadius = 57
locurrentNote = 4
locurrentRoot = 3
locurrentScale = 21
logap = 0.5
loiLength = 12
loinput0 = 0.70250022411346
lolineRadius0 = 15
lolineRadius1 = 50
loline_stroke = 0.5
lonoteCircle_stroke = 0.25
lopointer_radius = 30
lorootDisplay = {}
lorootDisplay[1] = 1
lorootDisplay[2] = 1
lorootDisplay[3] = 2
lorootDisplay[4] = 3
lorootDisplay[5] = 4
lorootDisplay[6] = 4
lorootDisplay[7] = 5
lorootDisplay[8] = 5
lorootDisplay[9] = 6
lorootDisplay[10] = 7
lorootDisplay[11] = 8
lorootDisplay[12] = 8
lorootDisplay[13] = 9
lorootDisplay[14] = 10
lorootDisplay[15] = 11
lorootId = 10
losiny = -0.96592582628907
losize = 3
loteardropRadius = 39
lotextRadius = 57
lpointer_radius = 30
lrootDisplay = {}
lrootId = 10
lsiny = -0.96592582628907
lsize = 3
lteardropRadius = 39
ltextRadius = 57
max = {}
max[1] = 50.088001251221
max[2] = 9.5159997940063
min = {}
min[1] = 0.83999997377396
min[2] = -1.1160000562668
mode = 0
n = 5
noteCircle_stroke = 0.25
noteLabel = {}
noteLabel[1] = "A"
noteLabel[2] = "#"
noteLabel[3] = "B"
noteLabel[4] = "C"
noteLabel[5] = "#"
noteLabel[6] = "D"
noteLabel[7] = "#"
noteLabel[8] = "E"
noteLabel[9] = "F"
noteLabel[10] = "#"
noteLabel[11] = "G"
noteLabel[12] = "#"
noteTranspose = 8
oct = 1
octave = 0
phase = -1.5707963267949
pointer_radius = 30
px = 0.2
py = 4
radius = 2.5
rdm = {}
rdm[1] = 0.65602757998039
rdm[2] = 0.3785321260049
rdm[3] = 0.12103426319473
rdm[4] = 0.86195211205899
rdm[5] = 0.56847555038083
rdm[6] = 0.8450904698416
rdm[7] = 0.78820399802295
rdm[8] = 0.60366161476274
rdm[9] = 0.40629710401831
rdm[10] = 0.2045765011128
rdm[11] = 0.16267396559006
rdm[12] = 0.55764200436788
rdm_gap = 0.3
root = 0
rootDisplay = {}
rootDisplay[1] = 1
rootDisplay[2] = 1
rootDisplay[3] = 2
rootDisplay[4] = 3
rootDisplay[5] = 4
rootDisplay[6] = 4
rootDisplay[7] = 5
rootDisplay[8] = 5
rootDisplay[9] = 6
rootDisplay[10] = 7
rootDisplay[11] = 8
rootDisplay[12] = 8
rootDisplay[13] = 9
rootDisplay[14] = 10
rootDisplay[15] = 11
rootDisplay[16] = 11
rootDisplay[17] = 12
rootDisplay[18] = 12
rootDisplay[19] = 13
rootDisplay[20] = 14
rootDisplay[21] = 15
rootDisplay[22] = 15
rootDisplay[23] = 16
rootDisplay[24] = 17
rootId = 10
rootName = {}
rootName[1] = "A"
rootName[2] = "A#"
rootName[3] = "B"
rootName[4] = "C"
rootName[5] = "C#"
rootName[6] = "D"
rootName[7] = "D#"
rootName[8] = "E"
rootName[9] = "F"
rootName[10] = "F#"
rootName[11] = "G"
rootName[12] = "G#"
rot = 0.95833333333333
s = 0.8
scl = 0.31317275762558
segments = 10
shift_text = 0
siny = -0.96592582628907
size = 0.75
stroke = 0.85
stroke_color = {}
stroke_color[1] = 0.051
stroke_color[2] = 0.051
stroke_color[3] = 0.051
stroke_color[4] = 1
sx = 0.5
t = 1
t_color = {}
t_color[1] = 0
t_color[2] = 0.831
t_color[3] = 1
t_color[4] = 1
t_y = 44.432588009297
tdrop_circle_radius_offset = -0.2
tdrop_circle_yoffset = 1
tdrop_height = 5
tdrop_width = 1.8
teRadius = 34
te_color = {}
te_color[1] = 0
te_color[2] = 0.831
te_color[3] = 1
te_color[4] = 1
te_y = 44.432588009297
tearRadius = 34
teardRadius = 34
teardroRadius = 34
teardropRadius = 43
tex = -11.905676074716
texRadius = 34
tex_color = {}
tex_color[1] = 0
tex_color[2] = 0.831
tex_color[3] = 1
tex_color[4] = 1
tex_y = 44.432588009297
textRadius = 57
text_color = {}
text_color[1] = 0.839
text_color[2] = 0.839
text_color[3] = 0.839
text_color[4] = 1
text_radius = 44
text_size = 0.9
text_x = -11.905676074716
text_y = 44.432588009297
textx = -11.905676074716
texx = -11.905676074716
tx = -11.905676074716
v = 0.45
voices = 1
w = 80
w2 = 2.7
white = {}
white[1] = 0.84
white[2] = 0.84
white[3] = 0.84
white[4] = 1
x = -8.7998475334857
x1 = -11.905676074716
y1 = 44.432588009297
y_y = 44.432588009297
yr_y = 44.432588009297
yrx_y = 44.432588009297
yrxy = 44.432588009297
yrxy_y = 44.432588009297
yrxyy = 44.432588009297
yry = 44.432588009297
yy = 44.432588009297
                       |   l   \   L   <   ,                mode       oct    scl    root       voices     gate3      gate2      gate1      gate0      input3     input2     input1     input0      L@  

-- Pitch wheel intervals by Jerry Smith and Rudiger Meyer, 2023

-------------------------------------------------------------
Scales = {
{ label = "Chromatic", 	    notes = { 0,1,2,3,4,5,6,7,8,9,10,11 } },
{ label = "Ionian", 	    notes = { 0,2,4,5,7,9,11 } },
{ label = "Dorian", 	    notes = { 0,2,3,5,7,9,10 } },
{ label = "Phrygian", 	    notes = { 0,1,3,5,7,8,10 } },
{ label = "Lydian", 	    notes = { 0,2,4,6,7,9,11 } },
{ label = "Mixolydian",     notes = { 0,2,4,5,7,9,10 } },
{ label = "Aeolian", 	    notes = { 0,2,3,5,7,8,10 } },
{ label = "Locrian", 	    notes = { 0,1,3,5,6,8,10 } },
{ label = "1/2 Dimin", 	    notes = { 0,2,3,5,6,8,10 } },
{ label = "Spanish", 	    notes = { 0,1,4,5,7,8,10 } },
{ label = "Gyp Maj/Arab", 	notes = { 0,1,4,5,7,8,11 } },
{ label = "Gypsy Minor", 	notes = { 0,2,3,6,7,8,11 } },
{ label = "Harmonic Min", 	notes = { 0,2,3,5,7,8,11 } },
{ label = "Ukranian", 	    notes = { 0,2,3,6,7,8,10 } },
{ label = "Blues Maj", 	    notes = { 0,2,3,4,7,9 } },
{ label = "Blues Min", 	    notes = { 0,3,5,6,7,10 } },
{ label = "Maj Pent", 	    notes = { 0,2,4,7,9 } },
{ label = "Susp/Egyp P",	notes = { 0,2,5,7,10 } },
{ label = "Min Blues P", 	notes = { 0,3,5,8,10 } },
{ label = "Maj Blues/Yo", 	notes = { 0,2,5,7,9 } },
{ label = "Min Pent", 	    notes = { 0,3,5,7,10 } },
{ label = "Ryūkyū", 	    notes = { 0,4,5,7,11 } },
{ label = "In Pent", 	    notes = { 0,1,5,7,8 } },
{ label = "Hirajoshi", 	    notes = { 0,2,3,7,8 } },
{ label = "Pelog", 	        notes = { 0,1,3,7,8 } },
{ label = "Whole Tone", 	notes = { 0,2,4,6,8,10 } },
{ label = "Octatonic", 	    notes = { 0,1,3,4,6,7,9,10 } },
{ label = "Messiaen 3rd", 	notes = { 0,2,3,4,6,7,8,10,11 } },
{ label = "Messiaen 4th", 	notes = { 0,1,2,5,6,7,8,11 } },
{ label = "Messiaen 5th", 	notes = { 0,1,5,6,7,11 } },
{ label = "Messiaen 6th", 	notes = { 0,2,4,5,6,8,10,11 } },
{ label = "Messiaen 7th", 	notes = { 0,1,2,3,5,6,7,8,9,11 } },
{ label = "Min 3rd", 	    notes = { 0,3,6,9 } },
{ label = "Maj 3rd", 	    notes = { 0,4,8 } },
{ label = "Fourth", 		notes = { 0,5 } },
{ label = "Fifth", 		    notes = { 0,7 } },
}


-- mappings for input(s), root, scale and octave to note names and wheel --
local iLength = oct * 12
local currentRoot = math.floor(root * 11.99)
local rootDisplay = {1,1,2,3,4,4,5,5,6,7,8,8,9,10,11,11,12,12,13,14,15,15,16,17}
local rootId = rootDisplay[math.floor(root * 23.99) + 1]
local roots = {"A","A#","Bb","B","C","C#","Db","D","D#","Eb","E","F","F#","Gb","G","G#","Ab"}
local currentScale = math.floor(scl * (#Scales - 0.001)) + 1


	
	
local function noteLabel(x, y, j, size, text_color)

local accidentals = { -- uses "×" for double sharp
    {"A", "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"},
    {"A#", "B", "B#", "C#", "C×", "D#", "D#", "E#", "F#", "F×", "G#", "G×"},
    {"Bb", "Cb", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A"},
    {"B", "C", "C#", "D", "D#", "E", "E#", "F#", "G", "G#", "A", "A#"},
    {"C", "Db", "D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B"},
    {"C#", "D", "D#", "E", "E#", "F#", "F×", "G#", "A", "A#", "B", "B#"},
    {"Db", "Ebb", "Eb", "Fb", "F", "Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C"},
    {"D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B", "C", "C#"},
    {"D#", "E", "E#", "F#", "F×", "G#", "G×", "A#", "B", "B#", "C#", "C×"},
    {"Eb", "Fb", "F", "Gb", "G", "Ab", "A", "Bb", "Cb", "C", "Db", "D"},
    {"E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"},
    {"F", "Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E"},
    {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "E#"},
    {"Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C", "Db", "Ebb", "Eb", "Fb", "F"},
    {"G", "Ab", "A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#"},
    {"G#", "A", "A#", "B", "B#", "C#", "C×", "D#", "E", "E#", "F#", "F×"},
    {"Ab", "Bbb", "Bb", "Cb", "C", "Db", "D", "Eb", "Fb", "F", "Gb", "G"}
}

local accidentals_flat5 = {
-- for scales with the flattened 5th
	{"A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#"},
    {"A#", "B", "B#", "C#", "C×", "D#", "E", "E#", "F#", "F×", "G#", "G×"},
    {"Bb", "Cb", "C", "Db", "D", "Eb", "Fb", "F", "Gb", "G", "Ab", "A"},
    {"B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"},
    {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"},
    {"C#", "D", "D#", "E", "E#", "F#", "G", "G#", "A", "A#", "B", "B#"},
    {"Db", "Ebb", "Eb", "Fb", "F", "Gb", "Abb", "Ab", "Bbb", "Bb", "Cb", "C"},
    {"D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B", "C", "C#"},
    {"D#", "E", "E#", "F#", "F×", "G#", "A", "A#", "B", "B#", "C#", "C×"},
    {"Eb", "Fb", "F", "Gb", "G", "Ab", "Bbb", "Bb", "Cb", "C", "Db", "D"},
    {"E", "F", "F#", "G", "G#", "A", "Bb", "B", "C", "C#", "D", "D#"},
    {"F", "Gb", "G", "Ab", "A", "Bb", "Cb", "C", "Db", "D", "Eb", "E"},
    {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "E#"},
    {"Gb", "G", "Ab", "Bbb", "Bb", "Cb", "Dbb", "Db", "Ebb", "Eb", "Fb", "F"},
    {"G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "F#"},
    {"G#", "A", "A#", "B", "B#", "C#", "D", "D#", "E", "E#", "F#", "F×"},
    {"Ab", "Bbb", "Bb", "Cb", "C", "Db", "Ebb", "Eb", "Fb", "F", "Gb", "G"}
}

local accidentals_chromatic = {
-- for the chromatic scale, wholetone + Messiaen 6th mode
	{"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"},
	{"A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A"},
	{"Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A"},
	{"B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#"},
	{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"},
	{"C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C"},	
	{"Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "C"},
	{"D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#"},
	{"D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D"},
	{"Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D"},
	{"E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#"},
	{"F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E"},
	{"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F"},		
	{"Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F"},
	{"G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#"},
	{"G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G"},
	{"Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G"}
}

function flatSymbol()
	paint = color_paint(text_color)
	stroke = .85
	segments = 10 -- segments in curve
	
	save()
	translate{0,0}
	stroke_segment( {0, 0}, {0, 8}, stroke, paint)
	
	-- cubic bezier control points
	P0 = {-.5, stroke*.5}
	P1 = {5.5, 0}
	P2 = {5.5, 7}
	P3 = {0.2, 4}
		
	axy = {0, stroke*.5}
   	for i = 1, segments do
    	t = i/segments
    	px = (1-t)^3*P0[1] + 3*(1-t)^2 * t*P1[1] + 3*(1-t) * t^2*P2[1] + t^3*P3[1]
    	py = (1-t)^3*P0[2] + 3*(1-t)^2 * t*P1[2] + 3*(1-t) * t^2*P2[2] + t^3*P3[2]
   	    bxy = {px, py}
    	stroke_segment(axy, bxy, stroke, paint)
    	fill_circle(bxy, stroke*.49, paint)
       	axy = bxy		
    end	
	restore()
end
	
	
local function sharpSymbol()
    local w, h = 5.5, 7.5
    local vstroke = .8
    local hstroke = .9
    local vspread = 1.1
   	local hspread = 1.3
    local shear = 1

   	local function shearY(x, y)
       	return x, y + (x * shear * hspread/w)
   	end

   	save()
   	translate{0,-.25}
   	local function drawRect(x1, y1, x2, y2)
       	move_to{shearY(x1, y1)}        	
       	line_to{shearY(x2, y1)}
        line_to{shearY(x2, y2)}
       	line_to{shearY(x1, y2)}
       	line_to{shearY(x1, y1)}
       	fill(color_paint(text_color))
   	end

   	drawRect(0, h/2 - hspread - hstroke/2, w, h/2 - hspread + hstroke/2) -- Top
   	drawRect(0, h/2 + vspread - hstroke/2, w, h/2 + vspread + hstroke/2) -- Bottom
   	drawRect(w/2 - vspread - vstroke/2, 0, w/2 - vspread + vstroke/2, h) -- Left
   	drawRect(w/2 + vspread - vstroke/2, 0, w/2 + vspread + vstroke/2, h) -- Right
   	restore()
end


local function doubleSharpSymbol()
	local w = 5
	local h = 5
	local rSize = 1.5
	local cRad = 0

	paint = color_paint(text_color)
	save()
	translate{w/4,h/3}
	fill_rect({0, 0}, {rSize, rSize}, cRad, paint)
	fill_rect({w - rSize, 0}, {w, rSize}, cRad, paint)
	fill_rect({0, h - rSize}, {rSize, h}, cRad, paint)
	fill_rect({w - rSize, h - rSize}, {w, h}, cRad, paint)

	stroke_segment({rSize/2, rSize/2}, {w - rSize/2, h - rSize/2}, rSize/1.8, paint)
	stroke_segment({w - rSize/2, rSize/2}, {rSize/2, h - rSize/2}, rSize/1.8, paint)
	restore()
end

	-- designate accidentals
	local noteName
		if currentScale == 8 
		or currentScale == 9 
		or currentScale == 27 
		or currentScale == 29 
		or currentScale == 30 
		or currentScale == 32 
		then noteName = accidentals_flat5[rootId]
	elseif currentScale == 1 
		or currentScale == 26 
		or currentScale == 31 
		then noteName = accidentals_chromatic[rootId]
	else
		noteName = accidentals[rootId]
	end
	
	local accId = j % #accidentals[1]+1
	local flatNote = noteName[accId]:gsub("b", "") -- Remove "b"
	local isFlat = #flatNote < #noteName[accId] -- Is the note a "b"?
	local doubleFlatNote = noteName[accId]:gsub("bb", "") -- Remove "bb"
	local isDoubleFlat = #doubleFlatNote < #noteName[accId] -- Is the note a "bb"?
	local sharpNote = noteName[accId]:gsub("#", "") -- Remove "#"
	local isSharp = #sharpNote < #noteName[accId] -- Is the note a "#"?
	local doubleSharpNote = noteName[accId]:gsub("×", "") -- Remove "×"
	local isDoubleSharp = #doubleSharpNote < #noteName[accId] -- Is the note a "×"?
	
	

	-- Draw -------------------
	save()
    translate{x,y}
	save()
	scale{size,size}
	local min,max = text_bounds(noteName[accId])
	translate{-max[1]/2, -max[2]/2}

	if isDoubleFlat then
    	save()
    	text(doubleFlatNote, text_color)
    	translate{8.4, 0}
    	flatSymbol()
    	translate{4.2, 0}
    	flatSymbol()
    	restore()
	elseif isFlat then    
    	save()
    	text(flatNote, text_color)
    	translate{8.5, 0}
    	flatSymbol()
    	restore()
    elseif isSharp then    
    	save()
    	text(sharpNote, text_color)
    	translate{7.9, 0}
    	sharpSymbol()
    	restore()
    elseif isDoubleSharp then    
    	save()
    	text(doubleSharpNote, text_color)
    	translate{6.5, 0}
    	doubleSharpSymbol()
    	restore()
	else
    	save()
    	text(noteName[accId], text_color)
    	restore()
	end
	restore()
	restore()
end


function teardrop(x, y, rot, width, height, circle_yoffset, circle_radius, paint)
	save()
	translate{x, y}
	save()
	rotate(-(rot * math.pi*2 + angle) + math.pi/2)
	local iter = 30
	move_to{2*width, 0}
	for i = 0, iter do
    	local theta = i / iter * math.pi * 2
    	local x0 = 2 * width * math.cos(theta) - width * math.sin(2 * theta)
    	local y0 = height * math.sin(theta)
    	line_to{x0, y0}    	
	end	
	fill(paint)
	-- hide this circle for "flat" teardrop style
    fill_circle({0, -height + circle_yoffset}, width * 3 + circle_radius, paint)
	restore()
	restore()
end

rdm = {}
math.randomseed(4)

function isNotNilOrZero(value, default)
    return value ~= nil and value or default
end

function rdmDashedLine(ax, ay, bx, by, stroke, gap, radius, color0, color1)
    function rdmNumber(n)
        for j = 1, n do
            rdm[j] = math.random()*.8+.1 -- set random range
        end
    end

    local segments = 12
    local dx = (bx - ax) / segments
    local dy = (by - ay) / segments
    local gapRatio = gap and 1 - gap or 0
    save()
    for i = 1, segments do
        rdmNumber(i)
        local x1 = ax + (i - 1) * dx 
        local y1 = ay + (i - 1) * dy
        local x2 =  x1 + (ax + i * dx - x1) * (gapRatio * isNotNilOrZero(rdm[i], 0.5))
        local y2 = y1 + (ay + i * dy - y1) * (gapRatio * isNotNilOrZero(rdm[i], 0.5))
        
        local color = {}
        for j = 1, 4 do
            color[j] = color0[j] * (1-i/segments) + color1[j] * i/segments
        end

        stroke_bezier({x1, y1}, {x2 + 0.001, y2 + 0.001}, {x2, y2}, stroke/2, color_paint(color))

        -- Update ax and ay for the next segment
        x1, y1 = x2, y2
    end

    -- Check for nil in bx, by, and radius before calling fill_circle
    if bx and by and radius then
        fill_circle({bx, by}, radius, color_paint(color1))
    end
    restore()
end


------- GRAPHICS --------
--if mode > 0 then

-- Hide knob ---------
save()
translate{canvas_width/2, canvas_height/2}
rotate(.1) -- hide the cuts
stroke_circle({0,0}, 34, 2.5, color_paint {.11, .11, .12, 1})
stroke_circle({0,0}, 34, 2, color_paint{.05,.05,.05,.3})
restore()
------------------------

-- Draw wheel -------------
save()
translate {canvas_width/2, canvas_height/2}

-- parameters
local textRadius = 70
local lineRadius0 = 10
local lineRadius1 = 60
local line_stroke = .5
--local rdm_gap = 1
--local circle_radius = 1

if oct == 1 then
	teardropRadius = 43
	text_size = .9
    tdrop_width = 1.8
    tdrop_height = 5
    tdrop_circle_yoffset = 1
    tdrop_circle_radius_offset = -0.2
elseif oct == 2 then
	teardropRadius = 45 
    text_size = .9
    tdrop_width = 1.6
    tdrop_height = 4.9
    tdrop_circle_yoffset = 2
    tdrop_circle_radius_offset = -0.3
elseif oct == 3 then
	teardropRadius = 46
    text_size = .7
    tdrop_width = 1.25
    tdrop_height = 4.2
    tdrop_circle_yoffset = 2
    tdrop_circle_radius_offset = -0.2
end

-- Shift pitch position around the wheel
if oct == 3 then 
	angle = math.pi/2 
elseif oct == 2 then
	angle = math.pi/2
else
	angle = math.pi/2 
end

-- HSV color space: hue, saturation and value in 0 to 1 range
-- use 'local r,g,b = hsvToRgb(h,s,v)' then color={r,g,b,1}
local function hsvToRgb(h,s,v)
    local kr = (5+(1-h)*6)%6
    local kg = (3+h*6)%6
    local kb = (1+h*6)%6
    local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
    local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
    local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end



-- table of inputs for poly
ins = {input0, input1, input2, input3}
gate = {gate0, gate1, gate2, gate3}

for i = 0, iLength - 1 do
    -- highlight notes in current scale
    highlight = {}
    for _, j in pairs(Scales[currentScale].notes) do
        local index = j%iLength
        for octaveIndex = 0, oct-1 do
            highlight[index + octaveIndex * 12] = 1
        end
    end
	
    -- HSV color
    h = i/(iLength/oct) -- hue

    local notePlaying = false

    for k = 1, voices do  
        local Note = math.floor((ins[k]+.001)*12) - currentRoot
        
        if i == Note%iLength and gate[k] > 0 then
            notePlaying = true
            break
        end
    end
	
	-- parameters for color, size, radii, etc.
    if notePlaying then
        s,v = .55, 1 -- teardrop saturation and (oversaturated) value .5, 1.3
        text_color = theme.text
        rdm_gap = .05
        line_color0 = {.6, .6, .6, .1}
        line_color1 = {.8, .8, .8, 1.5} --oversaturated alpha
        teardrop_halo_color = color_paint{.8,.8,.8,1}
    elseif highlight[i] == 1 then
        s,v = .8,.45
        text_color = theme.text
        rdm_gap = .3
        line_color0 = {.11,.11,.11,1}
        line_color1 = {.5,.5,.5,.5}
        teardrop_halo_color = color_paint{.8,.8,.8,0}
    else
        s,v = .5, 0.08
        text_color = {.25,.25,.25,1}
        rdm_gap = .3
        line_color0 = {.11,.11,.11,.2}
        line_color1 = {.5,.5,.5,.6}
        teardrop_halo_color = color_paint{.8,.8,.8,0}
    end
    
    local r,g,b = hsvToRgb(h,s,v)
    local teardrop_color = color_paint{r,g,b,a}
    
    -- Position around the circle
    local cosx = math.cos(i/iLength * math.pi*2 + angle)
    local siny = -math.sin(i/iLength * math.pi*2 + angle)
    
    rdmDashedLine( 
    lineRadius0 * cosx, lineRadius0 * siny, 
    lineRadius1 * cosx, lineRadius1 * siny, 
    line_stroke, rdm_gap, circle_radius, 
    line_color0, line_color1 )

    teardrop( -- halo teardrop with offset ratios
    (teardropRadius-0.2) * cosx, (teardropRadius-0.2) * siny, i/iLength,
    tdrop_width*1.2, 
    tdrop_height*1.05, 
    tdrop_circle_yoffset*.9, 
    tdrop_circle_radius_offset*2.5, 
    teardrop_halo_color )

    teardrop(
    teardropRadius * cosx, teardropRadius * siny, i/iLength,
    tdrop_width, 
    tdrop_height, 
    tdrop_circle_yoffset, 
    tdrop_circle_radius_offset, 
    teardrop_color )
    
    noteLabel(textRadius * cosx, textRadius * siny, i, text_size, text_color)
end

restore()

  j D @ 8 ,               (                    $                                   7                  j   @   x  x                  A  At              \N   7  currentNote = 3
rootName = {}
rootName[1] = "A"
rootName[2] = "A#"
rootName[3] = "B"
rootName[4] = "C"
rootName[5] = "C#"
rootName[6] = "D"
rootName[7] = "D#"
rootName[8] = "E"
rootName[9] = "F"
rootName[10] = "F#"
rootName[11] = "G"
rootName[12] = "G#"
noteTranspose = 10
text_color = {}
text_color[1] = 0.8
text_color[2] = 0.8
text_color[3] = 0.8
text_color[4] = 1
width = 12
stroke = 0.5
shiftx = 1.5
s = 0.8
n = 5
c1_stroke = {}
c1_stroke[1] = 0
c1_stroke[2] = 0
c1_stroke[3] = 0.0
c1_stroke[4] = 1
currentOctave = 3
c2_stroke = {}
c2_stroke[1] = 0
c2_stroke[2] = 0
c2_stroke[3] = 0.0
c2_stroke[4] = 1
nHeight = 12.5
cornerRadius = 3
Scales = {}
Scales[1] = {}
Scales[1]["notes"] = {}
Scales[1]["notes"][1] = 0
Scales[1]["notes"][2] = 1
Scales[1]["notes"][3] = 2
Scales[1]["notes"][4] = 3
Scales[1]["notes"][5] = 4
Scales[1]["notes"][6] = 5
Scales[1]["notes"][7] = 6
Scales[1]["notes"][8] = 7
Scales[1]["notes"][9] = 8
Scales[1]["notes"][10] = 9
Scales[1]["notes"][11] = 10
Scales[1]["notes"][12] = 11
Scales[1]["label"] = "chromatic"
Scales[2] = {}
Scales[2]["notes"] = {}
Scales[2]["notes"][1] = 0
Scales[2]["notes"][2] = 2
Scales[2]["notes"][3] = 4
Scales[2]["notes"][4] = 5
Scales[2]["notes"][5] = 7
Scales[2]["notes"][6] = 9
Scales[2]["notes"][7] = 11
Scales[2]["label"] = "ionian"
Scales[3] = {}
Scales[3]["notes"] = {}
Scales[3]["notes"][1] = 0
Scales[3]["notes"][2] = 2
Scales[3]["notes"][3] = 3
Scales[3]["notes"][4] = 5
Scales[3]["notes"][5] = 7
Scales[3]["notes"][6] = 9
Scales[3]["notes"][7] = 10
Scales[3]["label"] = "dorian"
Scales[4] = {}
Scales[4]["notes"] = {}
Scales[4]["notes"][1] = 0
Scales[4]["notes"][2] = 1
Scales[4]["notes"][3] = 3
Scales[4]["notes"][4] = 5
Scales[4]["notes"][5] = 7
Scales[4]["notes"][6] = 8
Scales[4]["notes"][7] = 10
Scales[4]["label"] = "phrygian"
Scales[5] = {}
Scales[5]["notes"] = {}
Scales[5]["notes"][1] = 0
Scales[5]["notes"][2] = 2
Scales[5]["notes"][3] = 4
Scales[5]["notes"][4] = 6
Scales[5]["notes"][5] = 7
Scales[5]["notes"][6] = 9
Scales[5]["notes"][7] = 11
Scales[5]["label"] = "lydian"
Scales[6] = {}
Scales[6]["notes"] = {}
Scales[6]["notes"][1] = 0
Scales[6]["notes"][2] = 2
Scales[6]["notes"][3] = 4
Scales[6]["notes"][4] = 5
Scales[6]["notes"][5] = 7
Scales[6]["notes"][6] = 9
Scales[6]["notes"][7] = 10
Scales[6]["label"] = "mixolydian"
Scales[7] = {}
Scales[7]["notes"] = {}
Scales[7]["notes"][1] = 0
Scales[7]["notes"][2] = 2
Scales[7]["notes"][3] = 3
Scales[7]["notes"][4] = 5
Scales[7]["notes"][5] = 7
Scales[7]["notes"][6] = 8
Scales[7]["notes"][7] = 10
Scales[7]["label"] = "aeolian"
Scales[8] = {}
Scales[8]["notes"] = {}
Scales[8]["notes"][1] = 0
Scales[8]["notes"][2] = 1
Scales[8]["notes"][3] = 3
Scales[8]["notes"][4] = 5
Scales[8]["notes"][5] = 6
Scales[8]["notes"][6] = 8
Scales[8]["notes"][7] = 10
Scales[8]["label"] = "locrian"
Scales[9] = {}
Scales[9]["notes"] = {}
Scales[9]["notes"][1] = 0
Scales[9]["notes"][2] = 2
Scales[9]["notes"][3] = 3
Scales[9]["notes"][4] = 4
Scales[9]["notes"][5] = 7
Scales[9]["notes"][6] = 9
Scales[9]["label"] = "maj blues"
Scales[10] = {}
Scales[10]["notes"] = {}
Scales[10]["notes"][1] = 0
Scales[10]["notes"][2] = 3
Scales[10]["notes"][3] = 5
Scales[10]["notes"][4] = 6
Scales[10]["notes"][5] = 7
Scales[10]["notes"][6] = 10
Scales[10]["label"] = "min blues"
Scales[11] = {}
Scales[11]["notes"] = {}
Scales[11]["notes"][1] = 0
Scales[11]["notes"][2] = 2
Scales[11]["notes"][3] = 3
Scales[11]["notes"][4] = 5
Scales[11]["notes"][5] = 6
Scales[11]["notes"][6] = 8
Scales[11]["notes"][7] = 9
Scales[11]["notes"][8] = 11
Scales[11]["label"] = "diminish"
Scales[12] = {}
Scales[12]["notes"] = {}
Scales[12]["notes"][1] = 0
Scales[12]["notes"][2] = 3
Scales[12]["notes"][3] = 5
Scales[12]["notes"][4] = 7
Scales[12]["notes"][5] = 10
Scales[12]["label"] = "min pentatonic"
Scales[13] = {}
Scales[13]["notes"] = {}
Scales[13]["notes"][1] = 0
Scales[13]["notes"][2] = 2
Scales[13]["notes"][3] = 4
Scales[13]["notes"][4] = 7
Scales[13]["notes"][5] = 9
Scales[13]["label"] = "maj pentatonic"
Scales[14] = {}
Scales[14]["notes"] = {}
Scales[14]["notes"][1] = 0
Scales[14]["notes"][2] = 1
Scales[14]["notes"][3] = 4
Scales[14]["notes"][4] = 5
Scales[14]["notes"][5] = 7
Scales[14]["notes"][6] = 8
Scales[14]["notes"][7] = 10
Scales[14]["label"] = "spanish"
Scales[15] = {}
Scales[15]["notes"] = {}
Scales[15]["notes"][1] = 0
Scales[15]["notes"][2] = 2
Scales[15]["notes"][3] = 3
Scales[15]["notes"][4] = 6
Scales[15]["notes"][5] = 7
Scales[15]["notes"][6] = 8
Scales[15]["notes"][7] = 11
Scales[15]["label"] = "gypsy minor"
Scales[16] = {}
Scales[16]["notes"] = {}
Scales[16]["notes"][1] = 0
Scales[16]["notes"][2] = 2
Scales[16]["notes"][3] = 4
Scales[16]["notes"][4] = 5
Scales[16]["notes"][5] = 6
Scales[16]["notes"][6] = 8
Scales[16]["notes"][7] = 10
Scales[16]["label"] = "arabian"
Scales[17] = {}
Scales[17]["notes"] = {}
Scales[17]["notes"][1] = 0
Scales[17]["notes"][2] = 2
Scales[17]["notes"][3] = 5
Scales[17]["notes"][4] = 7
Scales[17]["notes"][5] = 10
Scales[17]["label"] = "egyptian"
Scales[18] = {}
Scales[18]["notes"] = {}
Scales[18]["notes"][1] = 0
Scales[18]["notes"][2] = 4
Scales[18]["notes"][3] = 5
Scales[18]["notes"][4] = 7
Scales[18]["notes"][5] = 11
Scales[18]["label"] = "ryukyu"
Scales[19] = {}
Scales[19]["notes"] = {}
Scales[19]["notes"][1] = 0
Scales[19]["notes"][2] = 2
Scales[19]["notes"][3] = 4
Scales[19]["notes"][4] = 6
Scales[19]["notes"][5] = 8
Scales[19]["notes"][6] = 10
Scales[19]["label"] = "whole tone"
Scales[20] = {}
Scales[20]["notes"] = {}
Scales[20]["notes"][1] = 0
Scales[20]["notes"][2] = 4
Scales[20]["notes"][3] = 8
Scales[20]["label"] = "maj 3rd"
Scales[21] = {}
Scales[21]["notes"] = {}
Scales[21]["notes"][1] = 0
Scales[21]["notes"][2] = 3
Scales[21]["notes"][3] = 6
Scales[21]["notes"][4] = 9
Scales[21]["label"] = "min 3rd"
Scales[22] = {}
Scales[22]["notes"] = {}
Scales[22]["notes"][1] = 0
Scales[22]["notes"][2] = 7
Scales[22]["label"] = "fifth"
Scales[23] = {}
Scales[23]["notes"] = {}
Scales[23]["notes"][1] = 0
Scales[23]["notes"][2] = 4
Scales[23]["notes"][3] = 7
Scales[23]["notes"][4] = 11
Scales[23]["label"] = "maj 7th chord"
Scales[24] = {}
Scales[24]["notes"] = {}
Scales[24]["notes"][1] = 0
Scales[24]["notes"][2] = 3
Scales[24]["notes"][3] = 7
Scales[24]["notes"][4] = 10
Scales[24]["notes"][5] = 14
Scales[24]["label"] = "min 9th chord"
iLength = 12
noteLabel = {}
noteLabel[1] = "A"
noteLabel[2] = "#"
noteLabel[3] = "B"
noteLabel[4] = "C"
noteLabel[5] = "#"
noteLabel[6] = "D"
noteLabel[7] = "#"
noteLabel[8] = "E"
noteLabel[9] = "F"
noteLabel[10] = "#"
noteLabel[11] = "G"
noteLabel[12] = "#"
v = 0.4
n4 = 7
s0 = 0
v0 = 0
wrap = 0.0
n3 = 5
h0 = 0.4
c1_fill = {}
c1_fill[1] = 0.08
c1_fill[2] = 0.4
c1_fill[3] = 0.208
c1_fill[4] = 1
height = 150
highlight = {}
highlight[0] = 1
highlight[8] = 1
highlight[10] = 1
highlight[11] = 0
highlight[5] = 1
highlight[3] = 1
note = -2
root = 0.49000000953674
c = 0
notesInScale = 5
n2 = 3
c2_fill = {}
c2_fill[1] = 0.08
c2_fill[2] = 0.4
c2_fill[3] = 0.208
c2_fill[4] = 1
size = 1.2
outlineStroke = 0.5
Note = -2
currentRoot = 5
n1 = 0
rootId = 6
input = -0.42989501357079
gap = 1
octave = -12
currentScale = 12
gray = {}
gray[1] = 0.4
gray[2] = 0.4
gray[3] = 0.4
gray[4] = 1
n5 = 10
scl = 0.49374955892563
              root          text_color = theme.text

function flatSymbol()
	paint = color_paint(text_color)
	stroke = .85
	segments = 20 -- segments in curve
	
	save()
	translate{0,0}
	stroke_segment( {0, 0}, {0, 8}, stroke, paint)
	
	-- cubic bezier control points
	P0 = {-.5, stroke*.5}
	P1 = {5.5, 0}
	P2 = {5.5, 7}
	P3 = {0.2, 4}
		
	axy = {0, stroke*.5}
   	for i = 1, segments do
    	t = i/segments
    	px = (1-t)^3*P0[1] + 3*(1-t)^2 * t*P1[1] + 3*(1-t) * t^2*P2[1] + t^3*P3[1]
    	py = (1-t)^3*P0[2] + 3*(1-t)^2 * t*P1[2] + 3*(1-t) * t^2*P2[2] + t^3*P3[2]
   	    bxy = {px, py}
    	stroke_segment(axy, bxy, stroke, paint)
    	fill_circle(bxy, stroke*.49, paint)
       	axy = bxy		
    end	
	restore()
end
	
local function sharpSymbol()
    local w, h = 5.5, 7.5
    local vstroke = .8
    local hstroke = .9
    local vspread = 1.1
   	local hspread = 1.3
    local shear = 1

   	local function shearY(x, y)
       	return x, y + (x * shear * hspread/w)
   	end

   	save()
   	translate{0,-.25}
   	local function drawRect(x1, y1, x2, y2)
       	move_to{shearY(x1, y1)}        	
       	line_to{shearY(x2, y1)}
        line_to{shearY(x2, y2)}
       	line_to{shearY(x1, y2)}
       	line_to{shearY(x1, y1)}
       	fill(color_paint(text_color))
   	end

   	drawRect(0, h/2 - hspread - hstroke/2, w, h/2 - hspread + hstroke/2) -- Top
   	drawRect(0, h/2 + vspread - hstroke/2, w, h/2 + vspread + hstroke/2) -- Bottom
   	drawRect(w/2 - vspread - vstroke/2, 0, w/2 - vspread + vstroke/2, h) -- Left
   	drawRect(w/2 + vspread - vstroke/2, 0, w/2 + vspread + vstroke/2, h) -- Right
   	restore()
end	
	
local roots = {"A","A#","Bb","B","C","C#","Db","D","D#","Eb","E","F","F#","Gb","G","G#","Ab"}



-- Double up on naturals for knob display (to match quantizer calculations)
local rootsKnob = {1,1,2,3,4,4,5,5,6,7,8,8,9,10,11,11,12,12,13,14,15,15,16,17}

rootId = math.floor(root*23.99)+1
currentRoot = roots[rootsKnob[rootId]]

local flatRoot = currentRoot:gsub("b","")--Remove "b"
local isFlat = #flatRoot<#currentRoot--Check if the root had a "b"
local sharpRoot = currentRoot:gsub("#","")--Remove "#"
local isSharp = #sharpRoot<#currentRoot--Check if the root had a "#"


translate{canvas_width/2,canvas_height/2}



save()
--scale{1.2,1.2}
--[[min,max=text_bounds(currentRoot)
translate{-max[1]/2, -max[2]/2}
translate{0, -5}

-- flats rootId: 4,10,14,20,24
if rootId == 4 
or rootId == 10 
or rootId == 14 
or rootId == 20 
or rootId == 24 
then
translate{.5,0}
end --]]
min,max=text_bounds(currentRoot)
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
translate{0, -5}
if isFlat then
text(flatRoot,theme.text)
elseif isSharp then
text(sharpRoot,theme.text)
else
text(currentRoot,theme.text)
end 

-- Use flat symbol instead of "b"
if isFlat then
	translate{8.5,0}
	flatSymbol()
elseif isSharp then -- Use sharp symbol instead of "#"
	translate{8,0}
	sharpSymbol()		
end
restore()

save()
scale{.75,.75}
min, max = text_bounds("Root")
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
translate{0, 25}
text("Root", theme.text)
restore()

 t4   4                    Qx>  A   A    4                V@   @                 0   0     ?          B  B  K3ë@C               6      %  &  ),   ,                   B   A  A  H
               (0   0                                           W@   @                 0   0     ?           C  RC  K3VC                     #  $  *,   ,                   H       
               F<   <                   A  A4     pA         H   N                k       %  
translate{canvas_width/2, canvas_height/2}

save()
min, max = text_bounds(math.floor(k))
translate{-max[1]/2, -max[2]/2 - 5}
text(math.floor(k), theme.text)
restore()

save()
scale{.75,.75}
min, max = text_bounds("8ves")
translate{-max[1]/2, -max[2]/2 + 25}
text("8ves", theme.text)
restore()   ,   ,                   B   6Bę,XD               %   this knob is hidden behind the wheel.   x4   4                    '>  A   A˼ O               -,   ,                   B     C  B	               `I<   <                   A  A4     \B       C  pBN                k         -- HSV to RGB
function hsv(h,s,v)
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end

local function octLight(x)
	
	local octh = ((x+5)/10)
	local h=(1-octh)*.7
	local s=1
	
	local octv=(x+5)-math.floor(x+5)
	local v=octv*.9+.1
	local r,g,b = hsv(h,s,v)
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	fill_circle({10,10},9,color_paint{.05,.05,.05,.18})
	fill_circle({10,10},5,color_paint{.05,.05,.05,1})
	
	fill_circle({10,10},9,halo)
	fill_circle({10,10},5,paint)
	
	end
	
octLight(k) p4   4                 (    yB b    C   B                  O
  jD   D                 H   0   0     ?          C  A    C D                        Octave Meter    \M<   <                   A  A@            N                   m      k         
-- Knob graphics

-- add k and m input ports for knob and modulation

knobSize = 2 -- 1 = standard, 2 = mini, 3 = large
-- make Canvas width/height 50x50, 20x20 for mini, 70x70 for large

  
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 12.5 end
if knobSize == 3 then ksize = 35 end

-- knob style 1 is standard, 2 is bipolar
knobStyle = 2


-- Knob modulation: displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off, see below)

save()
translate{-2.5, -2.5} -- uncomment for mini (requires an extra translate to center)
-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, color_paint{.11,.11,.12,1})

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, color_paint(theme.grooves))


if knobStyle == 1 then

-- get knob and modulation values and scale for stroke_arc
a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, color_paint(theme.azureHighlight))

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

	-- change both to some other color (like red) to distinguish port from knob takeover
	if m >= 0 then
    	mpos = math.max(0,c)
    	stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, color_paint(theme.azureHighlight))
	elseif m < 0 then
    	mneg = math.min(0,c)
    	stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, color_paint(theme.grooves))
	end
end
	
if knobStyle == 2 then

-- get knob and modulation values and scale for stroke_arc
a = math.pi * (k-.5)
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
--stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, azure)

if k >= .5 then
	stroke_arc({ksize,ksize}, ksize-1, 2, a+math.pi/2, a, color_paint(theme.azureHighlight))
elseif k < .5 then
	stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, color_paint(theme.azureHighlight))
end
	
end
restore()

save()
translate{canvas_width/2,canvas_height/2}
scale{.75,.75}
min, max = text_bounds("Fine")
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
translate{-.5, 25}
text("Fine", theme.text)
restore()

save()
cents = math.floor(k*100-50)
translate{canvas_width/2, canvas_height/2-5}
--scale{.75,.75}
min, max = text_bounds(cents)
translate{-(min[1]+max[1])/2,-(min[2]+max[2])/2}
if cents < 0 then translate{-1,0} end
text(cents, theme.text)
restore()

-- highlight current position (using stroke_arc aperture)
--stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2, .03, color_paint(theme.azureHighlight))   i@   @                 0   0     ?          C  B  K3ð
A                     ;  <  =  ,=,   ,                       /
               <4   4                    Q ?      @ %               lj@   @                 0   0     ?          C  B  fH0oD                 	  
    >,   ,                   B   A  t  
               =(   (                 (                       x          floor(x*2.99)+1 x4   4                    p]>  B  uCICQ>D               h(   (             HC   A     C  D
                ?,   ,                    A   AI QsD	               x H   @ 8 0 , (                                                                                                 $ x   D                 C  RC$  t  t  a?DÁy  C  TB  >  B  # Pitch Wheel 2 

## Musical Scale Quantizer 

- Quantizes an incoming signal to a scale of 2 – 12 steps.  
- For scales other than the chromatic, the ‘unused’ steps are mapped to the closest out of the 12 equal steps.
- Accepts and converts modulation input, MIDI keyboard input, or use the built-in knob.  
- Displays up to 4-channel poly.

### Available scales:

|      | Scale                                | Steps |   
|-----|-----------------------------------|----------------------------------|   
| 1   | Chromatic             		| 0,1,2,3,4,5,6,7,8,9,10,11 |
| 2   | Ionian                    		| 0,2,4,5,7,9,11 |
| 3   | Dorian                   		| 0,2,3,5,7,9,10 |
| 4   | Phrygian               		| 0,1,3,5,7,8,10 |
| 5   | Lydian                     		| 0,2,4,6,7,9,11 |
| 6   | Mixolydian               		| 0,2,4,5,7,9,10 |
| 7   | Aeolian                    		| 0,2,3,5,7,8,10 |
| 8   | Locrian                    		| 0,1,3,5,6,8,10 |
| 9   | 1/2 Diminished       		| 0,2,3,5,6,8,10 |
| 10 | Spanish                 		| 0,1,4,5,7,8,10 |
| 11 | Gypsy Maj/Arabic      		| 0,1,4,5,7,8,11 |
| 12 | Gypsy Minor            		| 0,2,3,6,7,8,11 |
| 13 | Harmonic Minor     		| 0,2,3,5,7,8,11 |
| 14 | Ukranian                		| 0,2,3,6,7,8,10 |
| 15 | Blues Maj               		| 0,2,3,4,7,9 |
| 16 | Blues Min               		| 0,3,5,6,7,10 |
| 17 | Major Pentatonic       		| 0,2,4,7,9 |
| 18 | Suspended/Egyptian Pentatonic	| 0,2,5,7,10 |
| 19 | Minor Blues Pentatonic     		| 0,3,5,8,10 |
| 20 | Major Blues/Yo Pentatonic 		| 0,2,5,7,9 |
| 21 | Minor Pentatonic      		| 0,3,5,7,10 |
| 22 | Ryūkyū                   		| 0,4,5,7,11 |
| 23 | In Pentatonic                    		| 0,1,5,7,8 |
| 24 | Hirajoshi                 		| 0,2,3,7,8 |
| 25 | Pelog                     		| 0,1,3,7,8 |
| 26 | Whole Tone           		| 0,2,4,6,8,10 |
| 27 | Octatonic           		| 0,1,3,4,6,7,9,10 |
| 28 | Messiaen 3rd Mode of Limited Transposition       		| 0,2,3,4,6,7,8,10,11 |
| 29 | Messiaen 4th Mode of Limited Transposition       		| 0,1,2,5,6,7,8,11 |
| 30 | Messiaen 5th Mode of Limited Transposition       		| 0,1,5,6,7,11 |
| 31 | Messiaen 6th Mode of Limited Transposition       		| 0,2,4,5,6,8,10,11 |
| 32 | Messiaen 7th Mode of Limited Transposition       		| 0,1,2,3,5,6,7,8,9,11|
| 33 | Minor 3rd             		| 0,3,6,9 |
| 34 | Major 3rd             		| 0,4,8 |
| 35 | Fourth              			| 0,5 |
| 36 | Fifth               			| 0,7 |

***

### Controls

- Wheel – sets the current note with the knob within the pitch-wheel circle.  
- Scale slider – Select scales.  
- Mod/Kbd  – Shift between modulation or keyboard input.  
- ‘Root’ knob – Controls and displays the root note of the scale.  
- Shift knob – Adjust the ocatve.  
- ‘Fine’ knob – Shift the overall tuning up or down (up to 50 cents).  
- ‘8ves’ – The range covered by the wheel (1 – 3 octaves).  

### Inputs

- O –  Octave signal to be quantized  
- G – Gate signal for keyboard input – also useful when ‘Detune’ mode is used on the companion Tuning Wheel module.    
- Mod input for ‘Scales’ slider    
- Mod input for ‘Shift’ knob    
- Mod input for ‘Fine’ knob (biplolar)    

### Outputs

- G (polyphonic) gate signal for use in conjunction with the companion Tunings module.  
- O – Quantized octave signal. 
  
***

### Version History

- 2.11 - 23.03.2024: fixed Lua error in display, Jerry Smith
- 2.1 – 24.02.2024: by Jerry Smith and Rudiger Meyer with Lua internals and added Markdown description. 
- 2.0 – 2023: by Jerry Smith and Rudiger Meyer  
- 1.0 – 2022: by Jerry Smith   

              )   '                           !  "  0  1  2  3  4  5  7  8  9  :  >  ?  @  A  I  \  q  r  u  |                 Pitch Wheel 4   4                 D U2    C   B               }$   $                   jC                 O,   ,                           XB	               ȉD   D                 D 0   0     ?          A   A   D O                     $4   4                 lC U2    C   B               ~$   $                   jC                 P,   ,                           XB	               D   D                 C 0   0     ?          A  B  sD	r                      <4   4                 TB U2    C   B               $   $                   jC                 Q,   ,                           XB	               D   D                 |B 0   0     ?          A  4C  C                      Q(   (                   jICCC                Control     (   (                     C  >               H(   (                    TC %@=               (   (                     C  B>               ̕0   0                     4C    <#DppA
               0   0                         p    	               L0   0                           p  B	               (   (                        EC	               8   8                   $   $     ?         D                                 T(   (                 ,   jICCC                Control     
   1-Control
  t(   (                     C  >               (   (                    TC %@=               (   (                     C  B>               00   0                 T    4C    <#DppA
               p0   0                 $         p    	                  In B    0   0                 $           p  B	                  In A    4(   (                         EC	                  Crossfade Control   @8   8                 P   $   $     ?         D                                    Linear Crossfade    |s<   <                   A  A(    B  A   GD{_N               K   gray = {1,1,1,0.8}
rotate(math.pi/2)
scale {0.5, 0.5}
text("MIX OUT", gray) t<   <                   A  A(    B B   skrCܠ9N               K   gray = {1,1,1,0.8}
rotate(math.pi/2)
scale {0.5, 0.5}
text("VCA OUT", gray)  (   (                     iD  \>               h 4 0 (                                                                                          h   0   0                     HB  B iD  H               (   (                     D 6>               8   8                    ;     OB   A D "               v<   <                   HB  HBL	    pA  CC    	D  *N                   m      k       4                   	D                     m      Knob        v<   <                   HB  HB@     pA  B    D  \N                   m      k         
-- add k and m input ports for knob and modulation

knobSize = 1 -- 1 = standard, 2 = large, 3 = mini
-- make Canvas width/height 50x50, 70x70 for large, 25x25 for mini
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 35 end
if knobSize == 3 then ksize = 12.5 end

-- Audulus colors
white = color_paint {.84, .84, .84, 1}
black = color_paint { .05,.05,.06,1}
module = color_paint{ .11,.11,.11,1}

azure = color_paint {0, 0.83, 1, 1}
azure_dark = color_paint {0, 0.61, 0.73, 1}
azure_bkgd = color_paint {0, 0.06, 0.08, 1}

green = color_paint {0.23, 0.77, 0.33, 1}
green_dark = color_paint {0.15, 0.51, 0.03, 1}
green_bkgd = color_paint {0, 0.08, 0.01, 1}

red = color_paint {1, 0, 0.38, 1}
red_dark = color_paint {0.65, 0, 0.25, 1}
red_bkgd = color_paint {0.11, 0, 0.04, 1}

-- Knob modulation: this displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off)

-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, module)

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, black)

a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, red)

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

-- change both to some other color (like red) to distinguish port from knob takeover
if m >= 0 then
    mpos = math.max(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, red)
elseif m < 0 then
    mneg = math.min(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, black)
end

-- highlight current position (using stroke_arc aperture)
stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2, .03, red)
                      @D  H                   m      Knob         <   <                   HB  HB@     pA  A    D JN                   m      k         
-- add k and m input ports for knob and modulation

knobSize = 1 -- 1 = standard, 2 = large, 3 = mini
-- make Canvas width/height 50x50, 70x70 for large, 25x25 for mini
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 35 end
if knobSize == 3 then ksize = 12.5 end

-- Audulus colors
white = color_paint {.84, .84, .84, 1}
black = color_paint { .05,.05,.06,1}
module = color_paint{ .11,.11,.11,1}

azure = color_paint {0, 0.83, 1, 1}
azure_dark = color_paint {0, 0.61, 0.73, 1}
azure_bkgd = color_paint {0, 0.06, 0.08, 1}

green = color_paint {0.23, 0.77, 0.33, 1}
green_dark = color_paint {0.15, 0.51, 0.03, 1}
green_bkgd = color_paint {0, 0.08, 0.01, 1}

red = color_paint {1, 0, 0.38, 1}
red_dark = color_paint {0.65, 0, 0.25, 1}
red_bkgd = color_paint {0.11, 0, 0.04, 1}

-- Knob modulation: this displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off)

-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, module)

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, black)

a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, azure)

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

-- change both to some other color (like red) to distinguish port from knob takeover
if m >= 0 then
    mpos = math.max(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, azure)
elseif m < 0 then
    mneg = math.min(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, black)
end

-- highlight current position (using stroke_arc aperture)
stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2, .03, azure)
                 8    D 6                   m      Knob           clamp(Knob+m,0,1)   (   (                        =                k(   (                      C                    0.713   `(   (                      C >               (   (                     D  f>               k(   (                 D  AuK                Audio       4   4                    pXf    C   B               \$   $                   jC                 8m,   ,                           XB	               `D   D                   0   0     ?          @  B  BA                       t,   ,                   /C   RD(               L   v2.0 Audulus 4 version with structural changes and improvements. RM 12.03.24    P4   4                 (     A      D                    ×  (   (                    "C:=               \0   0                 $           	                  A/B (   (                      *C  >               ȟ(   (                      *C >               <   <                    A  A(      B C   s8N               }   save()
scale {.8, .8}
min, max = text_bounds("VCA")
translate{-max[1]/2+canvas_width/30,7}
text("VCA", theme.text) 
restore()   <   <                   A  A(     @  B      B  N               J   gray = {1,1,1,0.8}
rotate(math.pi/2)
scale {0.5, 0.5}
text("SHP IN", gray)   <   <                   A  A(     @  A   ]BN               J   gray = {1,1,1,0.8}
rotate(math.pi/2)
scale {0.5, 0.5}
text("VCA IN", gray)  0   0                         H  >  C	               \0   0                           >  \C	               (   (                 l;   >  C	               hr,   ,                   @  B  HB 	               (   (                      C  >               h 4 0 (                                                                                           h   0   0                      HB  4C  C                  r(   (                 =  AuK                Audio       4   4                    pXf    C   B               h$   $                   jC                 Dt,   ,                           XB	               lD   D                   0   0     ?          @   A                         8   8                    A  A$   KvBA  D  WN               }   save()
scale {.5, .5}
min, max = text_bounds("Wet")
translate{-max[1]/2+canvas_width/30,7}
text("Wet", theme.text) 
restore()   8   8                    A  A$   AA  D  WN                  save()
scale {.5, .5}
min, max = text_bounds("Switch")
translate{-max[1]/2+canvas_width/30,7}
text("Switch", theme.text) 
restore() <   <                    A  A(   LBxTC     C  *N                  save()
scale {.6, .6}
min, max = text_bounds("SYMMETRY")
translate{-max[1]/2+canvas_width/30,7}
text("SYMMETRY", theme.text) 
restore() h<   <                    A  A(   LB<C   4IHÈH&N               {   save()
scale {.5, .5}
min, max = text_bounds("AM")
translate{-max[1]/2+canvas_width/30,7}
text("AM", theme.text) 
restore() 4<   <                    A  A(     B C   (jBN                  save()
scale {.5, .5}
min, max = text_bounds("Full")
translate{-max[1]/2+canvas_width/30,7}
text("Full", theme.text) 
restore() <   <                    A  A(     pA C   9y`XCN               {   save()
scale {.5, .5}
min, max = text_bounds("RM")
translate{-max[1]/2+canvas_width/30,7}
text("RM", theme.text) 
restore()  y(   (                 7  AuK                Audio       4   4                 T|   pXf    C   B               $   $                   jC                 z,   ,                           XB	               D   D                   0   0     ?          B   A   @D                         z(   (                 (6  AuK                Audio       T4   4                 z   pXf    C   B               $   $                   jC                 {,   ,                           XB	               D   D                 L  0   0     ?          B  B  T_wC                       (   (                      D  >=               (   (                    MDC_Q>               X|(   (                 T4  AuK                Audio       (4   4                 y   pXf    C   B               $   $                   jC                 },   ,                           XB	               D   D                 x  0   0     ?           B C    4 K                       l<   <                    A  A(   TB#B    @D cN               }   save()
scale {.8, .8}
min, max = text_bounds("MIX")
translate{-max[1]/2+canvas_width/30,7}
text("MIX", theme.text) 
restore()   <<   <                    A  A(     B   C    D  fN                  save()
scale {.6, .6}
min, max = text_bounds("OVERDRIVE")
translate{-max[1]/2+canvas_width/30,7}
text("OVERDRIVE", theme.text) 
restore()   <   <                    A  A(   tBx=C     C  4N               y   save()
scale {.8, .8}
min, max = text_bounds("+")
translate{-max[1]/2+canvas_width/30,7}
text("+", theme.text) 
restore()   8   8                    A  A$     fA  9C  C  4N               y   save()
scale {.8, .8}
min, max = text_bounds("-")
translate{-max[1]/2+canvas_width/30,7}
text("-", theme.text) 
restore()   8   8                    A  A$      B  CIz/N                  save()
scale {.8, .8}
min, max = text_bounds("Bipolar")
translate{-max[1]/2+canvas_width/30,7}
text("Bipolar", theme.text) 
restore()   X4   4                 s   pXf    C   B               $   $                   jC                 ,   ,                           XB	               D   D                 H   0   0     ?          A  4C   0!D:                        Audio I/O Light ,   ,                   A  4C  C  	               ܃,   ,                   A  A D E	               ,   ,                   A  B iD h	               $   $                  ^CoFC               <   <                    A   A4     4B     g,DN                x          t = {"Pre-VCA","Off","Pre-SHP"}

save()
scale {0.5, 0.5}
min, max = text_bounds(t[x+1])
translate{-max[1]/2+canvas_width-1/2,5}
text(t[x+1], theme.text) 
restore()
    (   (                 (       D                x          (x<2)*(x+1) 0   0                              D(                 @    (,   ,                   HB      D               PD   D                 x   0   0     ?          A  C  9,'C9                                                Switch  ,   ,                   B    fC  fC
               (   (                      B  HC=               Ԇ(   (                 $&     C               (   (                    <BC@               @$   $                     CL               t$   $                 G_CL               $   $                     CL               h 4 0 (                                                                                           h   0   0                       B  C @D  \               ,,   ,                    B  HBlD_K               h,   ,                    B  \C  C  *               H4   4                 \>      B C̯\9               $   $             'C    RD                 $   $           B   A                  VCA Modulation Input (Bipolar)  L$   $             C     C  >                  Number of folds                 (      @5                x          x+.5    (   (             B  B   خPCL(
               (   (              B C       C	               <                (      (                x          -x                  (     %                  s          s/2+.5                  (                       m          m*2-1   ,   ,           f             	               (   (             pA       C @
               <(   (             pA  p     C 
               0   0             C(           jB6                  
Bipolar VCA
RMS Crossfade
 |0   0             C<#         ćS               (   (                  AmN	               L(   (             4B      	D  
               ,0   0             C                                            (     A                  s          s*(pi/2)    (   (               p     A 	                               (   _                x          cos(x)                  t  Ԩ                x       \+,   ,           $   $     ?        BE               u  v  w  x  y  z  {  |  }  ~                                               C K                  42  (   (             A      E,
               (   (                   r
	               ,,   ,           $   $     ?        X±               q  r                  ,    @]D  *                Input          tanh(Input*4)   h ( $                                                                                             h   $   $             (C     RD                    v1.1 With attenuation after the equal power crossfades in order to prevent potential clipping as pointed out by Robert Syrett. RM 25.04.18  |0   0             B(   d@<IC     \D  4                   VCA SHAPER $(   (             B   A    @D  
               \(   (             @   A     \  	                               (     C                  x          (2*x-1) $                (     4D  >                x          sin(x)  x @   8   0 , (                                                                                                 $ x   <   
  
            C  B  	  	  V?.BĄ,D ,D  	  # VCA-SHAPER
## After Rob Hordijk

Hordijk adds a VCA and crossfader to his waveshaper design, ingeniously extending the pallet of shaping options since the wavefolding is dependent on the amplitude of the signal. The one side of the crossfader can furthermore be set to point to either the original signal, no signal at all, or the output of the VCA.

The VCA is a bipolar, shifting from ring modulation to amplitude modulation to the full signal. With an inverted signal equally present alongside the original the two signals cancel each other out – until one introduces some modulation. With modulation at audio rates the ring modulation provides a nice counterpart to the harmonic content generated by the wavefolder .

Since the waveshaper design works best with slopes rather than verticals an overdrive is introduced after the waveshaping, should one wish  to ‘sharpen’ the waveform and bring the flanks closer to the vertical.    

---

### Controls 

- VCA Knob – The bipolar VCA can be shifted from RM (Ring Modulation) to AM (Amplitude Modulation) to Full. This knob simultaneously increases the number of folds in the wavefolder.   
- Symmetry – adjusts the vertical offset (bias) of the wave to be folded 
- Overdrive – adds overdrive distortion to the signal that has been wavefolded
- Pre-VCA/Off/Pre-Shaper switch – sets the (leftmost) point of the ‘Mix’ crossfader. 
	- Pre-VCA: the VCA IN input
	- Off: no input – the crossfader knob acts as a volume control for the waveshaped signal
	- Pre-Shaper: the signal after the VCA but before the waveshaper       
- Mix – Crossfade between the waveshaped signal and the input selected via the switch above.

### Inputs

- VCA IN – Main audio input for the module
- SHP IN – Normally connected (‘normalised’) from VCA OUT, but can also be used as an independent (audio) input for the wavefolder.
- VCA Mod in (Bipolar)
- Symmetry Mod in (Unipolar) 
- Overdrive Mod in (Unipolar)
- Mix Mod in (Unipolar)

### Outputs

- MIX OUT – Main audio output for the module 
- VCA OUT – Normally connected (‘normalised’) to SHP IN, but can also be used as an independent output.

### Version History

- v2.0 Audulus 4 version with structural changes and improvements. RM 12.03.24
- v1.1 With attenuation after the equal power crossfade in order to prevent potential clipping as pointed out by Robert Syrett. RM 25.04.18
- After Rob Hordijk's VCA-SHAPER, using Robert Syrett's Waveshaper as a starting point. RM. 23.04.18
 

             E         i  j  k  l  m  n  o  p  s  t                                                                                                                  
   VCA-SHAPER  p<   <                    A  A(    C C   ֟\CD4N               -   scale {0.75, 0.75}
text("Curve", theme.text)
   @   @                 0   0     ?          >   .UcÞ
               \  b  c  e  g  L,   ,                   HC  CLC
               0   0                 D        V q0	               0   0                  ` C C   ETC               d(   (                 (   `lB                p          floor(p*6)/2+1  0   0                 l          C 	               0   0                 $         R  4  \C	                  P   04   4                 $   $     ?        7\wdC               ]  ^  8,   ,                   A      B @
               $   $                 A	               h < 8 0 (                   '                                                                     h   8   8                    {$?     *C  CXB͛               (   (                      C  ?               $   $                   4D                  $   $                 zQDӜ               T(   (                 (     4D   B                s          1-s (   (                 4     /D                     s      x          -x+s
   h                4G  & D                   fs     t                       F  &C                   fs     t                       <G  qeC          0   $            fall       rise       out    in      $              
aC               (,   ,           @G    C       BD
                              C D1               ,   ,           LG             L D	               ̸,   ,           G        p    J  C	               T$   $           4H     U`!D	               0   0           H  $   $     ?          MD  4            	   N  O  P  Q  R  S  T  U  V  4   4                 $   $     ?          B                 J  K  ,   ,                   A      B @
               $$   $                 A	               X(   (                      D  C?               (   (                 (   `DD                d2      
   d2 > 0.99
  p4   4                 h    B 0C                      <   <                    A  @    B  +C    :#N               0   0                 $          C  	               
   Control 2b  0   0                 $         6²_	                  Decay Control 2 d4   4                 dM?           qC  !               <   <                   B  A8       A    @D  N                mod     (   (                     C?%                   Mod    Slider      ,   ,                   ?  p D  
               ,   ,                   ?    OC  '	               D   D                   0   0     ?          B  4C  0&               ?  @  A  B  C  x4   4                           C   B               0$   $                 |~jC               ,   ,                         C  TB	               4D   D                 @  0   0     ?          B   C  02f               ;  <  =  ,   ,                   B   C;	               @(   (                      D  4C?               x$   $                 -8pǆB               (   (                     mD  H?               (   (                 <     C  4C                   Decay      Time        
   Time>Decay  L(   (                    CfB=               (   (                      D  ?               0   0                          p    ,	               0   0                 (        =A	               P0   0                 4    C     C  A
               (   (                 4  B	               (   (                 l    4B  0                       Max    Power      Control      8   8                   $   $     ?        n	B㎧               .  /  0  1  2  x$   $                 2<w/D               $   $                 KuC               $   $                 Z ßJ'D               $   $                 *
#8D               H$   $                 #&D               (   (                 ,   B|                Audio          -Audio  \4   4                     C  A   X8CT               4   4                     X      C   B               X$   $                 |~jC               4,   ,                        C  TB	               \D   D                   0   0     ?          4C  B  X8CT               #  $  %  '  ز,   ,                   4C  BX8CT
               0   0                 $     \C    CD 
               	   Env B BiP   0   0                 $     4C  $(C΢
                  Bipolar x                (   fB'                x          x*2-1   P(   (                     C?               (   (                 8   S8(C                   Env    Timer          Timer>Env+0.1
  |!4   4                     C  @     C                 l8   8                 ]B    C  \B     C                  8   8                    B(     B  @   CZg(C                  S & H   <   <                    A  A(    C  C   %C	AN               *   scale {0.8, 0.8}
text("Time", theme.text)
  h < 8 0 (               $                                                                         h   8   8                    A  A$   LaB`/@C'CN               ,   scale {0.8, 0.8}
text("S & H ", theme.text)
    h8   8                   B(      B  C   0kAOC                  DUAL ENVELOPE
  $4   4                 (    @	C PC       H                  R

 d$4   4                 (    @B PC       *                  S

 $4   4                 (     ?B 0C                         D
  $4   4                 H>    A @C                      0   0                 $      A  B    \                  B
  d@   @                 0   0     ?            @                                ,   ,                   HB  B  C  RC
               @   @                 0   0     ?          B  @    R                           ,   ,                   B  B  zC  
               ,   ,                   B   A  C  B
               (,   ,                   HB   A  fC   C	               $   $                   fC  B(               0   0                 $          D 	                  Repeat  8   8                   A  A     A  Ao؎M               8<   <                   A  A8     A  A    B N                switch      E  

if switch > 0 then 
	label = "Trig"
	circle_color = theme.azureHighlight
	border_color = theme.grooves
	text_color = theme.azureHighlightBackground
else 
	label = "Rpt" 
	circle_color = theme.azureHighlightBackground
	border_color = theme.azureHighlight
	text_color = theme.azureHighlight
end

save()
translate{canvas_width/2, canvas_height/2}
stroke_circle( {0,0}, 12, 4, color_paint(border_color))
fill_circle({0,0}, 11.5, color_paint(circle_color))

min, max = text_bounds(label)
scale{.9,.9}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
text(label, text_color)
restore()   0(   (                  .BlG                 x       $0   0                          ԷBT(                ?    (   (                 8     9  C                   Env    Timer       
   Timer>Env
  (   (                     qwL=               h0   0                 $     B     ;  C	                  Mode    (   (                      *  C?               0   0                     B     D  4	               |8   8                   A  A         A  p  HCM               <   <                   A  A8         A     B  CN                switch      F  

if switch > 0 then 
	label = "Trig"
	circle_color = theme.azureHighlight
	border_color = theme.grooves
	text_color = theme.azureHighlightBackground
else 
	label = "Gate" 
	circle_color = theme.azureHighlightBackground
	border_color = theme.azureHighlight
	text_color = theme.azureHighlight
end

save()
translate{canvas_width/2, canvas_height/2}
stroke_circle( {0,0}, 12, 4, color_paint(border_color))
fill_circle({0,0}, 11.5, color_paint(circle_color))

min, max = text_bounds(label)
scale{.9,.9}
translate{-(min[1]+max[1])/2, -(min[2]+max[2])/2}
text(label, text_color)
restore()  (   (                 8   B  C                x       h 4 0 (             $                                                                             h   0   0                            B  HC(                      (   (                      HB  C?               H0   0                 $     B       D	                  Mode    0   0                     RC  4Î94CA)
               (   (                 <     *C  C                   Attack     Time           Time<Attack ,(   (                    G:o
                  3
  l(   (                    h¿                  2
  $   $                  @C C               $   $                   `C  B               $   $                   B  B               D$   $                   !C  =C               0   0                  @ C PC     \C  M               $   $                 CCuDC               0   0           A                                                C                  x       S(   (                    C  
                                  alz                   A      B       T(   (             4       4  	               HT(   (             4       4  	               d,   ,           $   $     ?        BHD                           0   0           ںA(           ZX                  or  h                P 8A	                x       \U(   (                  RCD	
                               4   alz                   A      B          (B==0)*(A==0)   U(   (             4     .z	               (V(   (             4     .=.	               e,   ,           $   $     ?        52OC                           $   $                     4D               $   $                 py%<D               $   $                     %D               ,$   $                     %D               h 4 0 (                                                                         '                 h   0   0                   pB  4   ʑPC ڹ               <8   8                    $   $     ?          p                  f  }                                       	     E  a     Envelope Core   0   0                 $         p  C   	                  Env B Decay ,0   0                 $         4    	                  Time    x0   0                 d$          C  p	               0   0                 $         p  C  	               	   Control 2   0   0                 $     \C    BD7
               	   Env A Mod   X0   0                 $           C  	                  Contol 4    0   0                 $     \C    CD  
               	   Env B Mod   0   0                 $         R  C 	                  Env B Attack    L0   0                 $           C  	               	   Control 3   0   0                    X=      C 	                8   8                   Bh  DWI     C               	D   D                   0   0     ?          HB  B    4                             (,   ,                   HB        $C
               d,   ,                   H       C	               (   (                 8      C                   Mod    Control        clamp(Control-Mod,0,1)  M4   4                    A   Aܨ         pCN                   mod    control     [,   ,                 *=      C               >4   4                            C   B               H $   $                 |~jC               $,   ,                         C  TB	               LD   D                 (  0   0     ?          HB  B                           <   <                    A  @    HB  B       N               ,   ,                   HB  B    	               8   8                   B(    DWI     C                  D   D   D                   0   0     ?          B  B    4                             ,   ,                   HB        $C
               H,   ,                   H       C	               (   (                 x     C                   Mod    Control     Q4   4                    A   A         pCN                   mod    control     p_,   ,                 c3>      C               XB4   4                 8          C   B               $   $                 |~jC               ,   ,                         C  TB	               D   D                 `  0   0     ?          B  B                           <   <                    A  @   @B @B       N               ,   ,                   B  B    	               p(   (                    .D                  5   (   (                                       20   0   0                 m        p    ,	               @0   0                 m        =A	               0   0                 n    C     C  A
               0(   (                 n  B	               (   (                 <n    4B  0                       Max    Power      Control     DI8   8                 Pn  $   $     ?        JB            	                     `,   ,                   pB      B    
               $   $                         	               $J8   8                   $   $     ?          C  D                   $,   ,                   pB      B    
               $   $                         	               J8   8                 X  $   $     ?          aD  D                   ,   ,                   pB      B    
               |	$   $                         	               K8   8                   $   $     ?          C  D                   (   (                    C?               <(   (                     D  C?               t(   (                      D  C?               (   (                 <   pCAC                   Attack     Time           Time>Attack $   $                 \AEC-               \0   0                 h        p    ,	               0   0                 h        =A	               0   0                 h    C     C  A
               H6(   (                 h  B	               D(   (                 h    4B  0                       Max    Power      Control     N8   8                 h  $   $     ?          B  A                         t%                (  & D                   fs     t       %                  &C                   fs     t       &                0  qeC          0   $            fall       rise       out    in      0              
aC               4,   ,           4    C       BD
                              C D1               ,   ,           @             L D	               ,   ,                   p    J  C	               `$   $           (     U`!D	               0   0             $   $     ?        6D_AC                                 (  )  *  +  ,  (   (                 @U     B  C               $0   0                 c        p    ,	               D$0   0                 c        =A	               $0   0                  d    C     C  A
               :(   (                  d  B	               (   (                 8d    4B  0                       Max    Power      Control     HS8   8                 Ld  $   $     ?          B  R                         %0   0                 0b        p    ,	                &0   0                 8b        =A	               @&0   0                 Db    C     C  A
               <(   (                 Db  B	               (   (                 |b    4B  0                       Max    Power      Control     U8   8                 b  $   $     ?        BC                         |'0   0                 $             \	                  Release Control '0   0                 $           C  B	                  Sustain Control $(0   0                 D       4    	               d(0   0                 $        p    A	               (0   0                     4C      D  4C
               ?(   (                 t  $C	               )0   0                 
            C	               DW8   8                    $   $     ?         	D  f            +   ~                                                  -  3  4  5  6  8  D  H  I  L  M  W  X  Y  Z  [  _  `     Analog ADSR Envelope Core   d(   (                                         0.001   *0   0                 $         	                  Min  +0   0                 \        p    ,	               @+0   0                 \        =A	               +0   0                 ]    C    ^C
               A(   (                 ]  B	               (   (                 T   p2B:          ,               Min    Max    Power      Control        Control^Power*(Max-Min)+Min pZ8   8                 $]  $   $     ?                           v  w  x  y  z  {  (   (                    $A5A>               (   (                 <      B                   Attack     Timer          Timer<Attack    |$   $                     4C-                2                |   & D                   fs     t       h2                4   &C                   fs     t       )   exp(ln(.01)/((t*.99999+.00001)*fs+.0001))   2                T       C          0   $            fall       rise       out    in      (   in>out?in+rise*(out-in):in+fall*(out-in)    <              
aC               @,   ,           (     C       BD
                  Output                 C D1               ,   ,           (              L D	               	   Rise Time   h 0 , $                                                                        #                   h   ,   ,           (         p    J  C	               	   Fall Time   h ( $                                                                                             h   $   $                      *D	                  Input   x 4   ,   $                                                                                                       x   0   0           d   $   $     ?        4&               i  j  k  l  m  n  o  p  q             Exponential Slew    \(   (                 <U  1               `8   8                    $   $     ?         	D 	               [  a  b  c  d  e  g  h  r  s  t  u  |                    d     Analog AD Envelope  d30   0                 $         p   p	                  Decay Control   30   0                 $            	                  Attack Control  8J(   (                 L    R  C	               D40   0                 $            	                  Time Constant   40   0                 $     4C    )CWV
                  Mod 40   0                 S        p    ,	                50   0                 S        =A	               `50   0                 $S    C     C  A
               K(   (                 $S  B	               (   (                 \S    4B  0                       Max    Power      Control     $d8   8                 pS  $   $     ?            f               \  ]  ^  _  `  a4   4                 |          C   B               "$   $                 |~jC               ,   ,                         C  TB	               .D   D                   0   0     ?          4C  pB    C                  X  Y  Z  H,   ,                   4C  pB  C  H
               ̏4   4                   B$   @!CCBӜC]x                  Time
   h 4 0 (                                                                                           h   0   0                 $     ? 0C                       A
  <   <                    A  @     (C *C   9&2N               0   0                 0g>        qC  !               <   <                   B  A,       A    @D  N                mod     (   (                     C?%                   Mod    Slider      ,   ,                   ?  p D  
               ,   ,                   ?    OC  '	                2D   D                   0   0     ?          *C  4C  g9&               N  O  P  Q  R  e4   4                           C   B               <'$   $                 |~jC               ,   ,                         C  TB	               @3D   D                 4  0   0     ?          *C   C  grL               J  K  L  ,   ,                   *C   Cg9&9	                <   <                    A  @   
C *C   s9&0N               l4   4                 
Ƣ>           qC  !               <   <                   B  A       A    @D  N                mod     8(   (                     C?%                   Mod    Slider      0,   ,                   ?  p D  
               l,   ,                   ?    OC  '	               5D   D                 L  0   0     ?          C  4C  g9&               B  C  D  E  F  h4   4                           C   B               *$   $                 |~jC               ,   ,                         C  TB	               6D   D                   0   0     ?          C   C  3rL               >  ?  @  ,,   ,                   C   C9&7	               t<   <                    A  @<    B  +C   J9&2N               Xp4   4                 Mr>           qC  !               <   <                   B  AD       A    @D  N                mod     (   (                     C?%                   Mod    Slider      ,   ,                   ?  p D  
               ,   ,                   ?    OC  '	               9D   D                 ؓ  0   0     ?          B  4C  '9&               6  7  8  9  :  ll4   4                 $          C   B               $.$   $                 |~jC                 ,   ,                         C  TB	               (:D   D                 L  0   0     ?          B   C  3rL               2  3  4   ,   ,                   B   C3=9&9	               <   <                    A  @ȋ    @B  +C   sy9&4N               s4   4                 +E>           qC  !               x<   <                   B  AЌ       A    @D  N                mod      (   (                 0    C?%                   Mod    Slider      ,   ,                   ?  p D  
               T,   ,                   ?    OC  '	               |<D   D                 d  0   0     ?          HB  4C  3V9&               *  +  ,  -  .  o4   4                           C   B               1$   $                 |~jC               t,   ,                         C  TB	               =D   D                 ؐ  0   0     ?          HB   C  ?b&               &  '  (  ,   ,                   HB   Ck9&;	               4q4   4                 ̬   @     瞖CsB               2$   $                   bC  XB               ,   ,                         C  TB	               >D   D                 n  0   0     ?           A   A    H  C               !  "  #  Lr4   4                 D          C   B               4$   $                 |~jC               ,   ,                        C  TB	               @D   D                 l  0   0     ?          4C   A    C                       "<   <                    A  @$    A  +C   i5N               py4   4                 <=           qC  !               #<   <                   B  A,       A    @D  N                mod     (   (                 8     C?%                   Mod    Slider         clamp(Slider-Mod,0,1)
  ,   ,                   ?  p D  
               ,   ,                   ?    OC  '	               <BD   D                   0   0   p@G  nB  A  4C  9&                         u4   4                           C   B               X7$   $                 |~jC               4	,   ,                         C  TB	               \CD   D                   0   0     ?          A   C  rL                     	,   ,                   A   C9&=	               
,   ,                   4C   A  C  
               L
,   ,                    A   A    B	               JD   ,  ,                  C  ?C      y@2CNC  C    # Dual Envelope
## After Rob Hordijk
<https://forum.audulus.com/t/hordijk-dual-envelope/513>

### Envelope A  
 The first of the two envelopes is a standard (analogue style) ADSR, though with the addition of a second decay for the sustain section, i.e AD[S]DR. An overall timing control ( 0 – 20 seconds) is provided and there are modulation inputs for each stage of the envelope. 
 
 There is a special ‘Trigger’ mode available for the incoming gate signal in which the attack stage of the envelope will always be allowed to be completed before the next gate is allowed through. (With long attack times this means that the envelope can function as a kind of clock divider.) 
 
 In the standard ‘Gate’ mode the next gate signal will restart the envelope regardless of whether the attack has been completed or not. 
 
 A curve control enables shaping the slope of the exponential curves (only affects envelope A).   
 
### Envelope B 
 
 The second is a simpler AD envelope that is always set to the ‘trigger’ mode mentioned above and shares the same gate input as envelope A.  
 
 The ‘Repeat’ button cycles the envelope so that it repeats as soon as the decay stage is completed, regardless of the gate input. In this mode it can also reach audio rates. 
 
 Envelope B has a bipolar output in addition to its regular modulation output that can be useful for filter or oscillator modulations, or for use as a sound source in itself.      
 
 A sample and hold circuit is included as an aid to modulating the envelopes (since one would otherwise need very slow LFOs to effectively modulate the various envelope stages).  
 
 ### Notes
 If the fader for the second decay (the sustain section of the envelope) is set to it’s highest point, then the sustain will be constant at the level set by the sustain (S) fader.            
 
 The modulation input for the attack stage of both envlopes is inverted, i.e. greater modulation will make the attack shorter, which can be useful if when used e.g. in conjunction with keyboard velocity as a modulation source. The louder the sound the shorter the attack.

***

### Controls 

- Green sliders – Time parameters for the four stages (AD[S]DR) of envelope A, fader ‘S’ sets the ‘sustain’ level, or point from which decay 2 begins. 
- Time slider – Controls the maximum time of each time paramter from 0 to 20 seconds, scaled exponentially
- ‘Curve’ knob for shaping the slope of the exponential curves.
- ‘A’ knob – Sets the attack parameter for envelope A
- ‘D’ knob – Sets the decay parameter for envelope B
- Gate/Trig button – Select between gate or trigger mode (as described above)
- Repeat/Trig button – Select between repeat or trigger mode for envelope B (as described above)  


### Inputs

- 6 × M – Modulation inputs for the slider controls
- M - Modulation input for the ‘A’ knob (attack envelope B).
- M - Modulation input for the ‘D’ knob (decay envelope B).
- G - Gate input to trigger the envelopes
- Sample and Hold input  

### Outputs 

- Sample and Hold output
- A (M) - Modulation output for the A envelope
- B (A) - Bipolar output for the B envelope
- B (M) - Modulation output for the B envelope
  
  ---
  
### Version History

- 2.1 – 02.03.24: Version with a second decay for the sustain section. 
- 2.0 – 25.02.24: New version for Audulus 4 by Rudiger Meyer, based the multimode envelope in the Audulus Library.   
- 1.1 – 09.06.18: Rudiger Meyer 
- 1.0 – 03.18: Rudiger Meyer, based on ST Schoen’s uLope modules                  @                    $  %  )  /  0  1  5  ;  <  =  A  G  H  I  M  S  T  U  V  W                      
                                !  "  &  7  9  :  >  F  G  f     Dual Envelope   SD   D                 H   0   0     ?        8@\A  C    C  *                 
       Value Display   X,   ,                   I@D  	               J(   (                    5DA               4   4                 P   @     瞖CsB               hI$   $                   bC  XB               D,   ,                         C  TB	               lUD   D                 4X  0   0     ?          HB   A   @D  8                   	  ,   ,                   HB   A  C  
               ^0   0                     pC   @;D  LB
               `,   ,                   pB      B    
               J$   $                         	               $8   8                 H  $   $     ?        dk S"                   |K$   $                     B               (   (                    BGB                   Old    New     `0   0                     B  >myCN_GB
               v(   (                     D   B	               t8   8                 4  $   $     ?          7D                         `0   0                 (%        @C
	               O(   (                    D=               P(   (                 <    C  $B                   Gate       Trigger        clamp(Trigger+Gate,0,1) a0   0                           C  4B	               4   4                 t   @     瞖CsB               DN$   $                   bC  XB                 ,   ,                         C  TB	               HZD   D                 XS  0   0     ?           A  B                          <<   <                   @   A(     A  B   Q'N                  -- Set the number of dots
dots = 3

-- Default gray color
gray = color_paint{1,1,1,.8}

for i = 1,dots do fill_circle({i*2,2},.5,gray) end  !,   ,                    A  B   	               =<   <                   @  @A(     A  B    @  oN                  -- Set the number of dots
dots = 5

-- Default gray color
gray = color_paint{1,1,1,.8}

for i = 1,dots do fill_circle({i*2,2},.5,gray) end  4   4                 p          C   B               PQ$   $                 |~jC               ,#,   ,                         C  TB	               T]D   D                  q  0   0     ?           A  B     0                     #,   ,                    A  B   y	               @<   <                   A  AH     $B  B     C  N                   Toggle     Select      ^  -- This gray matches the default text color

gray = {1,1,1,0.8}

-- Checks if the Select input is equal to a certain value then displays the corresponding text to match it. To expand the number of options, copy and paste the elseif statement (shown below) and place it above the final else statement.

-- elseif Select == 2 then
-- text("OPTION2.5", gray) 

-- Note that the Select input works with whole positive integers.

function Hz()
	translate {0, 1}
	scale {0.8, 0.8}
	text("max", gray)
end

function BPM ()
	if Select == 0 then 
		text(" /1", gray)
	elseif Select == 1 then
		text(" /2", gray)
	elseif Select == 2 then
		text(" /4", gray) 
	elseif Select == 3 then
		text(" /8", gray) 
	elseif Select == 4 then
		text("/16", gray) 
	elseif Select == 5 then
		text("/32", gray) 
	else
		text("/64", gray) 
	end
end

if Toggle == 0 then Hz() else BPM() end  aD   D                 P   0   0     ?        GB  B     n                            Mini Knob w/ Mod In \(,   ,                    B    b#C
               (,   ,                           C	               0((   (                 (Z     C                   Mod    Control     4   4                    A   A<          pCN                   mod    control       -- Default color picker for the module library

azure = color_paint {0, 0.83137254902, 1, 1}
azure_dark = color_paint {0, 0.60784313725, 0.7294117647, 1}
azure_back = color_paint {0, 0.05882352941, 0.07843137254, 1}

green = color_paint {0.23137254902, 0.76862745098, 0.33333333333, 1}
green_dark = color_paint {0.14901960784, 0.51372549019, 0.02745098039, 1}
green_back = color_paint {0, 0.07843137254, 0.01176470588, 1}

red = color_paint {1, 0, 0.38431372549, 1}
red_dark = color_paint {0.65098039215, 0, 0.25098039215, 1}
red_back = color_paint {0.10980392156, 0, 0.0431372549, 1}

gray = color_paint {1,1,1,0.8}

black = color_paint {0,0,0,1}

white = color_paint {1,1,1,1}


-- Declare size and color variables

radius = 11.5
width = 2
paint = red_dark

-- Assign pi 

pi = 3.1415926535
pi2 = 6.28318530718

-- Rotate so that beginning points match

rotate(0.5 * pi)

-- Calculate initial variables to animate modulation

aperture = mod * pi
rotation = control * pi2 + aperture

-- Calculate how much the animation overshoots (wraps around the bottom)

over = math.max(-pi2 + rotation + aperture, 0)

-- Recalculate variables taking overshoot into account

aperture2 = mod * pi - over/2
rotation2 = control * pi2 + aperture2

-- Draw arc

stroke_arc( {0, 0}, radius, width, rotation2, aperture2, paint)    0   0                       ?     C               .,   ,                   pB      B    
               ]$   $                         	               8   8                 8  $   $     ?        ]C                   /,   ,                   pB      B    
               D^$   $                         	               t8   8                 t  $   $     ?        ~|Dy%                   t0,   ,                   pB      B    
               _$   $                         	               88   8                   $   $     ?        z!C9&                   8   8                 d  $   $     ?          6C                                                                         `t0   0                 $         ;yHs	                  Max/PPQ Control t0   0                 $         &uB	                  Hz/BPM Control  u0   0                 Pu    pC    HDk
               Hu0   0                 $     pC  bD
                  Hz/BPM Value    u0   0                 d    pC  pº'CH
               u0   0                 $         z!C9	               
   Run Button  X(   (                    DkKB	                  Mode Toggle tv0   0                 $         p ,D 	               
   PW Control  8   8                 `   $   $     ?        BBH                                          PPQ Selector    Tw0   0                 $     4C     C 1
               	   PPQ Value   Ѝ(   (                        >	               w0   0                 $     4C  ށC  >
                  Select Value     5(   (                      B  >                  16  `5(   (                      B  /                  8   5(   (                      B                     4   5(   (                      B                    2    6(   (                 v   B                 X6(   (                      B                    0.5 6(   (                      B                    0.25    g(   (                    ŃCm ?               h(   (                    ,D?               8   8                   A(     B  B                        Run ,rD   D                 T   0   0     ?          @B  B                                   Button Switch   0{0   0                 (o    B     D  \B
               \g$   $                 V
D(B               {0   0                 n    B     C  DB
               (   (                 tn       B	               h$   $                 MC_               h , (                                                                                             h   (   (                    KB@+
B(                ?    T                ,   HQB                Sample         1-Sample    08   8                 D   $   $     ?        ۻBP\B                         	   Flip-Flop   i$   $                 p},B               k(   (                    .CD>               l(   (                    ~D>               L;(   (                 ,   PDW|                Value          floor(Value*100)/100    l(   (                    I-D:%F?               ;(   (                 ,   
ACй                Control        floor(Control*200.999)+20   P<(   (                 4   _CX                   PPQ    BPM     
   BPM/60*PPQ  h 0 , $                                                                          #                h   ,   ,                         9D                 T=(   (                 ,   83B                Control        floor(Control*6.999)    @4   4                 P3    @     瞖CsB               l$   $                   bC  XB               >,   ,                         C  TB	               xD   D                 x3  0   0     ?          HB   B  6[V                     t?,   ,                   HB   Bا]
               [<   <                   A  A8     @ C     _C  (N                Toggle         -- This gray matches the default text color

gray = {0.8,0.8,0.8,1}

-- Displays one text option when the Toggle input is 0 and another text option when the Toggle input is not 0.

if Toggle == 0 then 

text(" Hz", gray) else
text("BPM", gray)
end

   h 4 0 (                                                                                           h   0   0                       A  CԘB)               D8   8                   A(     B C      B                  PW  `A(   (                 ,   A!'CZ                Phasor         Phasor<1    p$   $                 rZC(               0   0                 $         1l]CMQ	                  PWM Control <B(   (                 8   eDA                   PW     Phasor         Phasor<(2*pi*PW)    q$   $                 .2)B*!B%               0   0                 $         ph3A	                  Sync    d(   (                    (rB	                  Hz  x0   0                 c    C      HD  B
               8   8                 P   $   $     ?        UDP                               
   Clock Core  $D(   (                 ,   螈B                Control     
   50*Control  |D(   (                    7CqA                  3   ̇0   0                 $         p    ,	                  Max 0   0                 $         =A	                  Power   `0   0                 $     C     C  A
                  Out Ԟ(   (                    B	                  Control E(   (                 H     4B  0                       Max    Power      Control        Control^Power*Max   P8   8                 D   $   $     ?        *C=B                            Exponential Max Control Scaler  d4   4                 ,*    @     瞖CsB               v$   $                   bC  XB               G,   ,                         C  TB	                D   D                 T*  0   0     ?           A   A  *	                     H,   ,                    A   A8	               d<   <                    A  @C    ,B  +C      N               ,e<   <                    A  @C  cSA+C   ~"Ê,5CN               ,   ,                 ?   pC!               e<   <                   B  AD    ?  A   Q6DLXN                mod     \I(   (                 G    C?%                   Mod    Slider      TJ,   ,                   A  p D  
               J,   ,                   A    OC  '	               D   D                 (H  0   0     ?          B  4C                              4   4                 tH          C   B               y$   $                 |~jC               K,   ,                         C  TB	               ؅D   D                 H  0   0     ?          4B   C      ,                     PL,   ,                   4B   C    	               ,   ,                 ??   pC!               h<   <                   B  AtA    ?  A   Q6DLXN                mod     |L(   (                 D    C?%                   Mod    Slider      tM,   ,                   A  p D  
               M,   ,                   A    OC  '	               ؇D   D                 E  0   0     ?          @  4C     XC                         <4   4                 TE          C   B               |$   $                 |~jC               N,   ,                         C  TB	               D   D                 |E  0   0     ?          pA   C  ktwC                     pO,   ,                   pA   Ckt.C	               D   	  	                  C  pBx	        ?              Clock - v1.0

— — — 


- Controls - 

Mode toggle - Toggles between Hz and BPM modes

Hz/BPM slider - Controls the speed of the clock in either Hz or BPM depending on how the Mode toggle switch is set. Hz can range from 0 to 50Hz and BPM from 20 to 220.

PW slider - Controls the pulse width of the clock from 0 to 100%

Run button - Starts and stops the clock

max/subdivision knob - Controls either the maximum Hz value (0 to 50Hz scaled exponentially) or the subdivision value for the clock (1 bar to 1/64th note). 


- Inputs -

M - Modulation input for Hz/BPM slider

M - Modulation input for PW slider

G - Gate input to remotely start/stop module (high = run, low = stop). Will not function if Run button is turned on.

M - Modulation input for max/subdivision knob

S - Sync input resets the clock on rising edge


- Outputs - 

S - Outputs a sync signal when Run button is turned on

G - Gate signal as clock output


— — — 


The Clock module generates a periodic gate signal. The length of the gate is called the pulse width.

The Clock module has two modes: Hz and BPM.

In Hz mode, the clock’s speed input is displayed in Hz. The maximum clock speed in this mode is 50Hz depending on how the max knob is set.

In BPM mode, the clock is first set to a BPM from 20 to 220. Then the clock speed is subdivided by the subdivision knob. The available subdivisions are:

/1 - 1 Bar
/2 - Half note
/4 - Quarter note (Equal to BPM)
/8 - 8th note
/16 - 16th note
/32 - 32nd note
/64 - 64th note

The Run button will start and stop the clock, simultaenously resetting the clock and outputting a sync signal used to syncronize external modules (such as two separate sequencers). The gate input for the Run button will turn the button on and off remotely, but only if the Run button itself is turned off. 

Clocks can be used to drive sequencers, trigger envelopes and samples, trigger a sample & hold, and much more.

The sync input is used to restart the clock. It always restarts high (outputting a value of 1).

The PW slider value is sampled at the rising edge of each clock pulse. This means any change to the PW slider will only be noticeable on the following clock pulse.


— — — 

Version History

1.0 - 2022.07.15 - Created                  }  ~                                                           Clock   du<   <                    A  @L3    dC  +C    @TD DN               H4   4                   ?           qC  !               u<   <                   B  AT4       A    @D  N                mod     Y(   (                 7    C?%                   Mod    Slider      Z,   ,                   ?  p D  
               Z,   ,                   ?    OC  '	               D   D                 7  0   0     ?          fC  4C   wD @(D               v  w  x  y  z  \4   4                 48          C   B               $   $                 |~jC               [,   ,                         C  TB	               D   D                 \8  0   0     ?          fC   C   kD  0D               r  s  t  \,   ,                   fC   C  bD D	               x<   <                    A  @/    FC  +C    &D DN               4   4                 ͂=           qC  !               hy<   <                   B  A0       A    @D  N                mod     ](   (                 @4    C?%                   Mod    Slider      ^,   ,                   ?  p D  
               D^,   ,                   ?    OC  '	               lD   D                 t4  0   0     ?          HC  4C    JD @'D               j  k  l  m  n  4   4                 4          C   B               $   $                 |~jC               d_,   ,                         C  TB	               D   D                 4  0   0     ?          HC   C    >D  /D               f  g  h  `,   ,                   HC   C 4D D	               L|<   <                    A  @d,    (C  +C     C  DN               04   4                 QH=           qC  !               |<   <                   B  Al-       A    @D  N                mod     `(   (                 0    C?%                   Mod    Slider      |a,   ,                   ?  p D  
               a,   ,                   ?    OC  '	               D   D                  1  0   0     ?          *C  4C   D &D               ^  _  `  a  b  D4   4                 L1          C   B               $   $                 |~jC               b,   ,                         C  TB	                D   D                 t1  0   0     ?          *C   C   D .D               Z  [  \  xc,   ,                   *C   C @D @D	               <   <                    A  @(    
C  +C     C DN               4   4                 m'?           qC  !               P<   <                   B  A)       A    @D  N                mod     c(   (                 X-    C?%                   Mod    Slider      d,   ,                   ?  p D  
               ,e,   ,                   ?    OC  '	               TD   D                 -  0   0     ?          C  4C   C &D               R  S  T  U  V  4   4                 -          C   B               p$   $                 |~jC               Lf,   ,                         C  TB	               tD   D                  .  0   0     ?          C   C   C @.D               N  O  P  f,   ,                   C   C C  D	               4<   <                    A  @|%    B  +C     B @DN               4   4                 s=           qC  !               ă<   <                   B  A&       A    @D  N                mod     lg(   (                 )    C?%                   Mod    Slider      dh,   ,                   ?  p D  
               h,   ,                   ?    OC  '	               ȢD   D                 *  0   0     ?          B  4C    }C  'D               F  G  H  I  J  ,4   4                 d*          C   B               $   $                 |~jC               i,   ,                         C  TB	               D   D                 *  0   0     ?          B   C    MC .D               B  C  D  `j,   ,                   B   C  'C D	               <   <                    A  @"    B  +C      DN               4   4                 u>           qC  !               8<   <                   B  A#       A    @D  N                mod     j(   (                 p&    C?%                   Mod    Slider      k,   ,                   ?  p D  
               l,   ,                   ?    OC  '	               <D   D                 &  0   0     ?          B  4C    B &D               :  ;  <  =  >  4   4                 &          C   B               X$   $                 |~jC               4m,   ,                         C  TB	               \D   D                 '  0   0     ?          B   C    A @.D               6  7  8  m,   ,                   B   C    D	               <   <                    A  @    @B  +C      @DN                4   4                 @>           qC  !               <   <                   B  A       A    @D  N                mod     Tn(   (                 "    C?%                   Mod    Slider      Lo,   ,                   ?  p D  
               o,   ,                   ?    OC  '	               D   D                 0#  0   0     ?          HB  4C      &D               .  /  0  1  2  4   4                 |#          C   B               ̞$   $                 |~jC               p,   ,                         C  TB	               ЪD   D                 #  0   0     ?          HB   C    ' -D               *  +  ,  Hq,   ,                   HB   C  M D	               h4   4                 (     @     瞖CsB                  S   ($   $                   bC  XB               r,   ,                         C  TB	               ,D   D                 H   0   0     ?           A   B  /+DD               %  &  '     Sync IO Light   4   4                 d>   @     瞖CsB               T$   $                   bC  XB               0s,   ,                         C  TB	               XD   D                 H   0   0     ?           A   A  +DR˴D               !  "  #     Gate I/O Light  t8   8                   ,B`-             C               D   D                   0   0     ?          HC  B  `;DD                           t,   ,                   HB        $C
               t,   ,                   H       C	               pt(   (                      C                   Mod    Control     44   4                    A   A         pCN                   mod    control     h 0 , $                    #                                                                      h   ,   ,                   ?      C               P4   4                 @          C   B               $   $                 |~jC               v,   ,                         C  TB	               D   D                 h  0   0     ?          HC  B  `;D슌D                     <   <                    A  @     FC  B   BhCjDN               w,   ,                   HC  BvC슃D	               8   8                   B(     `       C                  Begin
  LD   D                 T   0   0     ?          HB  B  `D*D                              Knob w/ Mod In  x,   ,                   HB        $C
                y,   ,                   H       C	               x(   (                 	     C                   Mod    Control     |4   4                    A   A<          pCN                   mod    control       -- Default color picker for the module library

azure = color_paint {0, 0.83137254902, 1, 1}
azure_dark = color_paint {0, 0.60784313725, 0.7294117647, 1}
azure_back = color_paint {0, 0.05882352941, 0.07843137254, 1}

green = color_paint {0.23137254902, 0.76862745098, 0.33333333333, 1}
green_dark = color_paint {0.14901960784, 0.51372549019, 0.02745098039, 1}
green_back = color_paint {0, 0.07843137254, 0.01176470588, 1}

red = color_paint {1, 0, 0.38431372549, 1}
red_dark = color_paint {0.65098039215, 0, 0.25098039215, 1}
red_back = color_paint {0.10980392156, 0, 0.0431372549, 1}

gray = color_paint {1,1,1,0.8}

black = color_paint {0,0,0,1}

white = color_paint {1,1,1,1}


-- Declare size and color variables

radius = 24
width = 2
paint = red_dark

-- Assign pi 

pi = 3.1415926535
pi2 = 6.28318530718

-- Rotate so that beginning points match

rotate(0.5 * pi)

-- Calculate initial variables to animate modulation

aperture = mod * pi
rotation = control * pi2 + aperture

-- Calculate how much the animation overshoots (wraps around the bottom)

over = math.max(-pi2 + rotation + aperture, 0)

-- Recalculate variables taking overshoot into account

aperture2 = mod * pi - over/2
rotation2 = control * pi2 + aperture2

-- Draw arc

stroke_arc( {0, 0}, radius, width, rotation2, aperture2, paint)  h , (                                                                                             h   (   (                       C               4   4                           C   B               l$   $                 |~jC               H,   ,                         C  TB	               pD   D                   0   0     ?          HB  B  `DʛD               	  
    <   <                    A  @    @B  B   C쪓DN               4,   ,                 0HB  BCʒD	                8   8                   ,B(    oR       C                  <<-->>  D   D                 T   0   0     ?          B  B  :#D fD                               Big Knob w/ Mod In  L,   ,                   pB        $C
               ,   ,                   p       C	                (   (                 8      C                   Mod    Control        clamp(Control+Mod,0,1)  h 8 4 ,                 $                                                       +                 h   4   4                    A   A<          pCN                   mod    control       -- Default color picker for the module library

azure = color_paint {0, 0.83137254902, 1, 1}
azure_dark = color_paint {0, 0.60784313725, 0.7294117647, 1}
azure_back = color_paint {0, 0.05882352941, 0.07843137254, 1}

green = color_paint {0.23137254902, 0.76862745098, 0.33333333333, 1}
green_dark = color_paint {0.14901960784, 0.51372549019, 0.02745098039, 1}
green_back = color_paint {0, 0.07843137254, 0.01176470588, 1}

red = color_paint {1, 0, 0.38431372549, 1}
red_dark = color_paint {0.65098039215, 0, 0.25098039215, 1}
red_back = color_paint {0.10980392156, 0, 0.0431372549, 1}

gray = color_paint {1,1,1,0.8}

black = color_paint {0,0,0,1}

white = color_paint {1,1,1,1}


-- Declare size and color variables

radius = 34
width = 2
paint = red_dark

-- Assign pi 

pi = 3.1415926535
pi2 = 6.28318530718

-- Rotate so that beginning points match

rotate(0.5 * pi)

-- Calculate initial variables to animate modulation

aperture = mod * pi
rotation = control * pi2 + aperture

-- Calculate how much the animation overshoots (wraps around the bottom)

over = math.max(-pi2 + rotation + aperture, 0)

-- Recalculate variables taking overshoot into account

aperture2 = mod * pi - over/2
rotation2 = control * pi2 + aperture2

-- Draw arc

stroke_arc( {0, 0}, radius, width, rotation2, aperture2, paint)  h 4 0 (                     '                                                                     h   0   0                    ?      C               4   4                 	          C   B               `$   $                 |~jC               <,   ,                         C  TB	               dD   D                 
  0   0     ?          B  4B  `;DuD                     <   <                    A  @    B  `B   vCؕeDN               (,   ,                   B  4BvCcD	               H4   4                 H          C   B                $   $                 |~jC               ܋,   ,                         C  TB	               D   D                 p  0   0     ?          pCp A  aDh	D                     <   <                    A  @(     A  +C     DN                  -- Set the number of dots
dots = 3

-- Default gray color
gray = color_paint{0.8,0.8,0.8,1}

for i = 1,dots do fill_circle({2,i*2},.5,gray) end h 8 4 , $                  #                                                                      h   4   4                 	>           qC  !               <   <                   B  A4        A    @D  N                mod     W  -- Default color picker for the module library

azure = color_paint {0, 0.83137254902, 1, 1}
azure_dark = color_paint {0, 0.60784313725, 0.7294117647, 1}
azure_back = color_paint {0, 0.05882352941, 0.07843137254, 1}

green = color_paint {0.23137254902, 0.76862745098, 0.33333333333, 1}
green_dark = color_paint {0.14901960784, 0.51372549019, 0.02745098039, 1}
green_back = color_paint {0, 0.07843137254, 0.01176470588, 1}

red = color_paint {1, 0, 0.38431372549, 1}
red_dark = color_paint {0.65098039215, 0, 0.25098039215, 1}
red_back = color_paint {0.10980392156, 0, 0.0431372549, 1}

gray = color_paint {1,1,1,0.8}

black = color_paint {0,0,0,1}

white = color_paint {1,1,1,1}

-- Declare variables

height = 110
radius = 8

-- Make the circle move

move = mod * height

-- Draw circle

translate{radius,0}
stroke_circle( {0, move}, radius, 2, red_dark) (   (                 8     C?%                   Mod    Slider         clamp(Slider+Mod,0,1)
  ,,   ,                   ?  p D  
               h,   ,                   ?    OC  '	               D   D                 P   0   0     ?          A  4C     %D                            Slider  h 8 4 ,                                                                         +                 h   4   4                 (           C   B                  M   ($   $                 |~jC               ,   ,                         C  TB	               ,D   D                 H   0   0     ?          A   C     @-D                        Mod I/O Light   ,   ,                   A   C    D	               ,   ,                   C   qz                   If the sampled random value is greater than the value of the Direction control then swap the Begin and End control inputs; otherwise do nothing.     (   (                    hMXm?               X(   (                    /OÁ?               0   0                 $         #B	                  Direction Control   (   (                 <   hÐ                	   Direction      x          x>Direction


  h , (                                                                                             h   (   (                   8Ĵ               (              (               `,   ,                 OC   _VD0`T               o   If the Begin value is greater than the End value, subtract one from the Count; otherwise, add one to the count. ,   ,                  C     Cye               n   If the Count is greater than the End value, subtract 1 from the Count; otherwise send the Current Begin value.  ,   ,                   eC      C               w   If the Reset signal is greater than 0, then send the Current Begin value to be sampled; otherwise send the Count value. x ,   ,                  C     C  "C               r   If the Count is less than the Current End value then add one to the Count; otherwise send the Current Begin value.  ,   ,                   pB      C  B
               ($   $                   C  B	               L4   4                 $   $     ?        +}GsC                   $   $                 d#C~B               P                8    C~                   End    Count       	   Count>End   @(   (                 8    'D                     End    Begin       	   Begin>End   (   (                 ,     C                 Count          Count-1 (   (                     qD  ?               ,(   (                    Dr?               h(   (                 ,     C                  Count          Count+1 (   (                     D  pA?               $   $                     B               ((   (                   BGB                   Old    New     0   0                 $	    B  >myCN_GB
               (   (                 	    D   B	               8   8                 	  $   $     ?        lC                       H$   $                     B               (   (                 4   BGB                   Old    New        New>Old
    (   (                    +GOC?               (   (                      B 
                  1
  T(   (                      C  !@               (   (                      C  @               ȟ(   (                    wB5                  0.4 (   (                      C  @               P0   0                 d           	               0   0                 $       p  
  a	                  End l,   ,                   RC     `D  B               ,   ,                   4C     D  B               ,   ,                   C     qD  B                ,   ,                   B     @XD  B               \,   ,                   B     ?D  B               ,   ,                   pB      'D  B               Ԣ,   ,                   A     D  B               h$   $                   C  B               0   0                 $           	                  Begin   P@   @                 0   0     ?          A C  D쪘D                                               0   0                 $   THC    Bl5C
                  Count   0   0                 $         =lC	                  Reset   T(   (                 0  BTVB	               `0   0                 $     HC  `<I
                  Current Begin   0   0                 $   GC  p3
Ď
                  Current End 0   0                 $         p|y]	                  Begin Control   X0   0                 $    ȗ#v9C	               	   Max Count   0   0                 $         ¼~x6	                  End Control (   (                 T  2N                   MaxCount       x       <(   (                    ~`iB=               0   0                 $     B  >myCN_GB
                  Pulse   h , (                                                                                             h   (   (                      D   B	                  Gate    h8   8                 @   $   $     ?        #4B                          Rising Edge Detector    ,   ,                      >  C  B
               Ȩ,   ,                   pB      C  B	               L4   4                 $   $     ?        +}ᣝC                   T,   ,                      >  C  B
               ,   ,                   pB      C  B	               4   4                 $   $     ?        yDsC                                   ,  B(                               8    C  tB                   End    Count       	   Count<End    (   (                 <   L`_                   MaxCount       x          floor(x*MaxCount+0.999)
    p8   8                    $   $     ?        YDGD            &                                                                                  Begin-End Counter + Direction   (   (                    GDPuD                  7   (   (                    DC?               ,   ,                   pCPAaۖDnC
               ج,   ,                    A   A DR+D	               ,   ,                    A   B DD	               D                       C  zC        ?            ô  8 Step Sequencer Module - v1.0

— — — 


- Controls - 

x8 sliders - Modulation level value for each step 1-8.

Begin knob - Sets the beginning point of the sequence.

<<—>> knob - Sets the direction of the sequencer. When turned all the way up, the sequencer will move from beginning (green) to end (red). When turned all the way down, the sequencer will move from end (red) to beginning (green). When set anywhere in between, the direction has a chance to move backwards or forwards. At 50% there is an equal chance to move backwards or forwards with each step.

End knob - Sets the ending point of the sequence.


- Inputs -


x8 M - Modulation inputs for each step 1-8.

M - Modulation input for the Begin knob.

M - Modulation input for the <<—>> knob.

M - Modulation input for the End knob.

S - Sync input resets to the step set by the Begin knob on rising edge.

G - Gate input to advance sequencer by 1 step each pulse.


- Outputs - 

M - Modulation output


— — — 


The 8-Step Sequencer module outputs a sequence of 8 discrete modulation values. These modulation values can be translated into an Octave signal to become notes or used as modulation to control parameters of another module.

Every time the module is clocked at the gate input, the sequencer advances forward one step. The <<—>> (Direction) knob sets the direction of the sequence. The sequencer can run forwards or backwards or have a random bias towards forwards or backwards. For example, if the knob is set to 90%, then for approximately 1 out of every 10 steps the sequencer will run backwards instead of forwards.

The Begin and End knobs can be set to any step. If the Direction knob is turned all the way up and the Begin knob is at step 8 and the End knob at step 1, then effectively the sequencer will run in reverse.

When gated at the sync input, the sequencer will always reset to the current Begin step.


— — — 

Version History

1.0 - 2022.08.23 - Created                6                                                      $  (  )  -  3  4  5  9  ?  @  A  E  K  L  M  Q  W  X  Y  ]  c  d  e  i  o  p  q  u  {     8-Step Sequencer                       Y~D                      b      a      x       p                @   Y~D                      b      a      x          mix(x*x, a, b)  ,   ,                 ,mC   d'^=D                  This ensures that poly signal is mixed before entering the reverb. Reverbs are heavy enough without replicating them across n poly channels...  <(   (                 (        B                x          x < 0.5 ? x : (((x-.5))*.25)+.5 (   (                 (   Zê	                x          mix(x, .35, .91)     (   (                 (   N5eù                x          mix(x, .11, .34)    h 4 0 (                 $                                                                         h   0   0                  ;D  C   /9N               
  
dec = 6 -- decimal places

save()
translate{0,canvas_height-10}
text_box("DELAY TIMES  samples to secs  32768 to 44100 SR",120, theme.text)
restore()


save()
label = {"lap1", "lap2", "lap3", "lap4", "rap1", "rap2", "rap3", "rap4"}
et = {156,223,332,548,186,253,302,498}
translate{0,canvas_height-80}
text("earl refl allpasses", theme.text)
translate{0,-20}
for i =1, #et do
	save()
		text(label[i], theme.text)
	translate{40,0}
		text(string.format("%0.6f", et[i]/32768), theme.text)
		--text(t[i]/32768, theme.text)
	restore()
	translate{0,-20}
end
restore()


save()
label = {"ap1", "ap1b", "ap2", "ap2b", "ap3", "ap3b", "ap4", "ap4b", "del1", "del2", "del3", "del4", }
ring = {1251,1751,1443,1343,1582,1981,1274,1382, 5859,4145,3476,4568}
translate{0,canvas_height-270}
text("reverb ring", theme.text)
translate{0,-20}
for i = 1, #ring do

	save()
	if i > 8 then translate{0, -10} end
		text(label[i], theme.text)
	translate{40, 0}
		text(string.format("%0.6f", ring[i]/32768), theme.text)
		--text(t[i]/32768, theme.text)
	restore()
	translate{0,-20}
end
restore()

save()
label = {"tapL1", "tapL2", "tapL3", "tapL4", "tapR1", "tapR2", "tapR3", "tapR4"}
taps = {2630, 1943, 3200, 4016, 1163, 3330, 2420, 2631}



-- L/R gains per tap: 1.5, 1.2, 1.0, 0.8
translate{0,canvas_height-560}
text("output taps", theme.text)
translate{0,-20}
for i =1, #taps do
	save()
		text(label[i], theme.text)
	translate{40,0}
		text(string.format("%0.6f", taps[i]/32768), theme.text)
		--text(t[i]/32768, theme.text)
	restore()
	translate{0,-20}
end
restore()  <   <                   A  A(              C  N                  label = "size"

save()
translate {canvas_width/2, canvas_height/2}
scale {.6, .6}
min, max = text_bounds(label)
translate{-(min[1] + max[1])/2, -3}
text(label, theme.text)
restore()

 @   @                 0   0     ?          4B  B                             ,   ,                   4B    ZD2D
               ,   ,                    A
>  C                 0   0                 $              W	                  size    @(   (                 (                       x          mix(x^3, .99999, .5)    (   (                 (                      x          mix(x^2, .98, .38)  (   (                      A                    0.6 <(   (                      pB  4                  -0.6    p 4 0 (                 $                                                                                 p      ,                            O              t  d  T  D  4  $                                 t   d   T   D   4   $            SIZE       Rtap4      Rtap3      Rtap2      Rtap1      Ltap4      Ltap3      Ltap2      Ltap1      d4     d3     d2     d1     ring4b     ring4a     ring3b     ring3a     ring2b     ring2a     ring1b     ring1a     Rap4       Rap3       Rap2       Rap1       Lap4       Lap3       Lap2       Lap1             size        q  -- Delay times in samples for the FV-1 REV1 demo reverb
-- FV-1 sample rate is 32768.


-- Added room size parameter (and a mechanism for minimizing stairstepping since we are using control rate processing)

-- Room size can be adjusted from .25 to 4 times the original delay lengths


early_ap = {156, 223, 332, 548, 186, 253, 302, 498}
ring_ap = {1251, 1751, 1443, 1343, 1582, 1981, 1274, 1382}
ring_del = {5859, 4145, 3476, 4568}
Ltap_del = {2630, 1943, 3200, 4016}
Rtap_del = {1163, 3330, 2420, 2631}

function samplesToSecs(value)
    return value / 32768
end


local STABLE_THRESHOLD = 16
local lastSize = -1 -- Initialize to an impossible number for first run
local stableFrames = 0
local roomSize = 1

function process(frames)
    -- Output ports
    early_out = {Lap1, Lap2, Lap3, Lap4, Rap1, Rap2, Rap3, Rap4}
    ring_ap_out = {ring1a, ring1b, ring2a, ring2b, ring3a, ring3b, ring4a, ring4b}
    ring_del_out = {d1, d2, d3, d4}
    Ltap_out = {Ltap1, Ltap2, Ltap3, Ltap4}
    Rtap_out = {Rtap1, Rtap2, Rtap3, Rtap4}

	-- Minimizes stairstepping for size input
    if size[1] ~= lastSize then
        stableFrames = 0
        lastSize = size[1]
    else
        stableFrames = stableFrames + 1
        if stableFrames >= STABLE_THRESHOLD then
            roomSize = 2^(size[1] * 4 - 2)
        end
    end
    ------------------------------------

    if stableFrames >= STABLE_THRESHOLD then
        for j = 1, 8 do
            fill(early_out[j], samplesToSecs(early_ap[j]) * roomSize)
            fill(ring_ap_out[j], samplesToSecs(ring_ap[j]) * roomSize)
        end
        for j = 1, 4 do
            fill(ring_del_out[j], samplesToSecs(ring_del[j]) * roomSize)
            fill(Ltap_out[j], samplesToSecs(Ltap_del[j]) * roomSize)
            fill(Rtap_out[j], samplesToSecs(Rtap_del[j]) * roomSize)
        end
    end

    -- Debug output to monitor roomSize
    fill(SIZE, roomSize)
end
   (<   <                   A  A4     p  p    E DN                k         translate{5,5}

for i = 0, 3 do
stroke_circle({10,(i/3)*10}, (i/3)*12+3, 1.3, color_paint{.3,.3,.3,1})
end


iter = 8

len = math.floor((k)*(iter-1.001))


for i =0,len do
c = iter-2

stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 4, color_paint{.8,.8,.8,.05})

stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 6, color_paint{.8,.8,.8,.02})

stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 1.5, color_paint{.8,.8,.8,1})
end

translate {0, -15}
--text(len, {1,1,1,1})    8^8   8           0   0     ?          A  C  OC                     )$   $             8B  @ E  mD
               ]                _f?  D @lD               (<   <                    A  A(     pA   B     4C  CN                 
-- jersmi logo

fill_alpha = .1
grayscale = .3


col1 = color_paint{grayscale, grayscale, grayscale,1}
red = color_paint{1, .1, .3, fill_alpha}
green = color_paint{.1, .7, .1, fill_alpha}
blue = color_paint{.3, .6, 1, fill_alpha}
white = color_paint{.8, .8, .8, fill_alpha}

sizeX = 1
sizeY = .75

w = canvas_width
h = canvas_height * sizeY


w0 = canvas_width - canvas_width * sizeX 
w1 = canvas_width * sizeX
W2 = canvas_width/2
H2 = canvas_height/2
c = {w/2, h/2}

hs = h/100*4

-- colored pie slices
save()
stroke_arc({W2,H2}, (h/2 - hs*2.6)/2, h/3, -math.pi/2, math.pi/4, white )
stroke_arc({W2,H2}, (h/2 - hs*2.6)/2, h/3, math.pi, math.pi/4, green )
stroke_arc({W2,H2}, (h/2 - hs*2.6)/2, h/3, math.pi/2, math.pi/4, red )
stroke_arc({W2,H2}, (h/2 - hs*2.6)/2, h/3, 0, math.pi/4, blue )
restore()

save()
stroke_bezier({w0,H2}, {2, H2-.01}, {W2-h/2-hs,H2}, hs, col1)
stroke_bezier({W2+h/2+hs,H2}, {w-2,H2-.01}, {w1,H2}, hs, col1)
stroke_circle({W2,H2}, h/2*1.1, hs*2, col1)
stroke_circle({W2,H2}, h/2 - hs*2.6, hs*2.5, col1)
restore()

-- cross
save()
translate{W2,H2}
rotate(math.pi/4)
g = -hs*2 -- grow or shirnk
stroke_segment({-h/2-g, 0}, {h/2+g, 0}, hs*3, col1)
stroke_segment({0, -h/2-g}, {0, h/2+g}, hs*3, col1)
restore()

 L<   <                   A  A(              C  N                  save()	
translate {canvas_width/2, canvas_height/2}
scale {.6, .6}
min, max = text_bounds("mod")
translate{-(min[1] + max[1])/2, -3}
text("mod", theme.text)
restore()

    @   @                 0   0     ?          pA  B                            ,   ,                   4B    ZD2D
               h 0 , $                                                                                           h   ,   ,                    f=  C                 <@   @                 0   0     ?          9                             ,   ,                   C  %CJlm 
               h 4 0 (                                                                                           h   0   0                 >  WC  %C                  <   <                   HB  HB@     >C  C      N                   m      k       l
  
--[[ add k and m input ports for knob and modulation

knobSize = 2 -- 1 = standard, 2 = large, 3 = mini
-- make Canvas width/height 50x50, 70x70 for large, 25x25 for mini
if knobSize == 1 then ksize = 25 end
if knobSize == 2 then ksize = 35 end
if knobSize == 3 then ksize = 12.5 end

-- Knob modulation: this displays knob modulation for both types of modulation - connecting a cable directly to a knob and/or a modulation port for the knob (with clamping on or off)

-- Audulus colors
white = color_paint {.84, .84, .84, 1}
black = color_paint { .05,.05,.06,1}
module = color_paint{ .11,.11,.11,1}

azure = color_paint {0, 0.83, 1, 1}
azure_dark = color_paint {0, 0.61, 0.73, 1}
azure_bkgd = color_paint {0, 0.06, 0.08, 1}

green = color_paint {0.23, 0.77, 0.33, 1}
green_dark = color_paint {0.15, 0.51, 0.03, 1}
green_bkgd = color_paint {0, 0.08, 0.01, 1}

red = color_paint {1, 0, 0.38, 1}
red_dark = color_paint {0.65, 0, 0.25, 1}
red_bkgd = color_paint {0.11, 0, 0.04, 1}


-- module color circle (a little larger than knob to diminish aliasing when zoomed out)
stroke_circle({ksize,ksize}, ksize-1, 3, module)

-- black circle
stroke_circle({ksize,ksize}, ksize-1, 2, black)

a = math.pi * k
b = math.pi * m

-- when cable is attached directly to the knob (which is internally clamped)
stroke_arc({ksize,ksize}, ksize-1, 2, a-math.pi/2, a, azure)

-- when using the modulation port (clamp = 0 shows full range of modulation)
clamp = 1
if clamp == 1 then c = math.max(math.min(math.pi-a,b), -a) else c = b end

-- change both to some other color (like red) to distinguish port from knob takeover
if m >= 0 then
    mpos = math.max(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2+mpos, mpos, azure)
elseif m < 0 then
    mneg = math.min(0,c)
    stroke_arc({ksize,ksize}, ksize-1, 2.3, 2*a+math.pi/2+mneg, mneg, black)
end

-- highlight current position (using stroke_arc aperture)
stroke_arc({ksize,ksize}, ksize-1, 2, 2*a-math.pi/2, .03, azure)

--]]

function hp()
height = 17.5

translate{12,16}

stroke = .66
for i = 0,4 do
paint = color_paint{.27,.28,.3,1}

ipos = (math.floor(i/4*4.99)/5) * 20
stroke_bezier( {ipos, 0}, {ipos+.01, 8}, {ipos, 8}, stroke, paint)
stroke_bezier( {ipos, 8},{ipos, height}, {ipos+9, height}, stroke, paint)
stroke_bezier( {ipos+9, height}, {26+.01, height-0.01}, {27, height}, stroke, paint)

end


stroke = .76
pos = (math.floor(k*4.99)/5) * 20
paint = color_paint{.83,.83,.83,1}


stroke_bezier( {pos, 0}, {pos+.01, 8}, {pos, 8}, stroke, paint)
stroke_bezier( {pos, 8}, {pos, height}, {pos+9, height}, stroke, paint)
stroke_bezier( {pos+9, height}, {26+.01, height-0.01}, {27, height}, stroke, paint)

end

hp()
    h 8 4 , $                                                                                         h   4   4                    Uf.?  A  HC  4  B               p(   (              A  @        C	               K,   ,                 |5C   d'^[D               3   Audulus poly mix

Combine poly channels into stereo H(   (                    vC>               (   (                   |}=Đ-C                ch      $   $                 bjĠ5CK               $   $                 thD#               ,(   (                    X_\"D>               h(   (                 (   ;D                ch      
   1/sqrt(ch)  $   $                 ܧgDK               $   $                  fc*D#               4   4                 $   $     ?        9X݁                   p(   (                       =               $   $                                   )0   0                      p  @   f	               0*0   0                     p  B   u	                 D   D                   0   0     ?                  B                 l  m  o  p  q  r  *0   0                 x    p     	               ,   ,                   B      z
               L(   (                       =               $   $                                   +0   0                 $     p  @   f	                  mod rate    ,0   0                 $     p  B   u	               	   mod depth   x L   D 8 0 , (                                                                          C                      $ x   H   T   T                 d   @   @     ?               } Bp)
   modulation                 e  f  h  i  j  k     Mod LFO t-0   0                 Dv    p     	               H,   ,                   B      z
               R,   ,                 Y:C   8$C                  early allpass section   tR,   ,                 ND   CqC               5   -------------------- reverb ring --------------------   R,   ,                 p0C     D  HC                  output taps (dispersion)    (   (                   zD,                tap     P(   (                   rD'                tap     (   (                 $   D                  tap        $   $                 D)D               P   $   $                 >ϰD"D                  $   $                 +DD                  $   $                 >ϰD-D               (   (                    tD=               (   (                 (   Dc=                tap        tap*.8  @(   (                 (   Dj                tap        tap*1.2 (   (                 (    D  B                tap        tap*1.5     $   $                 DclBD               X   $   $                 jDLD                  $   $                 ƯD=D               ȳ   $   $                 jDD                (   (                      D  =               (   (                 (   J
Y                x          x* 0.015    L(   (                 T   +DJ               (   (                    +D`$B                  .5  (   (                 t   +0Ĕj                audio       (   (                 ,   +0lC                audio          audio*.5    X,   ,                   C$m      .C                $   $                   A                Ē8   8                      Cm  Ȅ|A  A  B  B               ,50   0                 m         H  B	               X#(   (                     C 	=               #(   (                     _ f=               50   0                 m           \	               d8   8                 ,n  $   $     ?        vWJ)               :  =  @  A  B  C  D  F  G  H  I  J  K  L  4,   ,                   A  A  C  
               p,   ,                     A   <	               (   (                 n    0A  <                   audio      g       \(   (                 n    B  {                   delay      g       d,   ,           $   $     ?          C                >  ?  O$   $                  A  
                P$   $                    	               ,   ,           $   $     ?         4D                ;  <  |P$   $                  A  
               P$   $                    	                                  D               |],   ,                   CHh      .C               x%$   $                   A                8   8                      Ch  Ȅ|A  A  B  B               :0   0                 h         H  B	               4((   (                     C 	=               l((   (                     _ f=               :0   0                  i           \	               h8   8                 Pi  $   $     ?        vWJ               '  *  -  .  /  0  1  3  4  5  6  7  8  9  ,   ,                   A  A  C  
               L,   ,                     A   <	               (   (                 ,i    0A  <                   audio      g       8(   (                 8i    B  {                   delay      g       @,   ,           $   $     ?          C                +  ,  T$   $                  A  
               T$   $                    	               ,   ,           $   $     ?         4D                (  )  XU$   $                  A  
               U$   $                    	               x                   D               Xb,   ,                   Clc      .C               T*$   $                   A                |8   8                      Cd  Ȅ|A  A  B  B               >0   0                 d         H  B	               -(   (                     C 	=               H-(   (                     _ f=               ?0   0                 $d           \	               m8   8                 td  $   $     ?        vWÔj                                !  "  #  $  %  &  ,   ,                   A  A  C  
               (,   ,                     A   <	               (   (                 Pd    0A  <                   audio      g       (   (                 \d    B  {                   delay      g       ,   ,           $   $     ?          C                    Y$   $                  A  
               Y$   $                    	               ̛,   ,           $   $     ?         4D                    4Z$   $                  A  
               hZ$   $                    	               T                   D               4g,   ,                   C^   b XC               0/$   $                   A                X8   8                      C4_  Ȅ|A  A B XC               C0   0                 <_         B  d	               1(   (                      C  =               $2(   (                     D B=               pD0   0                 H_           i	               r8   8                 _  $   $     ?        vWÔj                       	  
                  ,   ,                   A  A  C  
               ,   ,                     A d C	               (   (                 t_    #C  PB                   audio      g       (   (                 _   4 C E                   delay      g       ,   ,           $   $     ?         C                     `^$   $                  A  
               ^$   $                    	               ,   ,           $   $     ?         <D                    _$   $                  A  
               D_$   $                    	               0                   D               l,   ,                   CY      .C               4$   $                   A                48   8                      CXZ  Ȅ|A  A  B  B               H0   0                 `Z         H  B	               6(   (                     C 	=                7(   (                     _ f=               LI0   0                 lZ           \	               tw8   8                 Z  $   $     ?        vW(                                            ,   ,                   A  A  C  
               ,   ,                     A   <	               x(   (                 Z    0A  <                   audio      g       (   (                 Z    B  {                   delay      g       Ԥ,   ,           $   $     ?          C                    <c$   $                  A  
               pc$   $                    	               ,   ,           $   $     ?         4D                    c$   $                  A  
                d$   $                    	                                  D               p,   ,                   CT      .C               8$   $                   A                8   8                      C|U  Ȅ|A  A  B  B               xM0   0                 U         H  B	               ;(   (                     C 	=               ;(   (                     _ f=               (N0   0                 U           \	               P|8   8                 U  $   $     ?        vWàT                                           ,   ,                   A  A  C  
               ,   ,                     A   <	               T(   (                 U    0A  <                   audio      g       (   (                 U    B  {                   delay      g       ,   ,           $   $     ?          C                    h$   $                  A  
               Lh$   $                    	               `,   ,           $   $     ?         4D                    h$   $                  A  
               h$   $                    	                                  D               u,   ,                   CO      .C               =$   $                   A                8   8                      CP  Ȅ|A  A  B  B               TR0   0                 P         H  B	               @(   (                     C 	=               @(   (                     _ f=               S0   0                 P           \	               ,8   8                 Q  $   $     ?        vWðUB                                           \,   ,                   A  A  C  
               ,   ,                     A   <	               0(   (                 P    0A  <                   audio      g       (   (                 P    B  {                   delay      g       ,   ,           $   $     ?          C                    l$   $                  A  
               (m$   $                    	               <,   ,           $   $     ?         4D                    m$   $                  A  
               m$   $                    	               Į                   D               z,   ,                   C K   b XC               B$   $                   A                ȴ8   8                      CK  Ȅ|A  A B XC               0W0   0                 K         B  d	               \E(   (                      C  =               E(   (                     D B=               W0   0                 K           i	               8   8                 (L  $   $     ?        vW*IC                                           8,   ,                   A  A  C  
               t,   ,                     A d C	               (   (                 L    #C  PB                   audio      g       `(   (                 L   4 C E                   delay      g       h,   ,           $   $     ?         C                     q$   $                  A  
               r$   $                    	               ,   ,           $   $     ?         <D                    r$   $                  A  
               r$   $                    	                                  D               ,   ,                 C   5n               Y  Customizations
Added parameters for size and modulation.

Size adjuasts the original delay lengths from 1/4 to 4 times. Original specs at center position.
Modulation "smears" ap1 and ap3 in the reverb ring. Here we add a second modulation oscillator for a slow/fast approach. The modulation knob increases the amount of, adding more chorusing.

   ,   ,                  C        R                 ;reverb program
;large reverb, stereo in and out
;for mixers, uneven (for vocals)
;pot0=reverb time
;pot1=low freq response
;pot2=high freq response
;
mem	lap1	156
mem	lap2	223
mem	lap3	332
mem	lap4	548
mem	rap1	186
mem	rap2	253
mem	rap3	302
mem	rap4	498
;
mem	ap1	1251
mem	ap1b	1751
mem	ap2	1443
mem	ap2b	1343
mem	ap3	1582
mem	ap3b	1981
mem	ap4	1274
mem	ap4b	1382
;
mem	del1	5859
mem	del2	4145
mem	del3	3476
mem	del4	4568

equ temp		reg0
equ	lpf1		reg1
equ	lpf2		reg2
equ	lpf3		reg3
equ	lpf4		reg4
equ	hpf1		reg5
equ	hpf2		reg6
equ	hpf3		reg7
equ	hpf4		reg8
equ	rt		reg9
equ	hf		reg10
equ	lf		reg11
equ	lapout	reg12
equ	rapout	reg13

;set up lfo, 0.5Hz, +/-20 samples:
skp		run,	loop
wlds		sin0,	12,	160

loop:
;smear 2 allpass filters in reverb ring:

cho 		rda,	sin0,	0x06,	ap1+50
cho		rda,	sin0,	0,	ap1+51
wra		ap1+100,	0
cho 		rda,	sin0,	0x07,	ap3+50
cho		rda,	sin0,	1,	ap3+51	
wra		ap3+100,	0

;prepare pots for control:
rdax	POT0,	1.0
sof 	0.8, 	0.1
wrax	rt,	0	;rt ranges 0.1 to 0.9
;
;shelving controls are negative:
rdax	POT1,	1.0
sof		0.8, 	-0.8
wrax 	hf, 0	;hf ranges -0.8 to 0
;
rdax	POT2,	1.0
sof 	0.8,	-0.8
wrax 	lf,0	;lf ranges -0.8 to 0
;
;get inputs and process with three APs each
;
rdax	adcl,	0.5		
rda		lap1#,	-0.5	
wrap	lap1,	0.5		
rda		lap2#,	-0.5	
wrap	lap2,	0.5		
rda		lap3#,	-0.5	
wrap	lap3,	0.5		
rda		lap4#,	-0.5	
wrap	lap4,	0.5		
wrax	lapout,	0		
;
rdax	adcr,	0.5		
rda		rap1#,	-0.5	
wrap	rap1,	0.5		
rda		rap2#,	-0.5	
wrap	rap2,	0.5		
rda		rap3#,	-0.5	
wrap	rap3,	0.5		
rda		rap4#,	-0.5	
wrap	rap4,	0.5		
wrax	rapout,	0		
;
;now do reverb ring, use temp as temp reg for filtering:
;
;delay ap into 1:
rda		del4#,	1.0	;read previous delay	
mulx		rt			;multiply by reverb time coefficient
rdax		lapout,	1.0	;read left input from input allpass filter bank
rda		ap1#,	-0.6	;do an allpass filter
wrap	ap1,		0.6
rda		ap1b#,	-0.6	;do second all pass filter
wrap	ap1b,		0.6	
wrax	temp,	1.0	;write to temp, keep in acc	
rdfx		lpf1,		0.5	
wrhx	lpf1,		-1.0	;filter done
mulx		lf			;scale by lf
rdax		temp,	1.0	;add to temp
wrax	temp,	1.0	;write to temp again
rdfx		hpf1,	0.05	
wrlx		hpf1,	-1.0		;filter done
mulx		hf			;scale by hf
rdax		temp,	1.0	;add temp
wra		del1,	0.0		;write to next delay
;
;delay ap into 2:
rda		del1#,	1.0		
mulx		rt
rda		ap2#,	-0.6	
wrap	ap2,	0.6		
rda		ap2b#,	-0.6	
wrap	ap2b,	0.6		
wrax	temp,	1.0		
rdfx		lpf2,	0.5		
wrhx	lpf2,	-1.0	
mulx		hf
rdax		temp,	1.0		
wrax	temp,	1.0		
rdfx		hpf2,	0.05	
wrlx		hpf2,	-1.0	
mulx		lf
rdax		temp,	1.0		
wra		del2,	0.0		
;
;delay ap into 3:
rda		del2#,	1.0		
mulx		rt
rdax		rapout,	1.0		
rda		ap3#,	-0.6	
wrap	ap3,	0.6		
rda		ap3b#,	-0.6	
wrap	ap3b,	0.6		
wrax	temp,	1.0		
rdfx		lpf3,	0.5		
wrhx	lpf3,	-1.0	
mulx		hf
rdax		temp,	1.0		
wrax	temp,	1.0		
rdfx		hpf3,	0.05	
wrlx		hpf3,	-1.0	
mulx		lf
rdax		temp,	1.0		
wra		del3,	0.0
;
;delay ap into 4:
rda		del3#,	1.0		
mulx		rt
rda		ap4#,	-0.6	
wrap	ap4,	0.6		
rda		ap4b#,	-0.6	
wrap	ap4b,	0.6		
wrax	temp,	1.0		
rdfx		lpf4,	0.5		
wrhx	lpf4,	-1.0	
mulx		hf
rdax		temp,	1.0		
wrax	temp,	1.0		
rdfx		hpf4,	0.05	
wrlx		hpf4,	-1.0	
mulx		lf
rdax		temp,	1.0		
wra		del4,	0.0		
;
rda		del1+2630,	1.5	;sum outputs as taps from reverb ring
rda		del2+1943,	1.2	
rda		del3+3200,	1.0	
rda		del4+4016,	0.8	
wrax	dacl,	0.0	
;		
rda		del3+1163,	1.5	
rda		del4+3330,	1.2	
rda		del1+2420,	1.0	
rda		del2+2631,	0.8	
wrax	dacr,	0.0	
; 8   8                   $   $     ?          C  C            V                      *  =  P  c  k  l  m  n  }                                                  2  E  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _  `  a  b  c  d  g  n  s  t  u  v  w  x  y  z  {  |                     REV 1   l0   0                         A  C  B	               l0   0                 $     C  BEБC
                  outL    <m0   0                 $         *Cn5D	                  inL m0   0                 $     C  B EmC
                  outR    m0   0                 $         B4DB	                  decay   n0   0                         BD6D	               \n0   0                 $        Cr]&D	                  inR n0   0                          HB  C   B	               n0   0                 $          Bʸ0C	                  mod ,o0   0                 $           H  	                  hp cut  xo0   0                 $         @  R  	                  lp cut   t                     D  4          (               sx1    B      cx1    A       t                L     D            (               sx1    B      cx1    A          (A*cx1+B*sx1)   t                (     D                  x          cos(x*pi/2) @u                (     D                   x          sin(x*pi/2) 0q0   0                 $         A  C  9	                  revL    |q0   0                 $           C  H	                  revR    q0   0                 x    B  A  D   
               r0   0                 $         HB  C   	                  dryR    Tr0   0                 $     B  \B  D  
                  L   r0   0                 $         B  C  	                  dryL    Р8   8                 d   $   $     ?        DmC                                         
   Stereo mix  xs0   0                 $         B  C	                  mix 0(   (                 (   WDB                x          x*.8+.1 a(   (                    bvD>               4b(   (                    bvDs>               lb(   (                    bvDs>               b(   (                    bvD>               D(   (           $       p  B @
                  3-4 $   $               p   	               (   (           $          B 

                  2-3 h$   $                   		               ,(   (           $         A 
                  1-2 ܍$   $                   	               ,   ,           $   $     ?        qC1a                               h , (                                                                                              h   (   (           $           A  
                  4-1 $   $                   	               L$   $              p  B @
               $   $               p   	               $   $                 B 

               $   $                   		               $   $                A 
               P$   $                   	               d,   ,           $   $     ?        dC6L                               $   $                 A  
               $   $                    	               L$   $              p  B @
               $   $               p   	               $   $                 B 

               $   $                   		               $   $                A 
               P$   $                   	               d,   ,           $   $     ?        KDAM               {  |  ~            $   $                 A  
               $   $                    	               9,   ,                   HB    C 
               X9,   ,                        4C  	               g$   $                   C  .                h$   $                   C  /               9,   ,                   HB    D  
               8:,   ,                        HC  u	               h$   $                   C .                i$   $                   C  u/               :,   ,                   HB    D  W
               ;,   ,                        HC  >	               i$   $                   C  \.               i$   $                   C  >/               X   $   $                 #ADqD                  $   $                 ?DD                  $   $                 ?DD               p , (                                                                                                     p      $   $                 ?DD               ,   ,                   C "      .C               k$   $                   A                8   8                      C"  Ȅ|A  A  B  B               00   0                 "         H  B	               \n(   (                     C 	=               n(   (                     _ f=               0   0                 "           \	               8   8                 (#  $   $     ?          C                X  [  ^  _  `  a  b  d  e  f  g  h  i  j  8?,   ,                   A  A  C  
               t?,   ,                     A   <	               ?(   (                 #    0A  <                   audio      g       `?(   (                 #    B  {                   delay      g       h,   ,           $   $     ?          C                \  ]  К$   $                  A  
               $   $                    	               ,   ,           $   $     ?         4D                Y  Z  $   $                  A  
               $   $                    	                                   D               ,   ,                   CD      .C               |p$   $                   A                8   8                      C  Ȅ|A  A  B  B               0   0                          H  B	               8s(   (                     C 	=               ps(   (                     _ f=               0   0                            \	               8   8                 L  $   $     ?          C                 E  H  K  L  M  N  O  Q  R  S  T  U  V  W  D,   ,                   A  A  C  
               PD,   ,                     A   <	               C(   (                 (    0A  <                   audio      g       <D(   (                 4    B  {                   delay      g       D,   ,           $   $     ?          C                I  J  $   $                  A  
               $   $                    	               ,   ,           $   $     ?         4D                F  G  \$   $                  A  
               $   $                    	               |                    D               \,   ,                   Ch      .C               Xu$   $                   A                8   8                      C  Ȅ|A  A  B  B               0   0                          H  B	               x(   (                     C 	=               Lx(   (                     _ f=               0   0                             \	               8   8                 p  $   $     ?          C  f               2  5  8  9  :  ;  <  >  ?  @  A  B  C  D  H,   ,                   A  A  C  
               ,I,   ,                     A   <	               H(   (                 L    0A  <                   audio      g       I(   (                 X    B  {                   delay      g        ,   ,           $   $     ?          C                6  7  $   $                  A  
               $   $                    	               ,   ,           $   $     ?         4D                3  4  8$   $                  A  
               l$   $                    	               X                    D               8,   ,                   C      .C               4z$   $                   A                \8   8                      C0  Ȅ|A  A  B  B               Ď0   0                 8         H  B	               |(   (                     C 	=               (}(   (                     _ f=               t0   0                 D           \	               8   8                   $   $     ?          C                    "  %  &  '  (  )  +  ,  -  .  /  0  1  M,   ,                   A  A  C  
               N,   ,                     A   <	               M(   (                 p    0A  <                   audio      g       M(   (                 |    B  {                   delay      g       ,   ,           $   $     ?          C                #  $  d$   $                  A  
               $   $                    	               ,   ,           $   $     ?         4D                   !  $   $                  A  
               H$   $                    	               4                    D               ,   ,                   C      .C               $   $                   A                88   8                      CT  Ȅ|A  A  B  B               0   0                 \         H  B	               ́(   (                     C 	=               (   (                     _ f=               P0   0                 h           \	               x8   8                   $   $     ?        ZC                                           R,   ,                   A  A  C  
               R,   ,                     A   <	               |R(   (                     0A  <                   audio      g       R(   (                     B  {                   delay      g       ,   ,           $   $     ?          C                    @$   $                  A  
               t$   $                    	               ,   ,           $   $     ?         4D                    $   $                  A  
               $$   $                    	                                   D               ,   ,                   C	      .C               $   $                   A                8   8                      Cx
  Ȅ|A  A  B  B               |0   0                 
         H  B	               (   (                     C 	=               (   (                     _ f=               ,0   0                 
           \	               T8   8                 
  $   $     ?        ZCVm                                         	  
    W,   ,                   A  A  C  
               W,   ,                     A   <	               XW(   (                 
    0A  <                   audio      g       W(   (                 
    B  {                   delay      g       ,   ,           $   $     ?          C                      $   $                  A  
               P$   $                    	               d,   ,           $   $     ?         4D                      ̳$   $                  A  
                $   $                    	                                   D               ,   ,                   C      .C               Ȉ$   $                   A                8   8                      C  Ȅ|A  A  B  B               X0   0                          H  B	               (   (                     C 	=               (   (                     _ f=               0   0                            \	               08   8                    $   $     ?          pC  \                                                         `\,   ,                   A  A  C  
               \,   ,                     A   <	               4\(   (                     0A  <                   audio      g       \(   (                     B  {                   delay      g       ,   ,           $   $     ?          C                      $   $                  A  
               ,$   $                    	               @,   ,           $   $     ?         4D                      $   $                  A  
               ܸ$   $                    	                                   D               ,   ,                   C    b XC               /   y[n] = (-g * x[n]) + x[n - d] + (g * y[n - d])  ؍$   $                   A                h < 8 0 (               $                                                                         h   8   8                      C$   Ȅ|A  A B XC                  -|+ آ0   0                 $          B  d	                  gain    (   (                      C  =               H(   (                     D B=               0   0                 $            i	                  time    8   8                 h   $   $     ?        ZCj                                                            Allpass b,   ,                   A  A  C  
               @b,   ,                     A d C	               a(   (                 8     #C  PB                   audio      g          g*audio 8b(   (                 8    4 C E                   delay      g          -g*delay    P,   ,           $   $     ?         C                       $   $                  A  
               $   $                    	               x 0   (                                                                                                           x   ,   ,           $   $     ?         <D                      $   $                  A  
               $   $                    	               p $                                                                                                        p                       D               h 8 4 , $                                                                                         h   4   4                   B$        B  C                    1-pole filters
LPF/HPF  x H   @ 4 , ( $                                                                         ?                         x   D   D                    0   0     ?           >   DL                              o  p  q  r  s  t  u  v  w  x  y  z             1p LP/HP    g,   ,                   HB  \  D   
               g,   ,                      \  HC  	               $   $                  C  $.               $   $                   C /               (   (                    {	AVm=               $(   (                    A@UI@=               <   <                   B   A@     4B         C  BN                   R      L       #  
-- Audio meter LED lights. Go to the bottom and use either function, ledRGB or ledHSV.


-- HSV to RGB
function hsv(h,s,v)
	
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    
    return r,g,b

end

-- smoothstep
local function smoothstep(edge0, edge1, x)

	if x <= edge0 then return 0 end
	if x > edge1 then return 1 end

-- Scale/bias into [0..1] range
   x = (x - edge0) / (edge1 - edge0)

   return x * x * (3 - 2 * x)

end

-- Audio meter using RGB
local function ledRGB(audio, y)
	r = smoothstep(.4,1,audio)
	g = smoothstep(.0001,.005,audio)*(1-smoothstep(.8,1.05,audio))
	b = math.sin(math.min(audio,.1)*10*math.pi)^.5

fill_circle({5,y}, 5, color_paint{r,g,b,1})
fill_circle({5,y}, 9, color_paint{r,g,b,.2})
end

-- Audio meter using HSV
local function ledHSV(audio, y)
	
	h = .7-smoothstep(0,1,audio)*.7
	s = 1
	v = audio^.5*.9+.1
	
	local r,g,b = hsv(h,s,v)
	
	fill_circle({5,y}, 5, color_paint{r,g,b,1})
	fill_circle({5,y}, 9, color_paint{r,g,b,.2})
end


-- second parameter sets y position of the led

ledHSV(math.abs(L), 30)
ledHSV(math.abs(R), 5)

--ledRGB(math.abs(L), 35)
--ledRGB(math.abs(R), 5) <   <                   A  A4     p  p    E DN                k       9  translate{5,5}

for i = 0, 3 do
--stroke_circle({10,(i/3)*10}, (i/3)*12+3, 1, color_paint{.3,.3,.3,1})
end
c = (1-k)*.5+.3
stroke_circle({10,14}, 10, 2, color_paint{c,c,c,1})

iter = 8

len = math.floor((k)*(iter-1.001))


for i =0,6 do
c = iter-2
c1 = 1-i/6*.7+.1
stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 4, color_paint{c1,c1,c1,k*.1})
stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 6, color_paint{c1,c1,c1,k*.05})
stroke_circle({10,(c-i/c)*10-(c-1)*10},12-(12*i/c)+3, 1.5, color_paint{c1,c1,c1,k*.6})
end

translate {0, -15}
--text(len, {1,1,1,1})   x <   4 (                                                                      3       2                          x   8   8           0   0     ?          A  C       C                        ($   $             8B  @ E  mD
               h $                                                                                                h                   ӣ>  D @lD               D(   (             HB  @     C  HC
               |(   (             HB  A     C  C
               \0   0             ?C(     A  \B     HC  C                  FV-1    h , (                                                                                              h   (   (              A  A        C	               x D   <   0 , (                                                                ;                                $ x   @   
  
            C  pB<
  	  	    ?             HD  	  # FV-1 Reverb

## REV1 

Demo reverb algorithm for the FV-1 effecs chip, from the Spin Semiconductor website.  
***

## Controls
Mix — dry/wet reverb mix.
Decay — controls the feedback of the delay lines in the reverb loop.
LP — low pass filter cutoff. Darkens the tone and decreases the density of the reverb. 
HP — high pass filter cutoff. Brightens the tone and decreases the density of the reverb.  
Modulation — adds a bit of chorus swirl. The mod knob controls both depth and rate of modulation.
Size — set the delay lengths from 1/4 to 4 times. Center position outputs the delay lengths from the original algorithm.

## Ports
Audio input (mono)
L/R outputs (“fake stereo” — the mono input is sent through the reverb and output taps from different points are sent to L/R to create stereo depth).


### Notes
Delay times, etc., are based on the REV1 example reverb in the FV-1 archives. The structure demonstrates Keith Barr’s iconic “allpass loop” template described in Spin Semiconductor’s documentation on “reverberation”.  
http://www.spinsemi.com/knowledge_base/effects.html#Reverberation

Who was Keith Barr?  
Keith Barr designed some hugely popular reverb hardware units in the 1990’s. He worked for Alesis and prior to that MXR. He was instrumental in designing the Alesis MidiVerb and QuadraVerb. He went on to found Spin Semiconductor, responsible for the FV-1 audio effects chip, used in a long list of hardware effects units.

There are two noteworthy modifications to original FV-1 algorithm: modulation and size.  
Modulation “smears” two of the allpass delay lines to create some chorusing. Here we just add a knob to parameterize it.  
More significant is the addition of the size parameter — a common feature on reverbs, but not for the FV-1, which favored algorithms with locked-in delay times. Size multiplies all delay times within a range of 1/4 to 4x the original delay lengths of the algorithm. 

You will notice that there is a little click when you change the size. The size paramaeter changes at control rate, which means stairstepping. Here we have set it up to only process the change once when the knob changes — otherwise we would add significant overhead to smooth the size change across all the delay lengths.
***

### Version History
2022 for the Audulus 4 release by Jerry Smith  
Feb 2024, REV1 template. DSP node configuration with new size parameter, poly mix input, 350px module layout, markdown description (Jerry Smith)                                      }  ~               Reverb  X$   $                 0DD               ~(   (                      kD  /D                  .99 4@   @                 0   0     ?            \B    D  D               9   :      ,   ,                   B  p`DkC
               Xx4   4                 $   $     ?          D  C                                                   ,   ,                   4B  p4ED
               Ā,   ,                      pD'D	                ,   ,                       4BDD	               <,   ,                   4B  4B4ED
               0   0                 ;        BDD	               ,   ,                       pADD	               ,   ,                   4B  pA4ED
               (   (                    7D8/D                  .05 Ȳ(   (                    ED?                (   (                    E)"D?               8(   (                    UE0AD?               t(   (                 (   DKD                x       
   abs(x)>.98  Ȃ(   (                 8   D*2	D                   phase      x          fract(x+phase)*2-1  4(   (                 (   %CD                x          x/(2*pi)    $   $                 CD%               (   (                 (   >BSD                hz         clamp(hz,0, 20000)  L8   8                   B(     B   B    D  pB                  hz  ,   ,                    B  B  D                   T<   <                    A   AD      A   B     D    N                   hzOn       k         
-- 1/oct or Hz light
 
mode = 0 -- 0 for 1/oct, 1 for hz. disable this to use the input port

-- HSV to RGB
function hsv(h,s,v)
	local kr = (5+(1-h)*6)%6
	local kg = (3+h*6)%6
	local kb = (1+h*6)%6
	local r = v-v*s*math.max(0,math.min(math.min(kr,4-kr),1))
	local g = v-v*s*math.max(0,math.min(math.min(kg,4-kg),1))
	local b = v-v*s*math.max(0,math.min(math.min(kb,4-kb),1))
    return r,g,b
end

local function octLight(input, x, y)
	
	local h=(1-((input+5)/10))*.7 -- color shift per octave
	local s=1 -- saturation always 1
	local v=((input+5)-math.floor(input+5))*.9+.1 -- dark to light per octave
	
	local r,g,b = hsv(h,s,v)
	
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	save()
	translate{x,y}
	fill_circle({0,0},9,color_paint{.05,.05,.05,.18})
	fill_circle({0,0},5,color_paint{.05,.05,.05,1})
	
	fill_circle({0,0},9,halo)
	fill_circle({0,0},5,paint)
	
	if hzOn > 0 then
	label = "hz"
	else 
	label = "O"
	end
	save()
	--translate{canvas_width/2, canvas_height/2}
	min, max = text_bounds(label)
	translate{-(min[1] + max[1])/2, -(min[2] + max[2])/2}
	text(label, theme.text)
	restore()
	restore()
end

local function hzLight(input, x, y)
	
	-- convert Hz to 1/oct
	-- log2(clamp(hz,0.00001,20000)/440)
	hz_clamped = math.max(math.min(input,20000),0.0001)
	oct = math.log(hz_clamped/440, 2)
	
	local h=(1-((oct+5)/10))*.7 -- color shift per octave
	local s=1 -- saturation always 1
	local v=((oct+5)-math.floor(oct+5))*.9+.1 -- dark to light per octave
	
	local r,g,b = hsv(h,s,v)
	
	if input == 0 then r,g,b = 0,0,0 end
	local paint = color_paint{r,g,b,1}
	local halo = color_paint{r,g,b,.18}
	
	save()
	translate{x,y}
	fill_circle({0,0},9,color_paint{0,0,0,.18})
	fill_circle({0,0},5,color_paint{0,0,0,1})
	
	fill_circle({0,0},9,halo)
	fill_circle({0,0},5,paint)
		
	translate{-3.75,-4}
	text("H", theme.text)
	restore()
	
end
	
if mode > 0 then
	hzLight(k, 5, 5)
else
	octLight(k, 5, 5)
end  (   (                    BpbC                  15  ؽ(   (                    _DqD=               $   $                 2D	DL               D$   $                 2D	DL               x(   (                      D   D=               $   $                   D  DL               $   $                   D  *DL               (   (                 (   Dxn]D                x          1-x h(   (                     >D  pD               (   (                 8   2D	D                   thresh     x          x-(1-thresh)    x <   4   , ( $                                                                                                   x   8   8                    $   $     ?          D  C            $   F   K   O   P   Q   U   [   z   {   |   }   ~                                                                              poly colors |0   0                 *    B   D]
               0   0                  ,    B  HBDDǇ
               0   0                 ,    B  A&D}
               <0   0                 H&        A,ī,	               h(   (                    C=               (   (                    C~=               (   (                    e]Cy=               (   (                    l `                  .6  T(   (                    @6                   .576    (   (                    kX2                  .541    D<   <                    BRB(   C FA   wC"	                  Audulus Gray    (4   4                 $   $     ?        ğ                                    0   0                 H  ĀUC."ACIG
               0   0                 P  VC*$BaC
               00   0                 X  ȀUC(-B(CL
               \(   (                    ȕB               (   (                    o͉B               (   (                    t~B               (   (                   ?               <(   (                    SÍB               t(   (                    dþB               (   (                    \B               $   $                  l	L               $   $                 <
cnL               L$   $                 PL               $   $                 ؼ®]L               $   $                 8rL               $   $                 ZL               $   $                 hm|L               P$   $                 XT|L               $   $                 ͅL               (   (                    q^Ĉ@               $   $                 RPYtK               $$   $                 (-jlL               X$   $                 8VL               $   $                 @L               h 0 , $                                                                                           h   ,   ,                 ,B   qCXEC               "   to use audio zero crossing to sync  (   (                 8   gDD                   thresh     x          x/thresh    (8   8                   B(    3B @   @oD                   detect  @   @                 0   0     ?PĀ TB   B  @    D                 .   _   `   a   b   c   r   s   t   u   w   P  Q  R  S  |,   ,                   \B  \vIDoJ
               $0   0                 $     p  ?Cq	                  A   l0   0                     p  \DD	               $   $                 ӁkD               Л(   (                 D    D   D                       y      thresh     x          abs(x)<thresh?y:0   |8   8                   ZC(       A   W÷DD                  amp 4   4                    £?    A H2D               (   (                    +D>               Ĺ<   <                    A   A8      A  B   DN                sync        s  

local function syncLight(input, x, y)
	if input > 0 then
		r,g,b,a = 1,1,0,1
		text_color = {.5,.5,.5,1}
	else
		r,g,b,a = 0,0,0,1
		text_color = theme.text
	end
			
	save()
	translate{x,y}
		fill_circle({0,0}, 5, color_paint{r,g,b,a})
		fill_circle({0,0}, 9, color_paint{r,g,b,a*.25})

	translate{-3.75,-4}
		text("S", text_color)
	restore()
end

syncLight(sync, 5, 5) (   (                 (   TҶQa!D                x          x*10    ܟ,   ,                   pA  B:D )	               0   0                 $       anC;oC	                  sync    (   (                 ,     D  D                audio          -audio  ļ<   <                    A   A4      A   A    D  N                ch1       
-- Audio meter LED lights

channels = 1 -- set canvas node height to 10 for 1 ch, 40 for 2 ch
show_A = 1 -- show the "A" in the light


-- smoothstep
local function smoothstep(edge0, edge1, x)

	if x <= edge0 then return 0 end
	if x > edge1 then return 1 end

-- Scale/bias into [0..1] range
   x = (x - edge0) / (edge1 - edge0)

   return x * x * (3 - 2 * x)

end

-- Audio meter using RGB
local function audioLight(input, x, y)
	
	audio = math.abs(input)
	
	if audio >= 0 and audio <= 1 then
		r = smoothstep(.4,1,input)
		g = math.sin(input*math.pi)
		b = math.sin(input*4*math.pi/2)
		alpha = 1
	elseif audio > 1 then
		r,g,b = 1,0,0
		alpha = audio
	end
	
	--[[ bip
	elseif input <= 0 and input >= -1 then
		r = math.abs(input)*.5
		g = math.sin(math.abs(input)*math.pi)
		b = smoothstep(.4,1,math.abs(input))
		a = 1
	elseif input < -1 then
		r,g,b,a = .5,0,1,math.abs(input)
	end
	--]]
	save()
	translate{x,y}
	fill_circle({0,0}, 5, color_paint{r,g,b,alpha})
	fill_circle({0,0}, 9, color_paint{r,g,b,alpha*.25})

	if show_A == 1 then

		translate{-4.2,-3.5}
		text("A", theme.text)
	end
	restore()
end

if channels == 1 then
audioLight(ch1, 5, 5)
else
audioLight(ch1, 5, 35)
audioLight(ch2, 5, 5)
end    h ( $                                                                                              h   $   $               \  zD OD               8   8                   B(     4        D  HC                  feedback    4   4                      ?      D  B               d(   (                 (     D  B                x          x^.3    (   (                    zC                  .991    $   $                 E;DP/               ($   $                 ^0DZF               h , (                                                                                             h   (   (                    $:/DBF               $   $                 n0DQ3               4(   (                   #CG               l(   (                    ,C                  .831    <   <                    BRB(   C FA   wC"	                  Audulus Blue    4   4                 $   $     ?        Ĥ               X   Y   Z   \   ]   ^   0   0                 x  ĀUC."ACIG
               0   0                   VC*$BaC
                0   0                   ȀUC(-B(CL
               0(   (                    kX2                  .839    <   <                    BRB(   C FA   ~CL@                  Audulus White   4   4                 $   $     ?        ޭĸ               R   S   T   V   W   @0   0                   ĀUC."ACIG
               0   0                   VC*$BaC
               0   0                   ȀUC(-B(CL
               (   (                    RֆB               $(   (                    RB               \(   (                    (58B               (   (                    #CG                  0.384   ܬ(   (                    HC                  1   <   <                    BRB(   C FA   [Cp                  Audulus Red d4   4                 $   $     ?        dh               H   I   J   L   M   N   0   0                   ĀUC."ACIG
               (0   0                   VC*$BaC
               h0   0                    ȀUC(-B(CL
               h @ < 4 (               $                                                        3                h   <   <                      B(   C FA   ~S@C                  Audulus Green   L4   4                 $   $     ?        ĵ               @   A   B   C   D   E   G   0   0                 $   ĀUC."ACIG
                  B   0   0                 $   VC*$BaC
                  R   d0   0                 $   ȀUC(-B(CL
                  G   (   (                    PZBGI                  .333    (   (                    ΆBk|                  .769    $(   (                    DBp                  .231    x0   0                 	      C  D  pC
               0   0                       %  D  C
               0   0                 
        D  C
               \8   8                   tB(       H   Z~D\D               
   lissajous
                  (   2D	D                x       	   sin(x*pi)   h < 8 0 $                                                                       /                 h   8   8                    B(          "CkC                  phase   h 8 4 , $                                                                                         h   4   4                    z>     pCC               h 4 0 (                                                                       '                   h   0   0             $B(     4  A   龏wZC                  zoom    (   (                 (   b;aC                x          2^floor(x*2+.5) h 0 , $                                                                                           h   ,   ,              >    AoC               tD   D                    0   0   nU?,4M   9C  B    D  B            -   /   0   1   2   3   4   6   7   8   ;   <   =   >   ?   d   e   f   g   i   j   l   n   o   p   q   x   y                                                            Scope Controls  0   0                 $       C*K^D	                  freq    `0   0                 $       %ö&ëYD	                  audio   0   0                       DD
               0   0                 `      a  D   C
               ,0   0                         D  HD
               X(   (                    2C>               h $                                                                                                h                   (   []D`                Hz      !   log2(clamp(Hz,0.00001,20000)/440)   ,   ,                   pA  4B  D  	               @,   ,                   pA  pA  D  	               <   <                    C  HC8     pB  B   cC$&BN                stroke         

--stroke_segment( {0, 0}, {0,canvas_height}, stroke, color_paint { 0.11, 0.11, 0.12, 1 } ) 
stroke_segment( {canvas_width, 0}, {canvas_width,canvas_height}, stroke, color_paint { 0.11, 0.11, 0.12, 1 } )    0   0                 $     pA  C  C  H	                  b   D   D                   0   0     ?          \  B  HDw            
   #   "   $   %   &   '   (   *   +      0   0                 $     pA  \C  C   	                  y   (0   0                 $     pA  B  C  z	                  p   p0   0                 $     pA  zC  C   A	                  x   0   0                 $     pA  >C  C  	                  r   h 4 0 (                                                                                           h   0   0                 $     pA   C  C  	                  g   P<   <                    C  HC(     pB  B   ԍ9DIBN               O   fill_rect( {0, 0}, {canvas_width,canvas_height}, 0, color_paint(theme.grooves)) h < 8 0 $                                                                       /                 h   8   8                    C  HC  pB  B   Dj>H               x H   @   8 4 0           (                  $                                                                  , x   D   P  P                  C  RCp  4  4  ~X?vO  uD  	  # Scope

***
## Controls
Amplitude - controls the height of the waveform in the scope view.  
Phase - shifts the waveform left/right in the scope view.  
Width - sets the width of the view area.  
Sync - offsets incoming pitch, which will cause the waveform to start moving to the left or right. Center at .5 on the knob.  
Zoom - doubles/quadruples the waveform cycles in the viewer.  
Feedback - effects the persistence input on the scope.  
Thickness - adjusts the thickness of the scope line.  
Lissajous - applies a sine wave to the x-axis instead of a cycling ramp.  
Detect - uses the audio signal to derive pitch for the oscilloscope.  
  
## Ports
O - 1/oct signal for external audio syncing. With no input, Hz = 440. The scope must share the same 1/oct signal as the oscillator to ensure accurate tracking.
A - Input for the audio signal being analyzed.  
S - Send a gate or trigger to sync the scope view. For this to work, sync your audio input signal at the same time.  

***
### Version History
v1.0 - JS March 23, 2023                  )   ,   -   5   h   k   m   v            H     Scope   ,   ,                   A  B  D	               ,   ,                   4B   A  H  D	               (,   ,                         \  D	               (   (                      > D=               (   (                       D                  .999    8$   $                     D/               x H   @ 4 , ( $                                                                 ?       >                         x   D   D                 \   0   0     ?          4B  4B    *  D                                       	   Soft mute   ,   ,                   B       D
               \<   <                   A  A8     p  p       DN                toggle        
if toggle == 0 then
paint = linear_gradient({0,0}, {0,canvas_height}, theme.azureHighlight, theme.azureHighlight)
text_color = theme.azureHighlightBackground
else
paint = color_paint{0,0,0,0}
text_color = theme.text
end

fill_circle({canvas_width/2, canvas_height/2}, 15, paint)


save()
translate{canvas_width/2, 12}
scale{0.8,0.8}
min, max = text_bounds("mute")
translate{-(min[1]+max[1])/2, 0}
text("mute", text_color)
restore()    h 4 0 (                 $                                                                         h   0   @                 @      D   	1DO            output           toggle       ?      -- Toggle with state saving

-- Input: toggle
-- Output: output


local prev_toggle = 0
local readState = false
local changed = false

function process(frames)
	if not readState then
		fill(output, storage[1])
    	readState = true
  	end
  	
  	if toggle[1] > .5 and prev_toggle == 0 then
    	fill(output, 1 - output[1])
    	changed = true
  	end
  	
  	prev_toggle = toggle[1]
  
  	if changed then
    	storage[1] = output[1]
    	changed = false
  	end
end  h , (                                                                                             h   (   8                 <   [x"sDO            output           input       o  
-- Lua DSP. Process some samples!

-- You must define a process function which will process samples.
-- Inputs and outputs are global arrays.
function process(frames)

    -- This simply iterates over the frames, copying
    -- input to output. You'll want to do something
    -- more interesting.
    for i=1,frames do
        output[i] = input[i]
    end

    -- if you need to quickly fill the buffer with a constant
    -- (useful for control-rate signals) do this:
    -- fill(output, value)

    -- if you need memory that is stored in the patch,
    -- use the global storage array:
    -- storage[j] = myValue
end
 $   $                   \ D               (   (                        zD>               h , (                                                                                             h   (   (                        D>                                 zD2               h                                                                                                  h                     D2               h , (                                                                                             h   (   (                         D               h ( $                                                                                             h   $   $                      D               P<   <                   \C   A\    A  B   }SDN                   k      input       ,   ,                    A   A    zD	               D(   (                 `.    z  pD                   level      audio       x D   < 0 ( $                                                                    ;       :                        x   @   @                 0   0   L@~Dy      pA      D               	               
   $,   ,                   A  A  M  D
               l<   <                   pC  A@      A  B     M  DN                   m      k         width = canvas_width
height = canvas_height

-- Inputs: k m
-- Connect slider directly to k. To m port connect clamped slider * modulation.
-- For drawbar type, inverted slider (1-k) before input to Canvas


-- types: 1 = unipolar (standard), 2 = bipolar, 3 = drawbar
type = 1

slider_height = 220
slider_bar_width = 2
indicator_width = 10
indicator_stroke = 2
db_xpos = 14
db_line_start = 12
db_line_end = 16


-- Color is set up for linear gradient
color1 = theme.grooves -- Dark
color2 = theme.azureHighlightDark



-- Draw graphics
save()
translate{10,10}
-- slider circle
--fill_circle( {0, k * slider_height},  9, color_paint{.12, .12, .13, 1})
	
-- background and slider groove
--fill_rect( {-1.5, -0.5}, {1.5, slider_height + 0.5}, 0, color_paint{.12, .12, .13, 1})
--fill_rect( {-1, 0}, {1, slider_height}, 0, color_paint(theme.grooves))
		
slider_color = linear_gradient({0,0}, {0, slider_height}, color1, color2)
--stroke_segment( {0, 0}, {0, (m) * slider_height}, slider_bar_width, slider_color)
			
-- slider circle
--translate{0, (m) * slider_height}
save()
scale{1.5,.75}
--fill_circle( {0, 0},  9, color_paint {.84, .84, .84, .18})
restore()


--stroke_segment( {-indicator_width, m * slider_height}, {indicator_width, m * slider_height}, indicator_stroke, color_paint {.05, .05, .05, 1})

restore()

function triangle(x, y, orient)
	w, h = 7, 5
	if orient == 1 then w = -w else w = w end
	move_to{x, y - h}
	line_to{x + w, y}
	line_to{x, y + h}
	line_to{x, y - h}
	fill(color_paint(theme.text))
end

save()
translate{0,10}
triangle(0, m * slider_height, 0)
triangle(20, m * slider_height, 1)
restore()



-- dB markers for Audulus slider :: Jerry Smith, 2023


-- change these table values as you see fit
-- -300 positions the marker near 0, replaced with "-inf"
db_markers = { -300, -60, -36, -24, -12, -6, 0, 6, 10 }


-- Position of db labels match slider taper x^6 * 3.16
local function db_to_slider_position(db)
        -- dB to linear
        local linear_value = 10.0^(db / 20.0)
        -- invert the taper function
        local adjusted_value = (linear_value / 3.16)^(1/4)
        return adjusted_value * slider_height
    end



width = canvas_width
height = canvas_height



-- Define db labels and positions

function db_slider()
    --slider_height = 110
    
    -- Draw horizontal dB markers and labels
    for i, db in ipairs(db_markers) do
        local y = db_to_slider_position(db)

        -- Draw marker line
        local axy = { db_line_start, y }
        local bxy = { db_line_end, y }
        stroke_segment(axy, bxy, .5, color_paint{.8, .8, .8, .2})

        -- Draw dB label
        save()
        translate{width/2 + db_xpos, y}
        min, max = text_bounds(string.format("%d", db))

        -- Kern dB less than 0
        local shift = db >= 0 and -5 or -6
        translate{shift, -2}
        scale{.75, .75}

        -- Highlight 0 (unity)
        local text_color = db == 0 and {.8, .8, .8, 1} or {.4, .4, .4, 1}

        text_label = string.format("%d", db)
        
        -- replace first table item with "-inf"
        if db == db_markers[1] then
        	text_label = "-inf"
        end
        
        text(text_label, text_color)
        restore()
    end
    
    translate{20,canvas_height-5}
    scale{.75, .75}
    text("db", {.4, .4, .4, 1})
end



translate{10,10}
db_slider()
    8(   (                 8   P6ľlD                   m      slider         clamp((slider+m),0,1)   L,   ,                   A  \BwD	               p 8 4 ,             (                                                                        $           p      0   0                          B#DI              (?    h < 8 0 (           $                                                                             h   8   8                   \C  A      A  BsDM               h @ < 4 (               $                                                       3                 h   <   <                   \C   AD      A  B   K<DN                   k      input       5  -- Audio level meters
-- Jerry Smith :: 2023

-- RMS, peak and current level, in one meter
-- Scaling is sey to match the +10 dB gain slider/knob with a nonlinear taper (level^4 * 3.16)
-- This version is sized to fit inside a standard knob (i.e., 25 px radius)


-- Meter response time will changed based on your device frame rate. This was made assuming 60 fps. To look the same at 120 fps, double the window size, etc.

-- Settings
rmsWindow = 10 -- Frames for RMS averaging
peakWindow = 10 -- Frames for peak hold
peakWindow2 = 120 -- Frames for peak hold (warning light)
levelWindow = 5 -- Frames for level metering


-- Initialization
rmsFrameCount = rmsFrameCount or 0
peakFrameCount = peakFrameCount or 0
peakFrameCount2 = peakFrameCount2 or 0
levelFrameCount = levelFrameCount or 0

currentLevel = currentLevel or 0
rmsSum = rmsSum or 0
maxInput = maxInput or 0
maxInput2 = maxInput2 or 0
currentRMS = currentRMS or 0
currentPeak = currentPeak or 0
currentPeak2 = currentPeak2 or 0



-- RMS, Peak, and Level calculations
-- Assumes input is scaled to +10dB as x^4 * 3.16

-- Make sure value is not nil and clamped at 3.16
inputLevel = math.min(math.abs(input or 0), 3.16)

-- Check for zero level
norm = inputLevel == 0 and 0 or (inputLevel / 3.16)^(1/4)

rmsSum = rmsSum + norm^2
maxInput = math.max(maxInput, norm)
maxInput2 = math.max(maxInput2, norm)

levelFrameCount = levelFrameCount + 1
rmsFrameCount = rmsFrameCount + 1
peakFrameCount = peakFrameCount + 1
peakFrameCount2 = peakFrameCount2 + 1


-- Check for NaN or illegal numbers in RMS
local function safeSqrt(value)
    return value >= 0 and math.sqrt(value) or 0
end

local function safePeak(value)
    return value >= 0 and math.abs(value) or 0
end




function envelope(currentValue, targetValue, rise, fall)
  	  	
    -- Check for NaNs
    if currentValue ~= currentValue then currentValue = 0 end
    if targetValue ~= targetValue then targetValue = 0 end

    local delta = targetValue - currentValue
    if delta > 0 then
        return currentValue + delta * rise
    else
        return currentValue + delta * fall
    end
end


--[[ WIP: rise-hold-fall envelope for more accurate peak hold
holdCount = holdCount or 0

function RHFenv(currentValue, targetValue, rise, fall, hold)
    -- Convert hold time from seconds to frames (assuming 60 Hz frame rate)
    local holdFrames = hold * 60

    -- Check for NaNs
    if currentValue ~= currentValue then currentValue = 0 end
    if targetValue ~= targetValue then targetValue = 0 end

    local delta = targetValue - currentValue
    local envelopeValue = currentValue

    -- Rising
    if delta > 0 then
        envelopeValue = currentValue + delta * rise
        -- Reset holdCount when starting to rise or if target value changes
        if envelopeValue >= targetValue then
            holdCount = 0
        end
    -- Holding or Falling
    elseif delta <= 0 then
        -- If holding, maintain target value
        if holdCount < holdFrames then
            envelopeValue = targetValue
            holdCount = holdCount + 1  -- Increment holdCount
        else
            -- Apply fall rate after hold duration is over
            envelopeValue = currentValue + delta * fall
        end
    end

    return envelopeValue
end
--]]


if rmsFrameCount >= rmsWindow then
    local newRMS = safeSqrt(rmsSum / rmsWindow)
    currentRMS = envelope(currentRMS, newRMS, 0.5, 0.1)
    rmsSum = 0
    rmsFrameCount = 0
end

if peakFrameCount >= peakWindow then
    local newPeak = maxInput
    currentPeak = envelope(currentPeak, newPeak, 1, 0.1)
    maxInput = 0
    peakFrameCount = 0
end


prev_k = prev_k or 0 -- previous slider input

if peakFrameCount2 >= peakWindow2 or k > prev_k then
	if k ~= prev_k then
		peakFrameCount2 = 0
		currentPeak2 = currentPeak
	else	
    	local newPeak2 = currentPeak
    	currentPeak2 = envelope(currentPeak2, newPeak2, 1, 0.05)
    	peakFrameCount2 = 0
    end
    
    prev_k = k
end


if levelFrameCount >= levelWindow then
    currentLevel = envelope(currentLevel, norm, 0.7, 0.2)
    levelFrameCount = 0
end



-- Graphics -----------------------
rms_color1 = {0.231, 0.769, 0.333, 0.5} -- {0.0, 0.831, 1, 0.5}
rms_color2 = {0.231, 0.769, 0.333, 0.9} -- {0.0, 0.831, 1, 0.2}
level_color1 = {0.0, 0.831, 1, 0.2}
level_color2 = {0.0, 0.831, 1, 0.5}


bkgd_color1 = {0.0, 0.03, 0.05, 0.2}
bkgd_color2 = {0.15, 0.02, 0.06, 0.2}


stroke_width = canvas_width - 1


save()
local bkgd_gradient = linear_gradient({0, 0}, {0, canvas_height}, bkgd_color1, bkgd_color2)
stroke_segment({canvas_width/2, 0}, {canvas_width/2, canvas_height}, stroke_width, bkgd_gradient)
restore()

function drawMeter(x, color1, color2)
    local paint = linear_gradient({0, 0}, {0, canvas_height}, color1, color2)
    save()
    translate{canvas_width / 2, 0}
    local minHeight = 0.01 -- minimum height to prevent degeneration
    local meterHeight = math.max(x * canvas_height, minHeight)
    stroke_segment({0, 0}, {0, meterHeight}, stroke_width, paint)
    restore()
end

function drawPeakMeter(x)
    --local paint = linear_gradient({0, canvas_height*.6}, {0, canvas_height*.72}, theme.azureHighlightDark, theme.redHighlight)
    paint = color_paint(theme.text)
    save()
    translate{canvas_width / 2, 0}
    local minHeight = 0.01 -- minimum height to prevent degeneration
    local meterHeight = math.max(x * canvas_height, minHeight)
    stroke_segment({0, meterHeight - 0.5}, {0, meterHeight + 0.5}, stroke_width, paint)
    restore()
end


function smoothstep(edge0, edge1, x)
    local t = math.min(math.max(((x - edge0) / (edge1 - edge0)), 0.0), 1.0)
    return t * t * (3.0 - 2.0 * t)
end

function drawPeakLight(x)	
	if x >= 0.74 then 
		paint = color_paint{1,0,0.384, 1}
	elseif x > 0.5 then 
		alpha = smoothstep(0.5, 0.74, x)
		r = smoothstep(0.5, 0.74, x)
		paint = color_paint{r * 0.6,.9,0, alpha}	
	else 
		paint = color_paint{.08,.08,.08,1}  
	end
	
	local meterHeight = 6
    local inset = 0.5
    --local paint = color_paint{1,0,0.384, alpha}
    save()
    translate{canvas_width/2, canvas_height}   
    fill_rect({-canvas_width/2 + inset, inset}, {canvas_width/2 - inset, meterHeight - inset}, 2, color_paint{0,0,0,.3})
    fill_rect({-canvas_width/2 + inset, inset}, {canvas_width/2 - inset, meterHeight - inset}, 2, paint)
    restore()
end

-- Unity marker
--stroke_segment({-2, 0.75 * canvas_height}, {canvas_width, 0.75 * canvas_height}, 0.5, color_paint{0.3, 0.3, 0.3, 0.5})

-- Draw -------------------
drawMeter(currentLevel, level_color1, level_color2)
drawMeter(currentRMS, rms_color1, rms_color2)
drawPeakMeter(currentPeak)
drawPeakLight(currentPeak2)
---------------------------




-- debug -----------------
translate{canvas_width+30, canvas_height}
scale{.6,.6}

-- text_box("RMS: " .. string.format("%.2f", currentRMS) .. "\nPEAK: " .. string.format("%.2f", currentPeak) .. "\nLEVEL: " .. string.format("%.2f", currentLevel), 80, theme.text)
-- text(currentPeak2, theme.text)
   h 0 , $                                                                                           h   ,   ,                    A  B    D	               h , (                                                                                             h   (   (                 <     z  D                   level      audio          audio * level^4 * 3.16  x D   <   0 , (                                                                ;       :                        $ x   @   \  \            C  pB  H  H  4ǐ?XGD_n   ^D    # Audio Output Meters

Audio output to DAC. The meter displays peak, RMS and current level.
***
#### Bar meters
**Current level** -- the signal with the most fluctuation.  
**RMS** -- root mean square, "perceptual level", considered a better representation of the way that humans hear sound. Here this is the more stable and consistent level indicator.  
**Peak** -- the white horizontal line. “Peak hold”. 
**Overload** -- the top light becomes red when the output level exceed unity (0 dB).  

The light gray marker represent unity, 0 dB gain, like on the slider markers.

#### Controls
Volume level slider - tapered level slider in dB, with output up to +10dB. Decibel increments and bar meters are scaled to this taper.

#### Ports
L/R stereo inputs
***
#### Notes
DC blockers are in place to alleviate DC offset before the signal outputs to speakers -- large DC offsets have been known to damage speakers.  
  
The bar meters use your device graphics frame rate for the envelopes used to set RMS and peak hold time. This means that the meters will respond 2x faster on a 120 hz display versus a 60 hz display, etc. This does not effect the accuracy, just the "refresh rate", the envelope times.  
***
#### Version History
15.03.2024 — added mute and modulation ports
Jan 2024 - v2.0 Jerry Smith                                                                         dac x 8   0   ( $                                                                                                     x   4   4                 $   $   3?   HC                          !        |    h      d    )  p      	  I
  
  
  U  X  