With a filter now featured in Ableton 10, Synthcore is an open-source, MIDI-controlled, cross-platform multitimbral synthesizer, with 16 channels feeding 4 parallel effects banks. Direct and arpeggiated notes from the 16 channels can play on any of 48 voices, allowing for example beat sequences, chord pads, and leads to play simultaneously.

Synthcore 2.1b
Synthcore 2.1b

Each channel contains three multi-waveform FM oscillators, two 5d state-variable filters, two comb filters, serial/parallel filter mix with stereo pan, 3 LFOs, 3 envelopes, 40x80x15 modulation matrix, glide/glissando, sequenced arpeggiator, and chord generator. Each channel's stereo output feeds any one of four separate effects banks, each with stereo tempo ping-pong delays, 8x chorus, and reverb. The output passes through a limiting compressor before scope display. The design also includes multiple monitoring modes, 42 modulation indicators, and microtuning.

Synthcore 2.1 patch layout is simple, due to scripting
Synthcore 2.1 patch layout is simple, due to scripting

How it Works

To describe it in a Reaktor paradigm, the event-rate logic is currently in compiled JavaScript, and the audio-rate logic is in compiled win32 and osx binaries. In most cases, the JavaScript performance is comparable to Reaktor event rates, with 1kHz easily obtainable. However, the JavaScript engine drops events if it exceeds the available CPU capacity, and in the Cycling74 paradigm, the JavaScript runs in a low-priority thread, together with screen events. So with single arpeggiator runs of notes less than 1/32nd in duration at 120bpm, it is stable, but at faster rates it currently drops occasional notes every few bars randomly, depending on other system events. Therefore, as the design will support 16 concurrent arpeggiators, the arpeggiation and voice-allocation code, listed below, will be transferring to a C++ linked library external, rather than running in a script.

Asymmetric Concurrent Processing

In the Cycling74 patch, there is one poly~ object containing gen~ code for all the audio-rate calculations. One instance of the poly~ object acts as a control processor, also calculating modulation values to update the display for the currently displayed channel, and playing one of the effects banks. The other poly~ instances play voices and the other effects banks. A low-priority repeating JavaScript taks checks the voices to see if the envelopes have finished from the previous voice, in which case the poly~ instances are muted. Thus a minimum of 4 poly~ instances are unmuted at all times, and others may be unmuted to play additional voices.

The parameters for each channel are stored in a buffer, rather than sent to the gen~ object as params. On note-on events, the poly~ instance unmutes itself and checks to see if the channel for the new note is the same as the channel it last played. If not, it loads the 221 audio parameters into a local data buffer, subsequently using those values until a new note is received or a 'dirty' channel indicator is set. Upon panel changes or MIDI control events, the 'dirty' indicator is set for that channel, resulting in all poly~ instances playing that channel to reload their local data arrays.

The active voices write their results to a cycling data exchange buffe,r twice the length of the DSP block setting, and with twice as many channels as there are voices, (one channel for left, and one for right). The four effects processors first check channel for all voices. When the synth voices are destined for the current effects bank, the effects units sum the left and right values for that voice from the data exhange buffer, reading it one DSP block behind the voice-write index. This is because the shared data buffer can only be written in chunks the size of the DSP block size,

gen~ Code

This is the 'main()' routine in gen~, which uses theSynthcore library, which is available for download on this site:. Currently only one effects bank is implemented, and the 16 channels cannot write or load program data from the programs banks.

Hide LIne Numbers
  1. //***************************************************************************************************MAIN
  2. Buffer adr("adr", 128, 1), 
  3.     pow25("pow25", 16384, 1), 
  4.     eptr("eptr", 16384, 1), 
  5.     svfgain("svfgain", 10201, 6),
  6.     wavesets("wavesets", 1671168), 
  7.     scales("scales", 128, 13), 
  8.     patterns("patterns", 128, 24), 
  9.     graph ("graph", 750000, 1),
  10.     drawbuf1("drawbuf1", 100, 1), 
  11.     drawbuf2("drawbuf2", 100, 1), 
  12.     drawbuf3("drawbuf3", 100, 1), 
  13.     drawbuf4("drawbuf4", 100, 1), 
  14.     drawbuf5("drawbuf5", 100, 1), 
  15.     drawbuf9("drawbuf9", 100, 2), 
  16.     channels("channels", 256, 17), 
  17.     xchange("xchange", 4096, 65);
  18. History dclk, gui, he1a, he2a,
  19.     zp0(60),zp1,    zp2,    zp3,    zf1,    zf2,    zvel1,     hinc1,     he1, 
  20.     henv1,     zvel2,     hinc2,     he2,     henv2,     zgate2, hinc3,     he3,     henv3,    hlfo1,
  21.     hl1sah1,hl1sah2,hlfo2,    hl2sah1,hl2sah2,hlfo3,     hl3sah1,hl3sah2,os1,     os2,     
  22.     os3,     hosc1,     hosc2,     hosc3,     zouta,    zoutb,    zpanal,    zpanar,    zpanbl, zpanbr,
  23.     m1s,    m2s,    m3s,    m4s,    m5s,    m6s,    m7s,    m8s,    m9s,    m10s,    
  24.     m11s,    m12s,    m13s,    m14s,    m15s,    m1d,    m2d,    m3d,    m4d,    m5d,    
  25.     m6d,    m7d,    m8d,    m9d,    m10d,    m11d,    m12d,    m13d,    m14d,    m15d,    
  26.     m1x,    m2x,    m3x,    m4x,    m5x,    m6x,    m7x,    m8x,    m9x,    m10x,    
  27.     m11x,    m12x,    m13x,    m14x,    m15x,    lo1,    lo2,    lo3,    lo4,    lo5,    
  28.     lo6,    lo7,    lo8,    lo9,    lo10,    lo11,    lo12,    lo13,    lo14,    lo15,    
  29.     e1m,    e2m,    e3m,    e1vs,    e2vs,    l1s,     l2s,     l3s,    l1t,    l2t,    
  30.     l3t,    o1snc,    o2snc,    o3snc,    o2ft1,    o2ft3,    o3ft1,    o3ft2,    c1t,    c2t,
  31.     ftrk,    ftrk2,    bend,    wheel,    foot,    sust,    port,    sost,    soft,    hold,
  32.     gtype,    gscale,    gkey,    tempo,    mon,
  33. //    d1m,    d2m,    d1l,    d2l,    d1r,    d2r,    d1p,    d2p,    d1w,    d2w,
  34. //    d1z,    d2z,    d2d,    d2h,    ch1m,    ch1b,    ch1f,    ch1s,    ch1d,    ch1z,    
  35. //    Rmix,    Rpre,    Rcut,    Rdamp,    Rdecay,    limon,     limlvl, limwin, lima,     limr,
  36.     hlastchan(-1),
  37.     t1, t2, t3, t4,
  38.     c0, c1, lahi, lrhi, dl1, dr1, dl2, dr2,
  39.     s1, s2, s3, s4, s5, s6, s7, s8;
  40.  
  41. Data gliss(128),    // glaissando sequence
  42.     d(80),             // local modulated data values
  43.     m(16, 5),         // modulation matrix src, dest, amount, lo, self modulation
  44.     fx(1024);        // fx data for current channel
  45. Param 
  46.     pitch(60), 
  47.     gate, 
  48.     vel, 
  49.     chan, 
  50.     ui, 
  51.     lastv(1),             // for glide
  52.     lastp(60), 
  53.     dspblocksize(2048), // xhange buffer
  54.     vdraw(32),             // drawing voice
  55.     vmax(31);            // # playable voices
  56. gain= 1; pan1= 2; pan2= 3; pmod= 4; o1p = 5; o2p  = 6; o3p = 7; o1s  = 8; o2s  = 9; o3s =10;
  57. o1w =11; o2w =12; o3w =13; tune=14; o1d =15; o2d  =16; o3d =17; o1ph =18; o2ph =19; o3ph=20;
  58. o1f1=21; o2f1=22; o2f3=23; o3f1=24; o3f2=25; sub  =26; o2am=27; o3am =28; o1m  =29; o2m =30;
  59. o3m =31; o1n =32; o2n =33; o3n =34; c1m =35; c2m  =36; c1d =37; c2d  =38; c1f  =39; c2f =40;
  60. f1u =41; f2u =42; f1t =43; f2t =44; f1p =45; f2p  =46; f1s =47; f2s  =48; f1q  =49; f2q =50;
  61. fmix=51; l1f =52; l2f =53; l3f =54; l1w =55; l2w  =56; l3w =57; e2pre=58; e3pre=59; e1a =60;
  62. e2a =61; e3a =62; e1d1=63; e2d1=64; e3d =65; e1b  =66; e2b =67; e1d2 =68; e2d2 =69; e1s =70;
  63. e2s =71; e3s =72; e1r =73; e2r =74; e3r =75; gtime=76; gpat=77; gang =78;
  64. d1m  = 0;  d2m  = 1; d1l  = 2; d2l  = 3; d1r  = 4; d2r  = 5;  d1p  = 6; d2p  = 7; d1w  = 8; d2w  = 9;    
  65. d1z  = 10; d2z  =11; d2d  =12; d2h  =13; ch1m =14; ch1b = 15; ch1f =16; ch1s =17; ch1d =18; ch1z =19;
  66. Rmix = 20; Rpre =21; Rcut =22; Rdmp =23; Rdec =24; Limo = 25; Liml =26; Limw =27; Lima =28; Limr =29;
  67.  
  68. out1, out2 = 0;
  69. //running = (henv1 || (vdraw == in11));
  70. trg0    = change(gate);
  71. trg1    = 0;
  72. cdur    = (samplerate * 240) / tempo; //beats per second in samples
  73. cinc    = 1 /cdur;                    // beat accum inc
  74. zclk    = .5 < accum(cinc, trg0, max = 1); 
  75. zv = 0;
  76. // gui     = lastv==in11 && (ui==2 || (ui ==1 && henv1 >0)); 
  77. u, v, w, x, y, z  = 0;
  78. p0, p1, p2, p3 = 60;
  79. x = channels.peek(0,chan);
  80. if (change(x !=0) || hlastchan != chan){
  81.     hlastchan = chan;
  82.     for(i = 1; i <79; i += 1){
  83.         d.poke(channels.peek(i, chan), i);
  84.      }
  85.     for(i = 1; i <16; i += 1){
  86.         m.poke(channels.peek(i + 78, chan), i, 0);//m1s ~m15s
  87.         m.poke(channels.peek(i + 93, chan), i, 1);//m1d ~m15d
  88.         m.poke(channels.peek(i +108, chan), i, 2);//m1x ~m15x
  89.         m.poke(channels.peek(i +123, chan), i, 3);//lo1 ~lo15
  90.         m.poke(1, i, 4);                  //self modulation
  91.     }
  92.     e1m   =channels.peek(139,chan); e2m   =channels.peek(140,chan); e3m   =channels.peek(141,chan); 
  93.     e1vs  =channels.peek(142,chan); e2vs  =channels.peek(143,chan); l1t   =channels.peek(144,chan); 
  94.     l2t   =channels.peek(145,chan); l3t   =channels.peek(146,chan); l1s   =channels.peek(147,chan);
  95.     l2s   =channels.peek(148,chan); l3s   =channels.peek(149,chan); o1snc =channels.peek(150,chan);
  96.     o2snc =channels.peek(151,chan); o3snc =channels.peek(152,chan); bend  =channels.peek(153,chan);
  97.     wheel =channels.peek(154,chan); foot  =channels.peek(155,chan); sust  =channels.peek(156,chan);
  98.     port  =channels.peek(157,chan); sost  =channels.peek(158,chan); soft  =channels.peek(159,chan);
  99.     hold  =channels.peek(160,chan); o2ft1 =channels.peek(161,chan); o2ft3 =channels.peek(162,chan); 
  100.     o3ft1 =channels.peek(163,chan); o3ft2 =channels.peek(164,chan); c1t   =channels.peek(165,chan); 
  101.     c2t   =channels.peek(166,chan); ftrk  =channels.peek(167,chan); ftrk2 =channels.peek(168,chan); 
  102.     gtype =channels.peek(169,chan); gscale=channels.peek(170,chan); gkey  =channels.peek(171,chan);    
  103.     tempo =channels.peek(172,chan); mon   =channels.peek(173,chan); fxchan=channels.peek(223,chan);
  104. }
  105. //-------------------------------------------------------------------------------------triggers and clocks
  106. if((hinc1 >0) || (in11 == vdraw)){    
  107.     for(i=1; i<16; i +=1){                                        // ************************** MATRIX
  108.         x = m.peek(i,1); // get dest
  109.         if(x>0){          // if modulated, restore from program buffer
  110.             d.poke(channels.peek(x, chan), x);
  111.         }
  112.     }
  113.     for(i=1; i<16; i +=1){
  114.         w = m.peek(i, 0);             // src 
  115.         x = m.peek(i, 1);             // dest
  116.         y = m.peek(i, 2);             // amount
  117.         if (w != 0 && x != 0 && y !=0){
  118.             y *= m.peek(i, 4);        // self modulation
  119.             m.poke(1, i, 4);
  120.             if (m.peek(i, 3) ==1){     //gang
  121.                 y *= d.peek(gang);
  122.             }
  123.             y *= selector(w,        
  124.                 clip(zp0 *.01-.1, 0, 100), 
  125.                 zp1 *.01-.1,     zp2 *.01-.1,             zp3*.01-.1,
  126.                    zf1 *.01 -.1,    zf2 *.01 -.1,
  127.                  vel,             zvel1,                    zvel2,
  128.                 henv1,              henv2,                    henv3,
  129.                 gate >0,         zgate2 >0, 
  130.                 hlfo1,              hlfo2,                     hlfo3,
  131.                    hlfo1 * henv1,     hlfo2 * henv1,             hlfo3 * henv1,
  132.                  hlfo1 * henv2,     hlfo2 * henv2,             hlfo3 * henv2, 
  133.                 hlfo1 * henv3,     hlfo2 * henv3,             hlfo3 * henv3,
  134.                    hl1sah1,         hl2sah1,                 hl3sah1, 
  135.                 hl1sah2,         hl2sah2,                 hl3sah2, 
  136.                    hlfo1*(gate >0),hlfo2*(gate >0),        hlfo1*(zgate2 >0),        hlfo2 * (zgate2 >0),
  137.                    wheel *.007874, wheel *.007874 * hlfo1, wheel *.007874 * hlfo2, wheel *.007874 * hlfo3,
  138.                 bend *.007874,     foot *.007874,             sust >0,                 soft >0, 
  139.                 hold >0,         port >0,                 sost >0,
  140.                    1, 
  141.                 (x > 0)? x * x *.0001  : x * neg(x) * -.0001, 
  142.                 (x > 0)? (1-x)* -.01 : (1-x)* .01
  143.             );
  144.             if ((in11 == vdraw) && zv == 29){        // render current state if used
  145.                 drawbuf9.poke(y, i); 
  146.             }
  147.             if(x <79){
  148.                 z = d.peek(x);
  149.                 y = selector(x,
  150.                     z + y *.01,                 //1  gain    
  151.                     clip(z + y *.01, 0, 1),        //2  pan1
  152.                     clip(z + y *.01, 0, 1),        //3  pan2
  153.                     z + y,                        //4  pmod
  154.                     z + y,                        //5  o1p
  155.                     z + y,                        //6  o2p
  156.                     z + y,                        //7  o3p
  157.                     wrap(round(z + y, 1, 54)),    //8  o1s
  158.                     wrap(round(z + y, 1, 54)),    //9  o2s
  159.                     wrap(round(z + y, 1, 54)),    //10 o3s
  160.                     clip(z + y, 0, 100),        //11 o1w
  161.                     clip(z + y, 0, 100),        //12 o2w
  162.                     clip(z + y, 0, 100),        //13 o3w
  163.                     z + y *.01,                    //14 tune
  164.                     z + y *.01,                    //15 o1d
  165.                     z + y *.01,                    //16 o2d
  166.                     z + y *.01,                    //17 o3d
  167.                     clip(z + y *.01, 0, 1),        //18 o1ph
  168.                     clip(z + y *.01, 0, 1),        //19 o2ph
  169.                     clip(z + y *.01, 0, 1),        //20 o3ph
  170.                     clip(z + y *.01, 0, .995),    //21 o1f1
  171.                     clip(z + y, 0, 127),        //22 o2f1
  172.                     clip(z + y, 0, 127),        //23 o2f3
  173.                     clip(z + y, 0, 127),         //24 o3f1
  174.                     clip(z + y, 0, 127),        //25 o3f2
  175.                     clip(z + y *.01, 0, 1),        //26 sub
  176.                     clip(z + y *.01, 0, 1),        //27 o2am
  177.                     clip(z + y *.01, 0, 1),        //28 o3am
  178.                     clip(z + y *.01, 0, 1),        //29 o1m
  179.                     clip(z + y *.01, 0, 1),        //30 o2m
  180.                     clip(z + y *.01, 0, 1),        //31 o3m
  181.                     clip(z + y *.01, 0, 1),        //32 o1n
  182.                     clip(z + y *.01, 0, 1),        //33 o2n
  183.                     clip(z + y *.01, 0, 1),        //34 o3n
  184.                     clip(z + y *.01, 0, 1),        //35 c1m
  185.                     clip(z + y *.01, 0, 1),        //36 c2m
  186.                     clip(z + y, 0, 127),        //37 c1d
  187.                     clip(z + y, 0, 127),        //38 c2d
  188.                     clip(z + y *.01, 0, 0.99),    //39 c1f
  189.                     clip(z + y *.01, 0, 0.99),    //40 c2f
  190.                     clip(z + y *.02, -1, 1),    //41 f1u
  191.                     clip(z + y *.02, -1, 1),     //42 f2u
  192.                     clip(z + y *.02, -1, 1),    //43 f1t
  193.                     clip(z + y *.02, -1, 1),    //44 f2t
  194.                     z + y,                        //45 f1p
  195.                     z + y,                        //46 f2p
  196.                     clip(z + y *2, 0, 200),        //47 f1s
  197.                     clip(z + y *2, 0, 200),        //48 f2s
  198.                     clip(z + y, 0, 100),        //49 f1q
  199.                     clip(z + y, 1, 100),        //50 f2q
  200.                     clip(z + y  *.01, 0, 1),    //51 fmix
  201.                     max(z + y * .3, 0),            //52 l1f
  202.                     max(z + y * .3, 0),            //53 l2f
  203.                     max(z + y * .3, 0),            //54 l3f
  204.                     clip(z + y *.01, 0, 1),        //55 l1w
  205.                     clip(z + y *.01, 0, 1),        //56 l2w
  206.                     clip(z + y *.01, 0, 1),        //57 l3w
  207.                     clip(z + y*.01*in1,0,1),    //58 e2pre         to check
  208.                     clip(z + y*.01*in1,0,1),    //59 e3pre
  209.                     clip(z + y, 1, 127),        //60 e1a
  210.                     clip(z + y, 1, 127),        //61 e2a
  211.                     clip(z + y, 1, 127),        //62 e3a
  212.                     clip(z + y, 1, 127),        //63 e1d1
  213.                     clip(z + y, 1, 127),        //64 e2d1
  214.                     clip(z + y, 1, 127),        //65 e3d
  215.                     clip(z + y, 1, 127),        //68 e1d2
  216.                     clip(z + y, 1, 127),        //69 e2d2
  217.                     clip(z + y *.01, 0, 1),        //72 e3s
  218.                     clip(z + y, 1, 127),        //73 e1r
  219.                     clip(z + y, 1, 127),        //74 e2r
  220.                     clip(z + y, 1, 127),        //75 e3r
  221.                     clip(z + y, 1, 127),        //66 e1b
  222.                     clip(z + y, 1, 127),        //67 e2b
  223.                     clip(z + y *.01, 0, 1),        //70 e1s
  224.                     clip(z + y *.01, 0, 1),        //71 e2s
  225.                     clip(z + y *.01, 0, 1),        //76 gtime        to check
  226.                     clip(z + y *.04, 0, 24),    //77 gpat
  227.                     clip(z + y, 0, 1)            //78 gang
  228.                 );
  229.                 d.poke(y, x);
  230.             }else {
  231.                 x -= 78;
  232.                 z  = m.peek(x, 4);
  233.                 m.poke(z + y *.01, x, 4);
  234.             } 
  235.          } else if ((in11 == vdraw) && zv == i){    // render current state if not used
  236.             drawbuf9.poke(0, i); 
  237.         }
  238.  
  239.     }// endfor loop through nodes
  240. }//end env test
  241. //*********************************************************************************** Envelope 1
  242. x = gate(gate,zclk);
  243. y = (e1m >1)? change(x) : trg0;
  244. if (y >0){
  245.     if (henv1){
  246.          x = 1; 
  247.         he1 = henv1;
  248.     }else{
  249.          x = 2;
  250.     }
  251. }else if(y <0){
  252.     x = 6; 
  253.     he1 = he1a;
  254. }else{
  255.     x =selector(hinc1, 
  256.         hinc1 + in2,
  257.          hinc1 + envscale(e1a, d, adr),
  258.          hinc1 + envscale(e1d1, d, adr),
  259.         hinc1 + envscale(e1d2, d, adr),
  260.          (e1m==1)? 2: 5,
  261.          hinc1 + envscale(e1r, d, adr),
  262.         0);
  263. }
  264. if(change(x >=2)){
  265.     trg1    = 1; 
  266.     zp      = pitch;
  267.     zvel1   = (e1vs >1)? vel * e1vs: 1 - e1vs + (vel *e1vs);
  268.     hl1sah1 = hlfo1; hl2sah1 = hlfo2; hl3sah1 = hlfo3;
  269. }
  270. henv1 = selector(x,
  271.     sample(pow25, 1-fract(x)) * he1,
  272.     (e1m==1 && gate>0)?
  273.           sample(pow25, fract(x)) *(1-d.peek(e1s))+d.peek(e1s)
  274.         : sample(pow25, fract(x)),
  275.     sample(pow25, 1-fract(x))       *(1-d.peek(e1b)) +d.peek(e1b), 
  276.     (d.peek(e1b) > d.peek(e1s))? 
  277.           sample(pow25, 1-fract(x)) *(d.peek(e1b) -d.peek(e1s)) +d.peek(e1s)
  278.          : sample(pow25, fract(x))   *(d.peek(e1s) -d.peek(e1b)) +d.peek(e1b),
  279.     d.peek(e1s),
  280.     sample(pow25, 1-fract(x)) * he1,
  281.      0);
  282. he1a = henv1;
  283. henv1 *= zvel1;
  284. hinc1 = x; 
  285. if((hinc1 >0) || (in11 == vdraw)){    // *********************************************************  lfos and other envs
  286.     p0 = glide(pitch,                                                     // **** Glide and pitch calc
  287.                 cdur * d.peek(gtime) * .25, 
  288.                 gscale, gkey, gtype, d.peek(gpat), scales, patterns, gliss)
  289.             + d.peek(pmod) + d.peek(tune);
  290.     zp0 = p0;
  291.     p1 = clip(zp0 + d.peek(o1p) + d.peek(o1d), 20, 131);
  292.     p2 = clip(zp0 + d.peek(o2p) + d.peek(o2d), 20, 131);
  293.     p3 = clip(zp0 + d.peek(o3p) + d.peek(o3d), 20, 131);
  294.     zp1 = p1;
  295.     zp2 = p2;
  296.     zp3 = p3;
  297.     zf1  = clip(zp0 * ftrk + d.peek(f1p), 20, 120); // filter fc in MIDI units;
  298.     zf2  = clip(zp0 * ftrk2 + d.peek(f2p), 20, 120);
  299.     hlfo1 = lfo(d.peek(l1f), l1t, l1s, d.peek(l1w), trg1);        // *******LFOs
  300.     hlfo2 = lfo(d.peek(l2f), l2t, l2s, d.peek(l2w), trg1);
  301.     hlfo3 = lfo(d.peek(l3f), l3t, l3s, d.peek(l3w), trg1);
  302.     y = (e2m >1)? change(gate(gate,zclk)) : trg0;                //******* Envelope 2
  303.     if (y >0) {                                    
  304.  
  305.         if (henv2){
  306.             x = 1; 
  307.             he2 = henv2;
  308.         }else { 
  309.             x = 2; 
  310.         }
  311.     } else if(y <0){ 
  312.         x = 7; 
  313.         zgate2 = 0;
  314.         he2 = he2a;
  315.     }else{
  316.         x =selector(hinc2, 
  317.             hinc2 + in2,
  318.             hinc2 + d.peek(e2pre),
  319.             hinc2 + envscale(e2a,  d, adr), 
  320.             hinc2 + envscale(e2d1, d, adr),
  321.             hinc2 + envscale(e2d2, d, adr),
  322.             (e2m==1)? 3: 6, 
  323.             hinc2 + envscale(e2r,  d, adr),
  324.             0);
  325.     }
  326.     if(change(x >=3)){
  327.         zgate2  = 1; 
  328.         zvel2   = (e2vs >1)? vel * e2vs: 1 - e2vs + (vel *e2vs);
  329.         hl1sah2 = hlfo1;
  330.         hl2sah2 = hlfo2;
  331.         hl3sah2 = hlfo3;
  332.     }
  333.     henv2 = selector(x,
  334.         sample(pow25, 1-fract(x)) * he2,
  335.          0,            
  336.         (e2m==1 && gate>0)?
  337.               sample(pow25, fract(x)) *(1-d.peek(e2s)) +d.peek(e2s)
  338.             : sample(pow25, fract(x)),
  339.         sample (pow25, 1-fract(x))    *(1-d.peek(e2b)) +d.peek(e2b),
  340.         (e2b > e2s)? 
  341.               sample(pow25, 1-fract(x)) *(d.peek(e2b) -d.peek(e2s)) +d.peek(e2s)
  342.              : sample(pow25, fract(x))   *(d.peek(e2s) -d.peek(e2b)) +d.peek(e2b),
  343.         d.peek(e2s), 
  344.         sample(pow25, 1-fract(x)) * he2,
  345.      0);
  346.     hinc2 = x;
  347.     he2a = henv2;
  348.     henv2 *= zvel2;
  349.     y = (e3m >1)? change(gate(gate,zclk)) : trg0;                //******* Envelope 3
  350.     if (y >0) {                                    
  351.         if (henv3)     { x = 1; he3 = henv3;}
  352.         else          { x = 2; }
  353.     } else if(y <0)  { x = 6; he3 = henv3;}
  354.     else x =selector(hinc3, 
  355.         hinc3 + in2,
  356.         hinc3 + d.peek(e3pre),
  357.           hinc3 + envscale(e3a, d, adr),
  358.         hinc3 + envscale(e3d, d, adr),
  359.         (e3m==1)? 2: 5,    
  360.         hinc3 + envscale(e3r, d, adr),
  361.      0);
  362.     if(change(x >=3)){
  363.         hl1sah3 = hlfo1; hl2sah3 = hlfo2; hl3sah3 = hlfo3;
  364.     }
  365.     henv3 = selector(x,
  366.         sample(pow25, 1-fract(x)) * he3, 0,            
  367.         (e3m==1 && gate>0)?
  368.               sample(pow25, fract(x)) *(1 -d.peek(e3s)) + d.peek(e3s)
  369.             : sample(pow25, fract(x)),
  370.         sample(pow25, 1-fract(x))  *(1 -d.peek(e3s)) +d.peek(e3s),
  371.         d.peek(e3s),
  372.          sample(pow25, 1-fract(x)) * he3,
  373.      0);
  374.     hinc3 = x;
  375. }
  376. if((hinc1 >0) && (in11 != vdraw)){    //audio on
  377.     if (change(hosc1 >=0) || change(d.peek(o1s)==0)!=0 ){//************************************* Osc 1
  378.         os1 = d.peek(o1s);
  379.     }
  380.     if (os1 ==0){
  381.         hosc1 = 0;
  382.      } else {
  383.         x = d.peek(o1f1);
  384.         x = (x==0)? 0 : mtof(p1 * x); // osc fb and FM, Hz
  385.          out1 = osc(os1, p1, mtof(p1) + hosc1 * x, d.peek(o1w), d.peek(o1ph), o1snc, trg1, 
  386.             hosc1, hosc2, hosc3, henv2, in1, in4, in5, in6, in8, wavesets, eptr, svfgain);
  387.             // in1, in4, in5, in6, in8 = rsrms, srx3, sr3d3, rsrxpi2, rsr
  388.         hosc1 = out1;
  389.         if (d.peek(sub) >0){                                                //************** subosc
  390.             v = mtof(clip(u -12, 20, 122)) * in8;    //in8 = 1/samplerate
  391.             x = accum(v, max=1);
  392.             out1 += eptrx(x, v, .5, eptr) * d.peek(sub);
  393.         }
  394.     }
  395.     if (change(hosc2 >=0) || change(d.peek(o2s)==0)!=0 ){    //*************** Osc 2
  396.         os2 = d.peek(o2s);
  397.     }
  398.     if (os2 ==0) {
  399.         v    = 0;    hosc2 = 0;
  400.      } else {
  401.         x = d.peek(o2f1) + p0 * o2ft1;
  402.         x = (x==0)? 0 : min(50000, mtof(x));
  403.         y = d.peek(o2f3) + p0 * o2ft3;
  404.         y = (y==0)? 0 : min(50000, mtof(y));
  405.         v = osc(os2, p2, mtof(p2) + x * out1 + y * hosc3, d.peek(o2w), d.peek(o2ph), o2snc, trg1, 
  406.             hosc2, hosc1, hosc3,  henv2, in1, in4, in5, in6, in8, wavesets, eptr, svfgain);
  407.         hosc2 = v;
  408.         z = d.peek(o2am);
  409.         out1   = out1 * (1 -z) + out1 * v * z;    // ring2
  410.     }
  411.     if (change(hosc3 >=0) || change(d.peek(o3s)==0)!=0 ){    //*************** Osc 3
  412.         os3 = d.peek(o3s);
  413.     }
  414.     if (os3 ==0) {
  415.         x    = 0;    hosc3 = 0;
  416.      } else {
  417.         x = d.peek(o3f1) + p0 * o3ft1;
  418.         x = (x==0)? 0 : min(50000, mtof(x));
  419.         y = d.peek(o3f2) + p0 * o3ft2;
  420.         y = (y==0)? 0 : min(50000, mtof(y));
  421.         x   = osc(os3, p3, mtof(p3) + x * out1 + y * v, d.peek(o3w), d.peek(o3ph), o3snc, trg1, 
  422.             hosc3, hosc1, hosc2,  henv2, in1, in4, in5, in6, in8, wavesets, eptr, svfgain);
  423.         hosc3 = x;
  424.         z = d.peek(o3am);
  425.         out1  = out1 * (1 - z) + out1 * x * z;    // ring3
  426.     }
  427.     if(mon==0) out2 = out1;
  428.     else if (mon==1){ out1 = v; out2 = v; }
  429.     else if (mon==2){ out1 = x; out2 = x; }
  430.     else {                                                        //*************** osc mix
  431.         u = d.peek(o1n); w = d.peek(o2n); y = d.peek(o3n);    
  432.         z = u + w + y;
  433.         if(z > 1) {
  434.             z = 1/z; u *= z; w *= z; y *= z;
  435.         }
  436.         out2 = out1 * smoother1(u) + v * smoother1(w) + x * smoother1(y);
  437.         u = d.peek(o1m); w = d.peek(o2m); y = d.peek(o3m);    
  438.         z = u + w + y;
  439.         if(z > 1) {
  440.             z = 1/z; u *= z; w *= z; y *= z;
  441.         }
  442.          out1 = out1 * smoother1(u) + v * smoother1(w) + x * smoother1(y);
  443.     } 
  444.     if (mon >3) {                                                //*************** Comb A
  445.         x = smoother1(d.peek(c1m));//comb mix
  446.         y = 1 - x; 
  447.         x *= .5;
  448.         w = samplerate /mtof(clip(d.peek(c1d) + c1t*zp0, 20,127)); //comb depth
  449.         out1 = out1 * y + comb(out1, w, d.peek(c1f), x) * x;
  450.         x = abs(out1);// saturator, +12dB headroom, o/p never exceeds +24dB
  451.         if (x > 4){
  452.             y    = min((x -4) *.25, 1);
  453.             out1 = y *y *4 *sign(out1) +4;
  454.         }
  455.     } 
  456.     if(mon==4) out2 = out1;
  457.     else if(mon >4){                                                    // ************** Filter A
  458.          out1 = filt(out1, 
  459.             smoother1(d.peek(f1t)), 
  460.             smoother1(d.peek(f1u)), 
  461.             d.peek(f1s), 
  462.             zf1, 
  463.             d.peek(f1q), 
  464.             in3, svfgain);
  465.     }                                    //in3=rsrxpi/3
  466.     if(mon==5) out2 = out1;
  467.     else if(mon >5){                                                    // ************** Comb B
  468.         x = smoother1(d.peek(fmix));
  469.         out2 = mix(out2, out1, x);
  470.         x = smoother1(d.peek(c2m));
  471.         y = 1 - x; 
  472.         x *= .5;
  473.         z = d.peek(c2f);
  474.         w = samplerate /mtof(clip(d.peek(c2d) + c2t*zp0, 20,127));//comb depth
  475.         out2 = out2 * y + comb(out2, w, z, x);
  476.         x = abs(out2);
  477.         if (x > 4){
  478.             y    = min((x -4) *.25, 1);
  479.             out2 = y *y *4 *sign(out2) +4;
  480.         }
  481.     } 
  482.     if(mon==6) out1 = out2;
  483.     else if(mon >6){                                                    // ************* filter B
  484.          out2 = filt(out2, 
  485.             smoother1(d.peek(f2t)), 
  486.             smoother1(d.peek(f2u)), 
  487.             d.peek(f2s), 
  488.             zf2, 
  489.             d.peek(f2q), 
  490.             in3, svfgain);
  491.     }
  492.     if(mon==7) out1 = out2;
  493.     if (change(out1 >=0)!=0) {                                            // ************* output gain and pan
  494.         zouta   = henv1 * d.peek(gain);
  495.         zpanar  = d.peek(pan1);
  496.         zpanal  = 1 - zpanar;
  497.     }
  498.     if (change(out2 >=0)!=0) {
  499.         zoutb   = henv1 * d.peek(gain);
  500.         zpanbr  = d.peek(pan2);
  501.         zpanbl  = 1 - zpanbr;
  502.     } 
  503.     u = out1 * zouta; 
  504.     v = out2 * zoutb;
  505.     out1 = u * zpanal + v * zpanbl;
  506.     out2 = u * zpanar + v * zpanbr;
  507.     out3 = out2;
  508.     xchange.poke(out1, in12, in11);//************************************************* Effect xhange buffer
  509.     xchange.poke(out2, in12, in11 + vmax);
  510.     //if (zv==16){                                    // env stage for muting in channel 2
  511.         drawbuf9.poke(hinc1, in11, 1);
  512.     //}
  513. }else if(in11 != vdraw) { //endif main audio if env1 on
  514.     xchange.poke(0, in12, in11);
  515.     xchange.poke(0, in12, in11 + vmax);
  516.     drawbuf9.poke(0, in11, 1);
  517. }
  518. //---------------------------------------------------------------------------------------------------------
  519. // EFFECTS 
  520. //---------------------------------------------------------------------------------------------------------
  521. out1 = 0;
  522. out2 = 0;
  523. if(in11 == vdraw){
  524.     x = 0;
  525.     if (change(channels.peek(193,vdraw))){
  526.         for (y =0; y <=29; y +=1){
  527.             fx.poke(channels.peek(193 +y, x), y, x);
  528.         }
  529.     }
  530.     x = in12 + dspblocksize;
  531.     buffersize = dspblocksize + dspblocksize;
  532.     if (x > buffersize){
  533.         x -= buffersize;
  534.     }
  535.     y, z = 0;
  536.     for(i=1; i<= vmax; i +=1){    
  537.         if(channels.peek(223, i) == x){
  538.             y += xchange.peek(x, i);
  539.             z += xchange.peek(x, i + vmax);
  540.         }
  541.     }
  542.     c1  = fx.peek(ch1f,x) * in8;            // chorus base delay.        // *****  Effects variables
  543.     c0  = c1 * fx.peek(ch1s,x);    // chorus frequency spread
  544.     lahi = 1 - fx.peek(Lima,x); 
  545.     lrhi = 1 - fx.peek(Limr,x);
  546.     dl1 = cdur / fx.peek(d1l,x);    // samples per delay line
  547.     dr1 = cdur / fx.peek(d1r,x);
  548.     dl2 = cdur / fx.peek(d2l,x);
  549.     dr2 = cdur / fx.peek(d2r,x);
  550.     t1 = train(dl1);
  551.     t2 = train(dr1);
  552.     t3 = train(dl2);
  553.     t4 = train(dr2);
  554.     s1 = parasine(c1);
  555.     s2 = parasine(c1 + c0 * 0.89);// primes closest to 1/8ths
  556.     s3 = parasine(c1 + c0 * 0.79);    
  557.     s4 = parasine(c1 + c0 * 0.61);    
  558.     s5 = parasine(c1 + c0 * 0.50);
  559.     s6 = parasine(c1 + c0 * 0.37);    
  560.     s7 = parasine(c1 + c0 * 0.23);    
  561.     s8 = parasine(c1 + c0 * 0.13);
  562.     if (mon == 9){    //    ************************************************************  Effects
  563.         y, z = ping1(dl1, dr1, fx.peek(0,x), fx.peek(8,x), fx.peek(6,x), fx.peek(10,x), y, z);// can't have peeks in last argument of function
  564.         y, z = ping2(dl2, dr2, fx.peek(d2m,x), fx.peek(d2w,x), fx.peek(d2p,x), fx.peek(d2z,x), 
  565.                         fx.peek(d2d,x), fx.peek(d2h,x), y, z); 
  566.         y, z = chorus(fx.peek(ch1b,x), fx.peek(ch1b,x) * fx.peek(ch1d,x), 
  567.                         fx.peek(ch1f,x) * fx.peek(ch1z,x), fx.peek(ch1m,x), s1, s2, s3, s4, s5, s6, s7, s8, y, z);
  568.         y, z = reverb(fx.peek(Rpre,x), fx.peek(Rcut,x), fx.peek(Rdmp,x), fx.peek(Rdec,x), fx.peek(Rmix,x), y, z);
  569.         y, z = limit(y, z, fx.peek(Limo,x), fx.peek(Limw,x), fx.peek(Liml,x), fx.peek(Lima,x), fx.peek(Limr,x), lahi, lrhi);
  570.     }
  571.     out1 = y;
  572.     out2 = z;//}    
  573. //if(in11 == vdraw){//---------------------------------------------------- Display
  574.     if (change(train(in9))!=0){    // 400Hz drawing clock
  575.              dclk += 1;                                              
  576.         if (dclk > 44) {
  577.             dclk = 1;// counts 0~31 at 25Hz
  578.         }
  579.         zv = dclk;
  580.     }
  581.     x = selector(zv,
  582.           drawbuf9.poke( hlfo1, 16, 0)
  583.         , drawbuf9.poke( hlfo2, 17, 0)
  584.         , drawbuf9.poke( hlfo3, 18, 0)
  585.         , drawbuf9.poke(t1, 19, 0)
  586.         , drawbuf9.poke(t2, 20, 0)
  587.         , drawbuf9.poke(t3, 21, 0)
  588.         , drawbuf9.poke(t4, 22, 0)
  589.         , drawbuf9.poke( zclk,  23, 0) 
  590.         , drawbuf9.poke( henv1, 24, 0)
  591.         , drawbuf9.poke( henv2, 25, 0)
  592.         , drawbuf9.poke( henv3, 26, 0)    
  593.         , drawbuf9.poke( s1 *.5 +.5, 27, 0)
  594.         , drawbuf9.poke( s2 *.5 +.5, 28, 0)
  595.         , drawbuf9.poke( s3 *.5 +.5, 29, 0)
  596.         , drawbuf9.poke( s4 *.5 +.5, 30, 0)
  597.         , drawbuf9.poke( s5 *.5 +.5, 31, 0)
  598.         , drawbuf9.poke( s6 *.5 +.5, 32, 0)
  599.         , drawbuf9.poke( s7 *.5 +.5, 33, 0)
  600.         , drawbuf9.poke( s8 *.5 +.5, 34, 0)
  601.         , drawlfo(l1s, l1w, 35, d, drawbuf9)
  602.         , drawlfo(l2s, l2w, 36, d, drawbuf9)
  603.         , drawlfo(l3s, l3w, 37, d, drawbuf9)
  604.         , drawosc(o1s, o1w, zp1, 38, d, graph, drawbuf3, drawbuf9)
  605.         , drawosc(o2s, o2w, zp2, 39, d, graph, drawbuf4, drawbuf9)
  606.         , drawosc(o3s, o3w, zp3, 40, d, graph, drawbuf5, drawbuf9)
  607.         , drawflt(zf1, f1q, f1s, f1t, f1u, d, graph, drawbuf1)                    // draw flts
  608.         , drawflt(zf2, f2q, f2s, f2t, f2u, d, graph, drawbuf2)
  609.         , 0);
  610.     //if(zv != 0){
  611.         drawbuf9.poke(d.peek(hlfo1),44, 0);
  612.     //}
  613. }

Script

So far the audio path is compiled and the top-level patch is entirely scripted, currently totaling 3,500 lines of code. The prototype for the gen~ code is available on this site as an open-source download. Following is the script for a single program's arpeggiator, and 16-channel multiphony.

Hide LIne Numbers
  1. //-- environment variables
  2. var channels    = new Buffer('channels'); //channels and settings data
  3. var xchange     = new Buffer('xchange');  // buffer for synth->fx data exhange
  4. var drawbuf     = new Buffer('drawbuf9');// display buffer
  5. var buf         = new Buffer('pgms');    // programs buffer
  6. var zdraw        = [];    // panel display history
  7. var lvl            = [];     // level history
  8. var settingsVals= [];    // array of settings vals 
  9. var dspBlckClr  = [];    // zero array to clear xchange buffer;
  10. var homepath    = '\\';    // filepath set as property
  11. var en_init     = 0;     // startup flag
  12. var taskinit    = 0;     // init task placeholder, overwritten by new waiting tasks
  13. var dbg            = 1;     // 0 off, 1 posts, 2 profiles, 3 more posts
  14. var vmax        = 1;     // # poly instances
  15. var vdraw       = 2;    // drawing processor
  16. var polyRdy     = 0;     // startup flag
  17. var zlastv      = 1;     // last voice history
  18. var scopeflag   = 0;     // osc trigger
  19. var t2             = 0;    // tip task object placeholder
  20. var t3             = 0;    // audio start taskj placeholder
  21. outlets            = 7;     // 0=poly~in1 1=poly~in2 2= bpatcher 3=dbg 4=sclk 5=pipe 6=deferlow
  22. //-- note variables
  23. var curChan        = 1;     // current displayed channel
  24. var channel     = [];    // channels for current voices
  25. var    anum        = [];    // # stored notes per channel
  26. var pitch        = [];    // note pitch
  27. var xpitch        = [];    // voice pitch after transposition
  28. var apitch         = new Array(16);    // channel pitch data
  29. var aveloc         = new Array(16);    // channel veloc data
  30. var arpCnt         = [];                // current arp note index
  31. var age            = [];    // voice instance
  32. var chord        = [];    // chord tags
  33. var chordflag     = 1;     // chord tag
  34. var kfix        = [0,0];// kslider duplicate note detector
  35. var maxv        = vmax; // # voices
  36. var numv        = 0;    // # voices on
  37. var lastv        = 1;    // last voice
  38. var pgmflag     = 1;    // dirty indicator SHOULD BE ARRAY
  39. var pgm         = 1;    // prgrams should be array
  40. // audio-based constants and settings
  41. var sr             = 48000;
  42. var srms          = sr * .001; 
  43. var rsr           = 1 / sr; 
  44. var rsrms         = rsr * 1000; 
  45. var blocksize    = 256;
  46. var ichan        = 1;
  47. var ochan        = 1;
  48. var omidien        = 0;
  49. var bsens        = 12;
  50. var ui            = 2;
  51. var tips        = 1;
  52. // object arrays
  53. var sPnl = new Array(20);
  54. var dPnl = new Array(57);
  55. var cPnl = new Array(223);
  56. var settingsParams = [ // setup settings objects
  57. //driver, option, sr, sigvs, iovs, odrive,
  58.     'driver',   'option',  'sr',     'iovs',  'sigvs', 'odrive', // 0-5:  audio driver display settings
  59.     'oport',    'ochan',   'out_en', 'iport', 'ichan', 'in_en',  // 6-11: midi driver settings
  60.     'bsens',      'ui',       'tips',                                  //12-14: other settings 
  61.     'inmidi',   'outmidi',                                         //15-16: midiinfo objects
  62.     'takeover', 'omidi',   'switch', 'switchVal'                 //17-20: other objects
  63. ];
  64. var displayParams = [ // panel display objects
  65.     '0',      'm1b',    'm2b',      'm3b',      'm4b',     'm5b',       'm6b',     'm7b',       'm8b',      'm9b',      // 0-9
  66.     'm10b',      'm11b',    'm12b',      'm13b',      'm14b',     'm15b',   'lfo1',     'lfo2',   'lfo3',      'd1',          //10-19
  67.     'd2',      'd3',        'd4',      'd5',          'env1',     'env2',   'env3',     'ch1',       'ch2',      'ch3',      //20-29
  68.     'ch4',      'ch5',    'ch6',      'ch7',      'ch8',     'l1wave', 'l2wave', 'l3wave', 'o1wave',   'o2wave',  //30-39
  69.     'o3wave', 'f1grph', 'f2grph', 'debugnum', 'splash',  'eptr',   'pow25',  'graph',  'svfgain',  'wavesets',//40-49
  70.     'pgms',   'kslider','kslider2','ezdac',      'tiptxt',     'muter',  'scopes', 'setChan'                             //50-57
  71. ];
  72. var params = [ // panel control objects
  73.     '0',    'gain',    'pan1',    'pan2',    'p0',    'o1p',    'o2p',    'o3p',    'o1s',    'o2s',    //0-9
  74.     'o3s',    'o1w',    'o2w',    'o3w',    'tune',    'o1d',    'o2d',    'o3d',    'o1ph',    'o2ph',    //10-19
  75.     'o3ph',    'o1f1',    'o2f1',    'o2f3',    'o3f1',    'o3f2',    'sub',    'o2am',    'o3am',    'o1m',    //20-29
  76.     'o2m',    'o3m',    'o1n',    'o2n',    'o3n',    'c1m',    'c2m',    'c1d',    'c2d',    'c1f',    //30-39
  77.     'c2f',    'f1u',    'f2u',    'f1t',    'f2t',    'f1p',    'f2p',    'f1s',    'f2s',    'f1q',    //40-49
  78.     'f2q',    'fmix',    'l1f',    'l2f',    'l3f',    'l1w',    'l2w',    'l3w',    'e2pre','e3pre',//50-59
  79.     'e1a',    'e2a',    'e3a',    'e1d1',    'e2d1',    'e3d',    'e1b',    'e2b',    'e1d2',    'e2d2',    //60-69
  80.     'e1s',    'e2s',    'e3s',    'e1r',    'e2r',    'e3r',    'gtime','gpat',    'gang',    'm1s',    //70-79
  81.     'm2s',    'm3s',    'm4s',    'm5s',    'm6s',    'm7s',    'm8s',    'm9s',    'm10s',    'm11s',    //80-89
  82.     'm12s',    'm13s',    'm14s',    'm15s',    'm1d',    'm2d',    'm3d',    'm4d',    'm5d',    'm6d',    //90-99
  83.     'm7d',    'm8d',    'm9d',    'm10d',    'm11d',    'm12d',    'm13d',    'm14d',    'm15d',    'm1x',    //100-109
  84.     'm2x',    'm3x',    'm4x',    'm5x',    'm6x',    'm7x',    'm8x',    'm9x',    'm10x',    'm11x',    //110-119
  85.     'm12x',    'm13x',    'm14x',    'm15x',    'lo1',    'lo2',    'lo3',    'lo4',    'lo5',    'lo6',    //120-129
  86.     'lo7',    'lo8',    'lo9',    'lo10',    'lo11',    'lo12',    'lo13',    'lo14',    'lo15',    'e1m',    //130-139
  87.     'e2m',    'e3m',    'e1vs',    'e2vs',    'l1t',    'l2t',    'l3t',    'l1s',    'l2s',    'l3s',    //140-149
  88.     'o1snc','o2snc','o3snc','bend',    'wheel','foot',    'sust',    'port',    'sost',    'soft',    //150-159
  89.     'hold',    'o2ft1','o2ft3','o3ft1','o3ft2','c1t',    'c2t',    'ftrk',    'ftrk2','gtype',//160-169
  90.     'gscale','gkey','tempo','mon',    'cdm',     'cd1',  'cd2',  'cd3',     'cdx',  'cdy',  //170-179
  91.     'cdz',    'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    'acnt', 'adur', 'arate',//180-189 
  92.     'adot',    'atrp', 'axp',    'd1m',    'd2m',    'd1l',    'd2l',    'd1r',    'd2r',    'd1p',  //190-199
  93.     'd2p',    'd1w',  'd2w',    'd1z',    'd2z',    'd2d',    'd2h',    'ch1m',    'ch1b', 'ch1f', //200-209
  94.     'ch1s',    'ch1d', 'ch1z',    'Rmix',    'Rpre',    'Rcut',    'Rdamp','Rdecay','limon','limlvl',//210-219
  95.     'limwin','lima', 'limr'    //220-222
  96. ];
  97. var cdp1   = [0,
  98. //     4th    5th    Maj    Min    Dim    Aug    Ss2 Ss4    Mj6    Mn6    Mj7    Mn7    Mi7    Dm7    Mj9    Mn9
  99.      5,  7,  4,  3,  3,  4,  2,  5,  4,  3,  4,  3,  3,  4,  4,  3,  
  100.     -7, -5, -8, -9, -9, -8,-10, -7, -8, -9, -8, -9, -9, -8, -8, -9,    //1st inversion
  101.      0,  0, -5, -5, -5, -5, -5,    -5, -5, -5, -5,    -5, -5, -5, -5, -5,    //2nd
  102.      0,  0,  0,  0,  0,  0,  0,  0, -4, -4, -1, -2, -1, -2, -1, -2];//3rd
  103. var cdp2 =[0,
  104.      0,  0,  7,  7,  6,  8,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  
  105.      0,  0, -5, -5, -6, -4, -5, -5, -5, -5, -5, -5, -5, -5, -5,    -5,    //1st inversion
  106.      0,  0, -5, -5, -6, -4, -5, -5, -4, -4, -1, -2, -1, -2,    -1, -2, //2nd
  107.      0,  0,  0,  0,  0,  0,  0,  0,  4,  3,  4,  3,  3,  4,  4,  3];//3rd
  108. var cdp3 =[0,  
  109.      0,  0,  0,  0,  0,  0,  0,  0,  8,  8, 11, 10, 11, 10, 11, 10, 
  110.      0,  0,  0,  0,  0,  0,  0,  0, -4, -4, -1, -2, -1, -2, -1, -2, //1st inversion
  111.      0,  0,  0,  0,  0,  0,  0,  0,  4,  3,  4,  3,  3,  4,  4,  3, //2nd
  112.      0,  0,  0,  0,  0,  0,  0,  0,  7,  7,  7,  7,  7,  7,  7,  7];//3rd
  113.  
  114. //-----------------------------------------------------------------------------
  115. // DEBUG AND CLOSE
  116. //-----------------------------------------------------------------------------
  117. function debugg(x){        //debug metro restarts tasks
  118.     if( dPnl[1] ==  null){
  119.         error('initialized by debug\n');
  120.         if(dbg)post('curChan', curChan, '\n');
  121.         max.sendapppath('hPath');
  122.         if(dbg)post('hPath', hPath, '\n');
  123.         initObjects();
  124.         taskinit = new Task(loadSettings, this);
  125.         taskinit.interval = 2;    //poll every 2 ms
  126.         taskinit.repeat(-1);    // repeat until cancelled
  127.         initPatterns();
  128.         initScales();
  129.         initTips();
  130. //dflt();    //load program
  131.         startTasks();
  132.         setArpState(0);
  133.         setchordflag();
  134.         flush();
  135.         clr();
  136.         startTasks();
  137.     }
  138.     if(x>0 && dbg <=0){
  139.          dbg = 1;
  140.         post('debug enabled\n');
  141.     }else if(x == 0 && dbg==1){
  142.         dbg = 0;
  143.         outlet(3,-1);
  144.         post('debug disabled\n');
  145.     } 
  146. }
  147. //-----------------------------------------------------------------------------
  148. // MENU AND CLOSE
  149. //-----------------------------------------------------------------------------
  150. function mInit(){        //called by load()
  151.     max.sendapppath('hPath');
  152.     var mmenu = this.patcher.getnamed('mmenu');
  153.     mmenu.message(1);
  154.     if(max.isruntime){
  155.         //this.patcher.window('flags','nomenu');// disable main menus
  156.         //this.patcher.window('exec');
  157.     }
  158.     dPnl[44].message('window','flags','nomenu'); //disable splash menus
  159.     dPnl[44].message('window','exec');    
  160. }
  161. function mNewChnSet(){        //called by menu
  162.     for(var chan =1; chan <=16; chan++){
  163.         dflt(chan);
  164.     }
  165. }
  166. function mOpenChns(){        //called by menu
  167. }
  168. function mSaveChns(){        //called by menu
  169. }
  170. function mNewPgm(){        //called by menu
  171.     dflt(curChan);    
  172. }
  173. function mOpenPgms(){        //called by menu
  174. }
  175. function mSavePgms(){        //called by menu
  176. }
  177. function mSettings(){        //called by menu
  178. }
  179. function mHelp(){    //called by menu
  180.     max.launchbrowser('https://www.yofiel.com');
  181. }
  182. function mAbout(){    //called by load and about menu
  183.     dPnl[44].message('front');
  184.     if(dbg)post('splash\n');
  185. }
  186. function close(){    // called by closebang
  187.     var x;
  188.     if(max.isruntime){
  189.         x = hPath;
  190.     }else{
  191.         x= this.patcher.filepath;
  192.     }
  193.     var x = this.patcher.filepath;
  194.     var n = x.lastIndexOf('\\');
  195.     if(n == -1) n = x.lastIndexOf('/');
  196.     x = x.slice(0, n +1);
  197.     buf.send('write', x + 'pgms.wav');
  198.     if(dbg) post ('saved to', x + 'pgms.wav\n'); 
  199.     channels.send('write', x + 'channels.wav');
  200.     if(dbg) post ('saved to', x + 'channels.wav\n'); 
  201. }
  202. //------------------------------------------------------------------------------------
  203. // PROGRAMS AND BANKS
  204. //------------------------------------------------------------------------------------
  205. function recall(pgm){                                    
  206.     var param, val;
  207.     var a = buf.peek(pgm, 0, 222);
  208.     pgmflag++;
  209.     a[0] = pgmflag;
  210.     channels.poke(curChan, 0, a);
  211. //need to know whether program is on any of the channels?
  212.     if(midi_out) pgm_out(pgm);
  213.     //if(dbg)post(a, '\nprogram ',pgm, recalled\n');
  214. }
  215. function store(pgm){                                    
  216.     var a = channels.peek(curChan, 1, 222);
  217.     buf.poke(pgm, 1, a);
  218.     if(dbg)post(pgm,'stored\n');
  219. }
  220. /*function rst(){
  221.     var parm, val;
  222.     for (var i = 1; i <= 223; i++){
  223.         //if(dbg) post('hard default ' + defaults[i] + ' ' + val + ' ' + cPnl[i] + '\n');
  224.         cPnl[i].message(val);
  225.     }
  226. }*/
  227. //-----------------------------------------------------------------------------
  228. // INITIALIZATION
  229. //-----------------------------------------------------------------------------
  230. function load(){ // called by loadbang at top level
  231.     if(dbg) error('LOAD: debug is', dbg,'\n');
  232.     initObjects();
  233.     mInit();
  234.     mAbout();
  235.     xchange.send('format','float32');
  236.     channels.send('format','float32');
  237.     channels.send('read','channels.wav');
  238. mNewChnSet();
  239.     taskinit = new Task(loadSettings, this);
  240.     taskinit.interval = 50;    //poll every 2 ms
  241.     taskinit.repeat(-1);    // repeat until cancelled
  242.     loadFiles();
  243. }
  244. function loadSettings(){    // called by load() as repeating task
  245.     var x = channels.length();
  246.     if(x){
  247.         arguments.callee.task.cancel();        // turn off task repeat
  248.         settingsVals = channels.peek(17,0,15);        // read settings
  249.         if(dbg)post('loadSettings()', settingsVals, '\n');
  250.         dPnl[53].message('stop');                // turn off audio
  251.         sPnl[17].message(0);                // disable adstatus takeover
  252.         sPnl[15].message('controllers');    // set midi input  device list
  253.         sPnl[16].message(-1);                // set midi output device list
  254.         var sVals = [1,1,48000,256,256,0,0,1,0,0,1,0,12,2,1];
  255. /*        if((settingsVals[0] === undefined) ||(settingsVals[0] <= 0)){
  256.             settingsVals[0] = 1;
  257.             channels.poke(17,0,1);    // write settings
  258.             if(dbg)post('loadsettings() DRIVER RESET ',0, settingsVals[0], '\n');
  259.         }
  260.         if((settingsVals[1] === undefined) ||(settingsVals[1] <= 0)){
  261.             settingsVals[1] = 1;
  262.             channels.poke(17,1,1);    // write settings
  263.             if(dbg)post('loadsettings() OPTION RESET ',1, settingsVals[1], '\n');
  264.         }
  265.         for(i = 2; i <15; i++){    
  266.             if ((settingsVals[i] === undefined) ||(settingsVals[i] < 0)){
  267.                 settingsVals[i] = sVals[i];
  268.                 channels.poke(17,i,sVals[i]);    // write settings
  269.                 if(dbg)post('loadsettings() RESET ',i, sVals[i], '\n');
  270.             }
  271.         }
  272. */        settingsVals = sVals;
  273.         for(i = 0; i <15; i++){                // set settings objects
  274.             sPnl[i].message(settingsVals[i]);
  275.         }
  276.         outlet(5,'startaudio');                //send startaudio to deferred queue
  277.     }else{
  278.         if(dbg)post('loadsettings() - waiting\n');
  279.     }
  280. }
  281. function setup(        // called by settings panel changes
  282.         idriver, ioption, iiovs, iodrive){
  283.     var s = [idriver, ioption, iiovs, iodrive];
  284.     if(en_init >0){
  285.         settingsVals[0] = idriver;
  286.         settingsVals[1] = ioption;
  287.         settingsVals[2] = iiovs;
  288.         settingsVals[3] = iodrive;
  289.         en_init     = 0;            // disable audio settings
  290.         outlet(5,'startaudio');        //send audio start to deferred queue
  291.         if(dbg)post('setup() poked', s, '\n');
  292.     }else{
  293.         if(dbg)post('setup() bypassed\n');
  294.     }
  295. }
  296. function startaudio(){
  297.     outlet(5,'startSystem');    // send startsysem to deferred queue
  298.     dPnl[53].message('start');    // start message to ezdac
  299.     if(dbg)post('startaudio\n');
  300. }
  301. function startSystem(){
  302.     setChan(curChan -1); // panel value is 0-based index
  303.     setsr(settingsVals[2]);
  304.     setblocksize(settingsVals[4]);
  305.     dPnl[44].message('wclose');    // close splash window if open
  306.     t3 = new Task(enableSettings, this);
  307.     t3.schedule(199);
  308. //TODO: start arpeggiator
  309.     if(dbg)post('startsystem\n');
  310. }
  311. function enableSettings(){
  312.     en_init    = 1;                // enable settings panel
  313.     if(dbg)post('enableSettings \n');
  314. }
  315. function loadFiles(){
  316.     outlet(0,'patchername','poly.maxpat');
  317.     outlet(0, 'voices', vdraw);
  318.     buf.send('format','float32');
  319.     buf.send('read','pgms.wav');
  320.     dPnl[45].message('read','eptr.wav');    //set up buffers
  321.     dPnl[46].message('read','pow25.wav');
  322.     dPnl[47].message('read','graph.wav');
  323.     dPnl[48].message('read','svfgain.wav');
  324.     dPnl[49].message('read','wavesets.wav');
  325.     taskinit = new Task(startwait,this);    //set up tasks
  326.     taskinit.interval = 2;
  327.     taskinit.repeat(-1);
  328. }
  329. function polyStarted(v){    // called by last instance of poly~ when it loads 
  330.     if(v==vmax +1){
  331.          polyRdy=1;
  332.     }
  333. //    if(dbg)post('polyStarted() \n');
  334. }
  335. function startwait(){        // called by load() 
  336.     var wavesets = new Buffer('wavesets');
  337.     var x = wavesets.length();
  338.     if(x && polyRdy){
  339.         outlet(0, 'target',  0);
  340.         outlet(0, 'vmax',    vmax);
  341.         outlet(0, 'vdraw',   vdraw);
  342.         outlet(0, 'lastv',   1);
  343.         outlet(0, 'ui',      ui);
  344.         buf.poke(1, 0, 1);
  345.         if(dbg)post('startwait(): poly started\n');
  346.         arguments.callee.task.cancel();
  347.         initPatterns();
  348.         initScales();
  349.         initTips();
  350.         flush();
  351.         clr();
  352.         startTasks();
  353.         setArpState(0);
  354.         setchordflag();
  355.     }else{
  356.         if(dbg)post('startwait(): buffer files loading\n');
  357.     }
  358. }
  359. //-----------------------------------------------------------------------------
  360. // PROPERTIES
  361. //-----------------------------------------------------------------------------
  362. function initObjects(){
  363.     var settings = this.patcher.getnamed("settings");
  364.     for(var i=0; i<=20; i++) {
  365.         sPnl[i] = settings.subpatcher().getnamed(settingsParams[i]);
  366.         //if(dbg) post('initsPnl()',i,settingsParams[i],'to sPnl()',sPnl[i],'\n');
  367.     }
  368.     for(var i=1; i<223; i++) {
  369.         cPnl[i] = this.patcher.getnamed(params[i]);
  370.         //if(dbg) post('initControlObjects() param:',i,' ',params[i],' ',cPnl[i],'\n');
  371.     }
  372.     for(var i=1; i<=57; i++) {
  373.         dPnl[i] = this.patcher.getnamed(displayParams[i]);
  374.         //if(dbg) post('initdPnl()',i + '], to',dPnl[i],'\n');
  375.     }
  376.     for(var i=35; i<43; i++){                    //set up scopes
  377.         dPnl[i].message('definepoint',0);
  378.         dPnl[i].message('defineline','lines');
  379.         dPnl[i].message('definethickness',1);
  380.         dPnl[i].message('margins',3,5,1,5);
  381.     }
  382.     for(i=35; i<41; i++){
  383.         dPnl[i].message('definerange',-1,1);        //osc & lfo range
  384.         //dPnl.message('numpoints',50);
  385.     }
  386.     dPnl[41].message('definerange',0,2);            //flt range
  387.     dPnl[42].message('definerange',0,2);
  388.     if(dbg) post('initObjects() complete\n');
  389. }
  390. function setsr(s){                //called by dspstate~ before loadbang and on changes
  391.     if(s==0) return;
  392.     sr       = s;    
  393.     srms  = s * .001;
  394.      rsr   = 1 /s;
  395.     rsrms = rsr * 1000;
  396.     settingsVals[2] = s;
  397.     outlet(3,'calccount', sr /24000);    // scopes; srate /24000
  398.     var adr = new Buffer('adr');            // init envelope buffer
  399.     var a   = [];
  400.     for(var x=0;x<128;x++){
  401.             // 1/(1000*sr*dBtoa(w*70/128 +12))
  402.         a[x] = 1/(srms*Math.pow(1.12202,x*.54687+12)); 
  403.     }
  404.     adr.poke(1, 0, a);
  405.     if (dbg) post('setsr()', s,'\n');
  406. }
  407. function setblocksize(i){
  408.     if(i==0) return;
  409.     sPnl[19].message(0);                // turn off audio
  410.     blocksize = i;
  411.     settingsVals[4] = i;
  412.     outlet(0,'dspblocksize', blocksize);    // send to poly
  413.     outlet(1,'dspbuffersize',blocksize *2);    // send to poly
  414.     dspBlckClr  = [];                        // create 0 array to clear on mute
  415.     for(j = 0; j < blocksize *2; j++){
  416.         dspBlckClr[j] = 0;
  417.     }
  418.     xchange.send('fill', 0)
  419.     for(j = 1; j <= vmax *2; j++){
  420.         xchange.poke(j, 0, dspBlckClr);
  421.     }
  422.     if(dbg)post('setblocksize()', i, '\n');
  423. }
  424. function setoport(i){
  425.     channels.poke(17, 6, i);
  426.     if(dbg) post('setoport():', i, '\n');
  427. }
  428. function setochan(i){ 
  429.     channels.poke(17, 7, i);
  430.     if(omidien >0){
  431.         ochan = i; 
  432.     }
  433.     if(dbg) post('setochan():', i, '\n');
  434. }
  435. function setomidien(i){
  436.     channels.poke(17, 8, i);
  437.     if(i==0){
  438.         ochan = 0;    
  439.     }else{
  440.         var a = channels.peek(17, 7, 1);
  441.         ochan = a[0];
  442.     }    
  443.     if(dbg) post('setomidien():', i, '\n');
  444. }
  445. function setiport(i){
  446.     channels.poke(17, 9, i);
  447.     if(dbg) post('setiport():', i, '\n');
  448. }
  449. function setichan(i){
  450.     channels.poke(17, 10, i);
  451.     ichan = i;
  452.     if(dbg) post('setichan():', i, '\n');
  453. }
  454. function setimidien(i){
  455.     channels.poke(17, 11, i);
  456.     if(dbg) post('setimidien():', i, '\n');
  457. }
  458. function setbsens(i){
  459.     channels.poke(17, 12, i);
  460.     bsens = i;
  461.     if(dbg) post('setbsens():', i, '\n');
  462. } 
  463. function setui(i){
  464.     ui = i;
  465.     settingsVals[13] = i;
  466.     if(i>0){
  467.         for(var j=35; j<39; j++){
  468.             dPnl[j].message('definecolor',1,.37,0,1);        //red
  469.         }
  470.         dPnl[39].message('definecolor', 0.5, 1.0,   0, .77);//osc2 green
  471.         dPnl[40].message('definecolor', 0.9, 0.8, .39, 1.0);//osc3 yellow
  472.         dPnl[41].message('definecolor', 1.0, .37,   0, 1.0);//flt1 red
  473.         dPnl[41].message('refer','drawbuf1');
  474.         dPnl[42].message('definecolor', 0.5, 1.0,   0, .77);//flt2 green
  475.         dPnl[42].message('refer','drawbuf2');
  476.         outlet(3, 1, 'fgcolor', 1, .37, 0,   1);             //scope, red
  477.         outlet(3, 2, 'fgcolor',.5,   1, 0, .77);             //scope, green
  478.         dPnl[55].message(0);                                 //unmute scope display
  479.         outlet(0, 'mute', lastv, 0 );                        //unmute last voice
  480.     }else{
  481.         for(var j=1; j<27; j++){
  482.                 dPnl[j].message('set', 0);
  483.         }
  484.         for(j=35; j<43; i++){
  485.             dPnl[j].message('definecolor',0,0,0,0);
  486.         }
  487.         outlet(3, 'fgcolor', 0,0,0,0); //scopes
  488.         dPnl[55].message(1); //mute scope display
  489.     }
  490.     outlet(0,'ui', i);    //send to audio
  491.     if(dbg) post('setui():', i, '\n');
  492. }
  493. function gettips(){
  494.     return tips;
  495. } 
  496. function settips(i){ 
  497.     tips  = i; 
  498.     channels.poke(17, 14, i);
  499.     if(dbg) post('settips():', i, '\n');
  500. }
  501. function setChan(newChan){// set current channel
  502.     if (en_init==0){
  503.         if(dbg)post('setChan(): bypass\n');
  504.          return;
  505.     }
  506.     curChan = newChan +1;
  507.     var a = channels.peek(curChan, 0, 223);
  508.     for(var i = 1; i <= 222; i++){// LIMITER VALS NOT WORKING
  509.         val   = buf2pnl(i, a[i]); 
  510.         cPnl[i].message('set', val);
  511.         if(i < 10)post('setChan() to cPnl[' +i +']', params[i], '- val in '+ a[i] +', out', val, '\n');
  512.     }
  513.     dPnl[51].message("clear");        // set keyboard notes for curChan
  514.     var b = [];
  515.     var c = [];
  516.     b = channels.peek(curChan, 256, vmax);
  517.     c = channels.peek(curChan, 288, vmax);
  518.     var velon;
  519.     for(var i = 0; i <= vmax; i++){
  520.         velon = c[i];
  521.         //if(dbg)post('setChan() index', i, 'velon:', velon, '\n');
  522.         if(velon){
  523.             dPnl[51].message('set', b[i], velon);
  524.         }
  525.     }
  526.     pgmflag++;
  527.     channels.poke(curChan, 0, pgmflag);// should only do it for voice 32
  528.     if(dbg)post('setChan():', curChan, '\n');
  529.     if(dbg)post('setChan() b', b, '\n');
  530.     if(dbg)post('setChan() c', c, '\n');
  531.     //if(dbg)post('setChan() p', channels.peek(curChan, 256, vmax), '\n');
  532.     //if(dbg)post('setChan() v', channels.peek(curChan, 288, vmax), '\n');
  533. }
  534. //------------------------------------------------------------------------------------
  535. // VOICE SETUP
  536. //------------------------------------------------------------------------------------
  537. function pnlrst(){                                    //force panel redraw
  538.     for (var i = 1; i <= 42; i++){
  539.         zdraw[i] = -200;
  540.     }
  541. }
  542. function setvoices(v){
  543. /*    var x;
  544.     for(i = numv+1; i <=maxv; i++){
  545.         if(pitch[voice[i]]==0 && lvl[voice[i]]>0){
  546.             x = voice[i];
  547.             for(j = i; j < vmax; j++){
  548.                 voice[j] = voice[j+1];
  549.                 pitch[j] = pitch[j+1];
  550.             }
  551.             voice[vmax] = x;
  552.             pitch[vmax] = 0;
  553.         }
  554.     }
  555.     for(i = v+1; i<=maxv; i++){ // NOW turn off playing notes
  556.         if(pitch[voice[i]] >0){
  557.              key(pitch[voice[i]], 0);
  558.         }
  559.     }
  560.     maxv = v;
  561.     outlet(0, 'vmax', v);
  562. */
  563. }
  564. function flush(){    // flush notes
  565.      dPnl[51].message('clear');
  566.      dPnl[52].message('clear');
  567.     //if(ochan) flush_out();
  568.     pnlrst();
  569.     for(var i= 1; i <= vmax; i++){
  570.         lvl[i]    = 7;
  571.         outlet(2, i, 0);
  572.     }
  573.     for(var i= 1; i <= maxv; i++){
  574.         pitch[i]   = 0;
  575.         chord[i]   = 0;
  576.         channel[i] = 0;
  577.         age[i]     = maxv - i +1;
  578.     }
  579. // var x = dPnl[57].getvalueof();
  580.     var x = 3;
  581.     setChan(x);//will add 1 because of pnl contrrol
  582.     lastv = 1;
  583.     outlet(0,'lastv',1);
  584.     for(var chan= 1; chan <= 16; chan++){
  585.         allvoicesoff(chan);
  586.     }
  587. }
  588. function clr(){    // clear saved notes
  589.      dPnl[51].message('clear');
  590.     setChan(0);//will add 1 because of pnl contrrol
  591.     setcnt(0);
  592.     var x = [];
  593.     var y = [];
  594.     for(var i= 0; i <= 32; i++){
  595.         x[i] = 0;
  596.         y[i] = 0;
  597.     }
  598.     for(var chan =0; chan <= 16; chan++){
  599.         apitch[chan] = new Array(vmax);
  600.         aveloc[chan] = new Array(vmax);
  601.         apitch[chan] = x;
  602.         aveloc[chan] = y;
  603.         anum[chan]   = 0;
  604.         arpCnt[chan] = 0;
  605.         channels.poke(chan, 255, x);
  606.         channels.poke(chan, 287, y);
  607.     }
  608.     if(dbg)post('clr() apitch', x, '\n'); 
  609.     if(dbg)post('clr() aveloc', y, '\n'); 
  610. }
  611. //------------------------------------------------------------------------------------
  612. // KEYBOARD AND MIDI NOTES
  613. //------------------------------------------------------------------------------------
  614. function kslide(p, vel){                                        // kslider notes
  615.     if (p ==kfix[0] && vel ==kfix[1])return; // filter dup notes
  616.     kfix[0] = p;
  617.     kfix[1] = vel;
  618.     if (vel>0) vel = 128 - vel;
  619.     var arpOn = channels.peek(curChan, 184, 1);        // arp on
  620.     if(dbg)post('kslide() arpon', arpOn, 'pitch', p, 'vel', vel, 'curChan', curChan, '\n'); 
  621.     playnote(arpOn, p, vel, curChan);
  622.     //note_out(p, vel);
  623. }
  624. function note(p, vel, chan){    // midi notes
  625.     var x = buf.peek(pgm, 184, 1);        // arp on
  626.     dPnl[51].message('set', p, vel);
  627.     var arpOn = channels.peek(chan, 184, 1);        // arp on
  628.     if(dbg)post('note() arp', arpOn, 'pitch', p, 'vel', 128 - vel, 'chan', chan, '\n'); 
  629.     playnote(arpOn, p, vel, chan);
  630. }
  631. function playnote(arpOn, p, vel, chan){
  632.      var y = arpState;
  633.     if(dbg)post('arpState',x,'previously',y,'\n');
  634.     if(arpOn==1 && y ==0){
  635.         allvoicesoff(chan);
  636.         arpState = 1;
  637.     }else if(x==0 && y ==1){
  638.         arpState = 0;
  639.     }
  640.     if(dbg)post('playnote() arp', arpOn, 'pitch', p, 'vel', vel, 'chan', chan, '\n'); 
  641.     if(arpOn==0){ //arp off
  642.         if(vel>0){
  643.             chordson(p, vel, chan);
  644.             storenote(p, vel, chan);
  645.         }else{
  646.              ageoff = chordsoff(p, chan);
  647.             deletenote(ageoff, chan);
  648.         }
  649.     }else{
  650.         if(vel>0){
  651.             storenote(p, vel, chan);
  652.         }else{
  653.             for(var a = numv; a >0; a--){
  654.                 v = age.indexOf(a);
  655.                 if(p == pitch[v] && chan == channel[v]){
  656.                     pitch[v]   = 0;
  657.                     channel[v] = 0;
  658.                     deletenote(a, chan);
  659.                     dPnl[51].message('set', p, 0);
  660.                     if(dbg)post('playnote() age',a,'off\n');
  661.                     return;
  662.                 }
  663.             }
  664.         }
  665.     }
  666. }
  667. function storenote(pon, velon, chan){    //add note to buffer
  668.     var a = anum[chan];
  669.     if(a < vmax) anum[chan] = a +1;
  670.     apitch[chan][a] = pon;
  671.     aveloc[chan][a] = velon;
  672.     channels.poke(chan, 256, apitch[chan]);
  673.     channels.poke(chan, 288, aveloc[chan]);
  674.     if(dbg)post('storenote() pon', pon, 'velon', velon, 'chan', chan, '\n'); 
  675.     if(dbg)post('storenote() anum', anum, '\n'); 
  676.     if(dbg)post('storenote() apitch', channels.peek(chan, 256, vmax), '\n'); 
  677.     if(dbg)post('storenote() aveloc', channels.peek(chan, 288, vmax), '\n'); 
  678.     if(dbg)post('apitch[]',  apitch[chan], '\n');    
  679.     if(dbg)post('aveloc[]',  aveloc[chan],'\n');
  680. }
  681. function deletenote(ageoff, chan){    //remove note from buffer
  682.     var a = anum[chan];
  683.     var b;
  684.     var c;
  685.     var d = 0;
  686.     if(dbg)post('deletenote() age',ageoff,'chan', chan,'\n');
  687.     for(var i = ageoff; i < numv; i++){
  688.         c = aveloc[chan][i];
  689.         if(c){
  690.             b = d + 1;
  691.             apitch[chan][d] = apitch[chan][b];
  692.             aveloc[chan][d] = aveloc[chan][b];
  693.             d++;
  694.         }
  695.     }
  696.     apitch[chan][a] = 0;
  697.     aveloc[chan][a] = 0;
  698.     anum[chan] = a -1;
  699.     channels.poke(chan, 256, apitch[chan]);
  700.     channels.poke(chan, 288, aveloc[chan]);
  701.     if(dbg)post('deletenote() age', ageoff, 'chan', chan, '\n'); 
  702.     if(dbg)post('deletenote() apitch', apitch[chan], '\n'); 
  703.     if(dbg)post('deletenote() aveloc', aveloc[chan], '\n'); 
  704. }
  705. function chordson(pon, velon, chan){                            // kb/midi chords on
  706. //    'gscale','gkey','tempo','mon',    'cdm',             //0-4   - scale, key, tempo, mon, mode
  707. //    'cd1',  'cd2',  'cd3',     'cdx',  'cdy',    'cdz',    //5-10  - chrd velocities and durations
  708. //  'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    //11-16 - chrd enable note, arp
  709. //  'acnt', 'adur', 'arate','adot',    'atrp', 'axp'    //17-22 - arp notes, dur, rate, transpose
  710.     chordflag++;
  711.     var d         = channels.peek(chan, 170, 23);
  712.     var scale     = d[0];
  713.     var key       = d[1];
  714.     var p         = scales(scale, pon + d[22] + key) -key; // d[11] = transpose
  715.     var chrd      = d[4];
  716.     if(dbg)post('scale',scale,'key',key,'transpose',d[22],'chord',chrd,'\n');
  717.     var xp   = (d[11]>0)? cdp1[chrd] :0; // chord enabled
  718.     if(xp !=0){
  719.         voiceon(p + xp, velon *d[5], chordflag, chan);
  720.         xp = cdp2[chrd];
  721.         if(xp !=0){
  722.             voiceon(p + xp, velon *d[6], chordflag, chan);
  723.             xp = cdp3[chrd];
  724.             if(xp !=0)
  725.                 voiceon(p + xp, velon *d[7], chordflag, chan);
  726.         }
  727.     }
  728.     var v =  voiceon(p, velon, chordflag, chan);
  729.     if(pitch[v]!=0) dPnl[51].message('set', pitch[v], 0);
  730.     pitch[v] = pon;
  731.     if(dbg)post('chordson voice',v,'pon',pon,'xp',p,'flag',chrdflag,'chan',chan,'\n');
  732.     if(dbg)post('age[]',     age,    '\n');    
  733.     if(dbg)post('pitch[]',   pitch,  '\n');
  734.     if(dbg)post('chord[]',   chord,  '\n');    
  735.     if(dbg)post('channel[]', channel,'\n');
  736. }
  737. function chordsoff(poff, chan){                                // kb/midi chords off
  738.     var v;
  739.     var flag;
  740.     for(var a = numv; a >0; a--){
  741.         v = age.indexOf(a);
  742.         if(dbg)post('chordsoff age',a,'pitch',poff,'chan', chan, '\n');
  743.         if(poff == pitch[v] && chan == channel[v]){
  744.             dPnl[51].message('set', poff, 0);
  745.             flag = chord[v];
  746.             voiceoff(v, a);
  747.             pitch[v] = 0;
  748.             if(dbg)post('chordsoff voice',v,'flag',flag,'pitch\n');
  749.             for(var b = numv; b > 0; b--){
  750.                 v = age.indexOf(b);
  751.                 if(chord[v] == flag){
  752.                     voiceoff(v, b);
  753.                 }//endif b
  754.             }//endfor b
  755.             return a;
  756.         }//endif a
  757.     }//endfor a
  758. }
  759. //------------------------------------------------------------------------------------
  760. // ARPEGGIATOR
  761. //------------------------------------------------------------------------------------
  762. var arpState = [];
  763. function bang(){
  764.     var i;
  765.     if(anum[curChan] && arpState){
  766.         var chan;
  767.         for (var chan =1; chan <=16; chan++){
  768.             arpCnt    = (arpCnt >= anum[chan])? 1: arpCnt +1;
  769.             arpchordson(apitch[chan][arpCnt], aveloc[chan][arpCnt], chan);
  770.         }
  771.         //if(dbg) post('bangcnt',i,'pitch',apitch[i],'vel',aveloc[i],'numv',numv,'anum',anum[curChan],'\n');    
  772.         if(dbg) outlet(3,aveloc);
  773.     }
  774. }
  775. function arpchordson(pon, velon, chan){        // arp notes
  776. //    'gscale','gkey','tempo','mon',    'cdm',             //0-4   - scale, key, tempo, mon, mode
  777. //    'cd1',  'cd2',  'cd3',     'cdx',  'cdy',    'cdz',    //5-10  - chrd velocities and durations
  778. //  'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    //11-16 - chrd enable note, arp
  779. //  'acnt', 'adur', 'arate','adot',    'atrp', 'axp'    //17-22 - arp notes, dur, rate, transpose
  780.     chordflag++;
  781.     var d     = buf.peek(pgm, 170, 23);
  782.     var dur   = (d[18]*600) /(d[2] *d[19]); //1000*(dur*.01)*(60/tempo)/rate
  783.         dur   = (d[20]>0)? dur *1.5 : dur;
  784.         dur   = (d[21]>0)? dur /3   : dur;
  785.         dur   = Math.max(10, Math.floor(dur));
  786.     var scale = d[0];
  787.     var key   = d[1];
  788. // XP AND RATE NEED SCALING
  789.     var p     = scales(scale, pon + d[22] + key) -key; 
  790.     //if(dbg)post('scale',scale,'key',key,'transpose',d[11],'\n');
  791.     //if(dbg)post('pitch in',pon,'out',p,'\n');
  792.     var chrd  = d[4];                    //chord
  793.     var xp    = (d[12]>0)? cdp1[chrd] : 0; 
  794.     var v, x;
  795.     if (xp !=0){
  796.         x  = p + xp;
  797.         v  = voiceon(x, velon  *d[5], chordflag, chan);
  798.         outlet(5, 'arpchordoff', x, v, chordflag, dur *d[8]);
  799.         //if(dbg)post('arpchords voice',v,'pitch',x,'flag',flag,'dur',dur,'\n');
  800.         xp = cdp2[chrd];
  801.         if(xp !=0){
  802.             x  = p + xp;
  803.             v = voiceon(x, velon  *d[6], chordflag, chan);
  804.             outlet(5, 'arpchordoff', x, v, flag, dur *d[9]);
  805.             //if(dbg)post('arpchords voice',v,'pitch',x,'flag',flag,'dur',dur,'\n');
  806.             xp  = cdp3[chrd];
  807.             if(xp !=0)
  808.                 x  = p + xp;
  809.                 v = voiceon(x, velon  *d[7], chordflag, chan);
  810.                 outlet(5, 'arpchordoff', x, v, flag, dur *d[10]);
  811.                 //if(dbg)post('arpchords voice',v,'pitch',x,'flag',flag,'dur',dur,'\n');
  812.         }
  813.     }
  814.     v  = voiceon(p, velon, chordflag, chan);
  815.     outlet(5, 'arpnoteoff', p, v, chordflag, dur);
  816.     //if(dbg)post('arp voice',v,'pon',pon,'xp',p,'flag',chordflag,'dur',dur,'\n');
  817.     dPnl[52].message('set', p, velon);
  818. }
  819. function arpnoteoff(poff, voff, flag){//arp root note-off from pipe
  820.     if (chord[voff] == flag){ 
  821.         voiceoff(voff, age[voff]);
  822.         dPnl[52].message('set', poff, 0);
  823.         //if(dbg)post('arpnoteoff root voice',voff,'flag',flag,'xp',xp,'\n');
  824.     }
  825. }
  826. function arpchordoff(poff, voff, flag){    //arp chord note-off from pipe
  827.     if (chord[voff] == flag){
  828.         voiceoff(voff, age[voff]);
  829.     }
  830. }
  831. //------------------------------------------------------------------------------------
  832. // VOICE ALLOCATOR
  833. //------------------------------------------------------------------------------------
  834. function voiceon(pon, velon, chrdflag, chan){                        // voice on
  835.     var v = age.indexOf(vmax);
  836.     for(var b = vmax; b >0; b--){
  837.         age[b] ++;
  838.     }
  839.     age[v]   = 1;
  840.     chord[v] = chrdflag;
  841.     channel[v] = chan;
  842.     if(numv < vmax) numv++;
  843.     var velnew = velon * .007874
  844.     outlet(2, v, 1, pon, velnew, chrdflag, chan -1);
  845.      outlet(2, vdraw, 1, pon, velnew, chrdflag, chan -1); // send gate signal to display voice    if(dbg)post('voiceon()',v,'p',pon,'vel',velon *.007874,'flag',chrdflag,'chan',chan,'\n')
  846.     if(dbg)post('numv',numv,'vmax',vmax,'\n')
  847.     return v;
  848. }
  849. function voiceoff(voff, ageoff){                        // voice off
  850.     var b;
  851.     for(var a = numv; a > ageoff; a--){
  852.         b = age.indexOf(a);
  853.         age[b] --;
  854.     }
  855.     age[voff]     = numv;
  856.     channel[voff] = 0;
  857.     chord[voff]   = 0;
  858.     if(dbg)post('voiceoff()',voff,'age',numv,'\n')
  859.     numv --;
  860.     outlet(2, voff, 0);
  861.     outlet(2, vdraw, 0);//send gate signal to display voice
  862. }
  863. function allvoicesoff(chan){                                // all voices off
  864.     var m = vmax +1;
  865.     for(var i=1; i <= vmax; i++){
  866.         if(channel[i] ==chan){
  867.             channel[i] = 0;
  868.             pitch[i]   = 0;
  869.             chord[i]   = 0;
  870.             age[i]     = m -i;
  871.             outlet(2, i, 0);
  872.         }
  873.     }
  874.     outlet(2, vdraw, 0);//send gate signal to display voice
  875.     kfix = [0,0];
  876.     numv = 0;
  877. }
  878. //------------------------------------------------------------------------------------
  879. // SYNTH PARAMS
  880. //------------------------------------------------------------------------------------
  881. function dflt(chan){
  882.     var defaults =[
  883.         //    0,        gain,    pan1,    pan2,    p0,        o1p,    o2p,    o3p,    o1s,    o2s,    //0-9
  884.             0,        0,        0,        100,    0,        0,        0,        0,        1,        2,        
  885.         //    o3s,    o1w,    o2w,    o3w,    tune,    o1d,    o2d,    o3d,    o1ph,    o2ph,    //10-19
  886.             4,        50,        0,        0,        0,        0,        0,        0,        0,        0,        
  887.         //    o3ph,    o1f1,    o2f1,    o2f3,    o3f1,    o3f2,    sub,    o2am,    o3am,    o1m,    //20-29
  888.             0,        0,        0,        0,        0,        0,        0,        0,        0,        100,        
  889.         //    o2m,    o3m,    o1n,    o2n,    o3n,    c1m,    c2m,    c1d,    c2d,    c1f,    //30-39
  890.             0,        0,        0,        100,    100,    0,        0,        100,    100,    50,        
  891.         //    c2f,    f1u,    f2u,    f1t,    f2t,    f1p,    f2p,    f1s,    f2s,    f1q,    //40-49
  892.             50,        0,        0,        1,        1,        0,        0,        0,        0,        0,        
  893.         //    f2q,    fmix,    l1f,    l2f,    l3f,    l1w,    l2w,    l3w,    e2pre,    e3pre,    //50-59
  894.             0,        0,        1,        2,        3,        0,        0,        50,        0,        0,        
  895.         //    e1a,    e2a,    e3a,    e1d1,    e2d1,    e3d,    e1b,    e2b,    e1d2,    e2d2,    //60-69
  896.             64,        64,        64,        64,        64,        64,        100,    100,    64,        64,        
  897.         //    e1s,    e2s,    e3s,    e1r,    e2r,    e3r,    gtime,    gpat,    gang,    m1s,    //70-79
  898.             50,        50,        50,        64,        64,        64,        0,        0,        0,        9,        
  899.         //    'm2s',    'm3s',    'm4s',    'm5s',    'm6s',    'm7s',    'm8s',    'm9s',    'm10s',    'm11s',    //80-89
  900.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  901.         //    'm12s',    'm13s',    'm14s',    'm15s',    'm1d',    'm2d',    'm3d',    'm4d',    'm5d',    'm6d',    //90-99
  902.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  903.         //    'm7d',    'm8d',    'm9d',    'm10d',    'm11d',    'm12d',    'm13d',    'm14d',    'm15d',    'm1x',    //100-109
  904.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  905.         //    'm2x',    'm3x',    'm4x',    'm5x',    'm6x',    'm7x',    'm8x',    'm9x',    'm10x',    'm11x',    //110-119
  906.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  907.         //    'm12x',    'm13x',    'm14x',    'm15x',    'lo1',    'lo2',    'lo3',    'lo4',    'lo5',    'lo6',    //120-129
  908.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  909.         //    'lo7',    'lo8',    'lo9',    'lo10',    'lo11',    'lo12',    'lo13',    'lo14',    'lo15',    'e1m',    //130-139
  910.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  911.         //    'e2m',    'e3m',    'e1vs',    'e2vs',    'l1t',    'l2t',    'l3t',    'l1s',    'l2s',    'l3s',    //140-149
  912.             0,        0,        1,        1,        0,        0,        0,        1,        2,        3,        
  913.         //    'o1snc','o2snc','o3snc','bend',    'wheel','foot',    'sust',    'port',    'sost',    'soft',    //150-159
  914.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  915.         //    'hold',    'o2ft1','o2ft3','o3ft1','o3ft2','c1t',    'c2t',    'ftrk',    'ftrk2','gtype',//160-169
  916.             0,        0,        0,        0,        0,        0,        0,        1,        1,        0,        
  917.         //    'gscale','gkey','tempo','mon',    'cdm',     'cd1',  'cd2',  'cd3',     'cdx',  'cdy',  //170-179
  918.             0,        0,        120,    9,        0,        1,        1,        1,        1,        1,        
  919.         //    'cdz',    'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    'acnt', 'adur', 'arate',//180-189 
  920.             1,        0,        0,        0,        0,        0,        1,        0,        1,        3,        
  921.         //    'adot',    'atrp', 'axp',    'd1m',    'd2m',    'd1l',    'd2l',    'd1r',    'd2r',    'd1p',  //190-199
  922.             0,        0,        0,        0,        0,        4,        4,        4,        4,        0,        
  923.         //    'd2p',    'd1w',  'd2w',    'd1z',    'd2z',    'd2d',    'd2h',    'ch1m',    'ch1b', 'ch1f', //200-209
  924.             0,        0,        0,        0,        0,        127,    0,        0,        0,        1,        
  925.         //    'ch1s',    'ch1d', 'ch1z',    'Rmix',    'Rpre',    'Rcut',    'Rdamp','Rdecay','limon','limlvl',//210-219
  926.             0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  927.         //    'limwin','lima', 'limr'];                                                        //220-222
  928.             0,        0,        0];
  929.     pgmflag++;
  930.     var a = [pgmflag];//dirty flag at index 0
  931.     var parm, val;
  932.     for (var i = 1; i < 223; i++){            // synth variables
  933.         val   = defaults[i];
  934.         cPnl[i].message('set', val);
  935.         val = pnl2buf(i, val);
  936.         a[i] = val;    
  937.         //if(dbg) post('default',params[idx],'val',val,'cPnl',cPnl[i],'\n');
  938.     }
  939.     channels.poke(chan -1, 0, a);
  940. }
  941. function pnl2synth(param, val){                        //send panel change to synth
  942.     var idx = params.indexOf(param);
  943.     var val = pnl2buf(idx, val);
  944.     channels.poke(curChan, idx, val);
  945.     pgmflag++;
  946.     channels.poke(curChan, 0, pgmflag);
  947. //    cc_out(curChan, param, val);
  948.     if(dbg)post('pnl2synth() chan',curChan,'param', params[idx], 'idx', idx, 'val', val,'\n');
  949. }
  950. function bend(val){
  951.     if(midi_out){
  952.         bend_out(val);
  953.     }
  954.     outlet(0,'bend', val);
  955. }
  956. var pnlscale =[
  957. //    0,        gain,    pan1,    pan2,    p0,        o1p,    o2p,    o3p,    o1s,    o2s,    //0-9
  958.     0,        6,        1,        1,        0,        0,        0,        0,        0,        0,        
  959. //    o3s,    o1w,    o2w,    o3w,    tune,    o1d,    o2d,    o3d,    o1ph,    o2ph,    //10-19
  960.     0,        0,        0,        0,        1,        1,        1,        1,        1,        1,        
  961. //    o3ph,    o1f1,    o2f1,    o2f3,    o3f1,    o3f2,    sub,    o2am,    o3am,    o1m,    //20-29
  962.     1,        1,        1,        1,        1,        1,        1,        1,        1,        1,        
  963. //    o2m,    o3m,    o1n,    o2n,    o3n,    c1m,    c2m,    c1d,    c2d,    c1f,    //30-39
  964.     1,        1,        1,        1,        1,        1,        1,        0,        0,        1,        
  965. //    c2f,    f1u,    f2u,    f1t,    f2t,    f1p,    f2p,    f1s,    f2s,    f1q,    //40-49
  966.     1,        3,        3,        2,        2,        0,        0,        0,        0,        0,        
  967. //    f2q,    fmix,    l1f,    l2f,    l3f,    l1w,    l2w,    l3w,    e2pre,    e3pre,    //50-59
  968.     0,        1,        7,        7,        7,        1,        1,        1,        5,        5,        
  969. //    e1a,    e2a,    e3a,    e1d1,    e2d1,    e3d,    e1b,    e2b,    e1d2,    e2d2,    //60-69
  970.     0,        0,        0,        0,        0,        0,        1,        1,        0,        0,        
  971. //    e1s,    e2s,    e3s,    e1r,    e2r,    e3r,    gtime,    gpat,    gang,    m1s,    //70-79
  972.     1,        1,        1,        0,        0,        0,        0,        0,        1,        0,        
  973. //    'm2s',    'm3s',    'm4s',    'm5s',    'm6s',    'm7s',    'm8s',    'm9s',    'm10s',    'm11s',    //80-89
  974.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  975. //    'm12s',    'm13s',    'm14s',    'm15s',    'm1d',    'm2d',    'm3d',    'm4d',    'm5d',    'm6d',    //90-99
  976.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  977. //    'm7d',    'm8d',    'm9d',    'm10d',    'm11d',    'm12d',    'm13d',    'm14d',    'm15d',    'm1x',    //100-109
  978.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  979. //    'm2x',    'm3x',    'm4x',    'm5x',    'm6x',    'm7x',    'm8x',    'm9x',    'm10x',    'm11x',    //110-119
  980.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  981. //    'm12x',    'm13x',    'm14x',    'm15x',    'lo1',    'lo2',    'lo3',    'lo4',    'lo5',    'lo6',    //120-129
  982.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  983. //    'lo7',    'lo8',    'lo9',    'lo10',    'lo11',    'lo12',    'lo13',    'lo14',    'lo15',    'e1m',    //130-139
  984.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  985. //    'e2m',    'e3m',    'e1vs',    'e2vs',    'l1t',    'l2t',    'l3t',    'l1s',    'l2s',    'l3s',    //140-149
  986.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  987. //    'o1snc','o2snc','o3snc','bend',    'wheel','foot',    'sust',    'port',    'sost',    'soft',    //150-159
  988.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  989. //    'hold',    'o2ft1','o2ft3','o3ft1','o3ft2','c1t',    'c2t',    'ftrk',    'ftrk2','gtype',//160-169
  990.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  991. //    'gscale','gkey','tempo','mon',    'cdm',     'cd1',  'cd2',  'cd3',     'cdx',  'cdy',  //170-179
  992.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  993. //    'cdz',    'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    'acnt', 'adur', 'arate',//180-189 
  994.     0,        0,        0,        0,        0,        0,        0,        0,        0,        0,        
  995. //    'adot',    'atrp', 'axp',    'd1m',    'd2m',    'd1l',    'd2l',    'd1r',    'd2r',    'd1p',  //190-199
  996.     0,        0,        0,        1,        1,        0,        0,        0,        0,        1,        
  997. //    'd2p',    'd1w',  'd2w',    'd1z',    'd2z',    'd2d',    'd2h',    'ch1m',    'ch1b', 'ch1f', //200-209
  998.     1,        1,        1,        1,        1,        0,        0,        1,        0,        0,        
  999. //    'ch1s',    'ch1d', 'ch1z',    'Rmix',    'Rpre',    'Rcut',    'Rdamp','Rdecay','limon','limlvl',//210-219
  1000.     1,        1,        1,        1,        0,        0,        1,        1,        0,        6,        
  1001. //    'limwin','lima', 'limr'];                                                        //220-222
  1002.     4,        8,        8];
  1003. function pnl2buf(idx, val){                            
  1004.     var i = pnlscale[idx];
  1005.     switch(i){
  1006.         case 0:
  1007.             break;
  1008.         case 1: //48 of them--0 indexed
  1009.             val *= .01;    
  1010.             break;
  1011.         case 2: //f1t,f2t
  1012.             val =  val *.01 -1;    
  1013.             break;
  1014.         case 3: //f1u,f2u
  1015.             val =  val *.5  -1; 
  1016.             break;
  1017.         case 4: //limwin, ch1b, Rpre (samples)
  1018.             val *= srms;
  1019.             break;
  1020.         case 5: //e2pre, e3pre (incs)
  1021.             val =  (val==0)? 1:    srms / val;    
  1022.             break;
  1023.         case 6: //gain, limlvl = dbtoa
  1024.             val =  (val ==0)? 1 :    Math.pow(1.12202,val);    
  1025.             break;
  1026.         case 7: //l1f,l2f,l3f
  1027.             val = val * rsr;
  1028.             break;
  1029.         case 8: //lalo,lrlo: integrators
  1030.             val  = 4.6 / (val * srms);            
  1031.             break;
  1032. // does not adjust bend range
  1033. // add axp, scale
  1034.         default:
  1035.     }
  1036.     if(dbg==3)post(idx,val,'adjusted by pnl2buf()\n');
  1037.     return val;
  1038. }
  1039. function buf2pnl(idx, val){                            
  1040.     var i = pnlscale[idx];
  1041.     switch(i){
  1042.         case 0: 
  1043.             break;
  1044.         case 1: //48 of them
  1045.             val *= 100;
  1046.             break;
  1047.         case 2: //f1t,f2t
  1048.             val =  val *100 +100;
  1049.             break;
  1050.         case 3: //f1u,f2u
  1051.             val =  val *2  +2;
  1052.             break;
  1053.         case 4: //limwin,ch1b,lalo,lrlo:
  1054.             val /= srms;
  1055.             break;
  1056.         case 5: //e2pre, e3pre, Rpre
  1057.             val =  (val==1)? 0: val * srms;
  1058.             break;
  1059.         case 6: //gain, limlvl dbtoa
  1060.             val =  8.688 *Math.log(val);
  1061.             break;
  1062.         case 7: //lf1, lf2, lf3
  1063.             val *= sr;
  1064.             break;
  1065.         default:
  1066.     }
  1067.     //if(dbg)post(param,val,'adjusted by buf2pnl()\n');
  1068.     return val;
  1069. }
  1070. //-----------------------------------------------------------------------------
  1071. // MIDI
  1072. //-----------------------------------------------------------------------------
  1073. function note_out(p, v){
  1074.     if(ochan){
  1075.         if(dbg) post('midi note out', p, v);
  1076.         // format 1001.cccc 0ppppppp 0vvvvvvv, c=chan, p=pitch, v=vel
  1077.         // chan in range 0-15, so 9 * 16 -1 = 143
  1078.         sPnl[18].message(chan + 143, p, v);
  1079.     }
  1080. }
  1081. function flush_out(){
  1082.     if(ochan){
  1083.         if(dbg) post('midi flush out');
  1084.         // format 1011cccc 0ppppppp 0vvvvvvv, c=channel, p=cc#, v=val 
  1085.         // 11 *16 - 1 = 175, cc #123, val 0
  1086.         sPnl[18].message(chan + 175, 123, 0);
  1087.     }
  1088. }
  1089. function pgm_out(x){
  1090.     var chan = getochan();
  1091.     if(ochan){
  1092.         if(dbg) post('pgm_out', x);
  1093.         // format 1100.cccc 0ppppppp, c=channel, p=pgm#
  1094.         // chan in range 0-15, so 12 * 16 -1 = 191
  1095.         sPnl[18].message(ochan + 191, p, v);    
  1096.     }
  1097. }
  1098. function bend_out(bend){
  1099.     if(ochan){
  1100.         if(dbg) post('bend_out', bend);
  1101.         // format 1110.cccc 0uuuuuuu 0vvvvvvv, c=chan, u=lsb, v=msb
  1102.         // 11 * 16 -1 = 223
  1103.         sPnl[18].message(getochan() + 223, 0, bend);
  1104.     }
  1105. }
  1106. var ccparams   = [
  1107.     // standard assignments:
  1108.     //4: foot        5:  glide time    7: volume        8: balance    10: pan
  1109.     //64: sus        65: portamento  66: sost        67: soft    68: foot    69: hold    
  1110.     //98-99 nrpn    101-101: rpn    121: reset        122: local        123: notesoff 124: omni off
  1111.     //125: omni on    126: mono on    127: poly on
  1112.     //    '0',    'gain',    'pan1',    'pan2',    'p0',    'o1p',    'o2p',    'o3p',    'o1s',    'o2s',    //0-9
  1113.         0,        7,        8,        10,        0,        1,        2,        3,        20,        21,
  1114.     //    'o3s',    'o1w',    'o2w',    'o3w',    'tune',    'o1d',    'o2d',    'o3d',    'o1ph',    'o2ph',    //10-19
  1115.         22,        23,        24,        25,        26,        27,        28,        29,        0,        0,
  1116.     //    'o3ph',    'o1f1',    'o2f1',    'o2f3',    'o3f1',    'o3f2',    'sub',    'o2am',    'o3am',    'o1m',    //20-29
  1117.         0,        30,        31,        32,        33,        34,        35,        36,        37,        38,
  1118.     //    'o2m',    'o3m',    'o1n',    'o2n',    'o3n',    'c1m',    'c2m',    'c1d',    'c2d',    'c1f',    //30-39
  1119.         39,        40,        41,        42,        43,        44,        45,        46,        47,        48,
  1120.     //    'c2f',    'f1u',    'f2u',    'f1t',    'f2t',    'f1p',    'f2p',    'f1s',    'f2s',    'f1q',    //40-49
  1121.         49,        50,        51,        52,        53,        54,        55,        56,        57,        58,
  1122.     //    'f2q',    'fmix',    'l1f',    'l2f',    'l3f',    'l1w',    'l2w',    'l3w',    'e2pre','e3pre',//50-59
  1123.         59,        60,        61,        62,        63,        70,        71,        72,        73,        74,
  1124.     //    'e1a',    'e2a',    'e3a',    'e1d1',    'e2d1',    'e3d',    'e1b',    'e2b',    'e1d2',    'e2d2',    //60-69
  1125.         75,        76,        77,        78,        79,        80,        81,        82,        83,        84,
  1126.     //    'e1s',    'e2s',    'e3s',    'e1r',    'e2r',    'e3r',    'gtime','gpat',    'gang',    'm1s',    //70-79
  1127.         85,        86,        87,        88,        89,        90,        5,        91,        92,        0,
  1128.     //    'm2s',    'm3s',    'm4s',    'm5s',    'm6s',    'm7s',    'm8s',    'm9s',    'm10s',    'm11s',    //80-89
  1129.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1130.     //    'm12s',    'm13s',    'm14s',    'm15s',    'm1d',    'm2d',    'm3d',    'm4d',    'm5d',    'm6d',    //90-99
  1131.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1132.     //    'm7d',    'm8d',    'm9d',    'm10d',    'm11d',    'm12d',    'm13d',    'm14d',    'm15d',    'm1x',    //100-109
  1133.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1134.     //    'm2x',    'm3x',    'm4x',    'm5x',    'm6x',    'm7x',    'm8x',    'm9x',    'm10x',    'm11x',    //110-119
  1135.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1136.     //    'm12x',    'm13x',    'm14x',    'm15x',    'lo1',    'lo2',    'lo3',    'lo4',    'lo5',    'lo6',    //120-129
  1137.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1138.     //    'lo7',    'lo8',    'lo9',    'lo10',    'lo11',    'lo12',    'lo13',    'lo14',    'lo15',    'e1m',    //130-139
  1139.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1140.     //    'e2m',    'e3m',    'e1vs',    'e2vs',    'l1t',    'l2t',    'l3t',    'l1s',    'l2s',    'l3s',    //140-149
  1141.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1142.     //    'o1snc','o2snc','o3snc','bend',    'wheel','foot',    'sust',    'port',    'sost',    'soft',    //150-159
  1143.         0,        0,        0,        0,        1,        68,        64,        65,        66,        67,
  1144.     //    'hold',    'o2ft1','o2ft3','o3ft1','o3ft2','c1t',    'c2t',    'ftrk',    'ftrk2','gtype',//160-169
  1145.         69,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1146.     //    'gscale','gkey','tempo','mon',    'cdm',     'cd1',  'cd2',  'cd3',     'cdx',  'cdy',  //170-179
  1147.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1148.     //    'cdz',    'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    'acnt', 'adur', 'arate',//180-189 
  1149.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1150.     //    'adot',    'atrp', 'axp',    'd1m',    'd2m',    'd1l',    'd2l',    'd1r',    'd2r',    'd1p',  //190-199
  1151.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1152.     //    'd2p',    'd1w',  'd2w',    'd1z',    'd2z',    'd2d',    'd2h',    'ch1m',    'ch1b', 'ch1f', //200-209
  1153.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1154.     //    'ch1s',    'ch1d', 'ch1z',    'Rmix',    'Rpre',    'Rcut',    'Rdamp','Rdecay','limon','limlvl',//210-219
  1155.         0,        0,        0,        0,        0,        0,        0,        0,        0,        0,
  1156.     //    'limwin','lima', 'limr'                                                            //220-222
  1157.         0,        0,        0        ];
  1158. function cc_out(param, val){//sets values from synth receive ranges
  1159.     var chan = getochan();
  1160.     if(chan){
  1161.         if(dbg) post('midi_out', param, val);
  1162.         var idx = ccparams.indexOf(param);
  1163.         if(idx >0){
  1164.             switch(param){
  1165.                 case 1: case 2: case 3: case 44: case 45: // o1p, o2p, o3p, f1p, f2p
  1166.                     val +=63;
  1167.                     break;
  1168.                 case 7:                        //level, limwin
  1169.                     val +=70;
  1170.                     break;
  1171.                 case 46: case 47:             // f1s, f2s, e1vs, e2vs, tempo
  1172.                     val *=0.5;
  1173.                     break;
  1174.                 case 40: case 41:             // f1u, f2u
  1175.                     val = (val +1) * 50;                //- TODO
  1176.                     break;                 
  1177.                 case 42: case 43:             //f1t, f2t
  1178.                     val = (val +1) * 50;
  1179.                     break;
  1180.                 case 27: case 28: case 29:     // o1d o2d o3d
  1181.                     val = (val + 0.5) * 100;
  1182.                     break;
  1183.                 case 51: case 52: case 53:     //l1f, l2f, l3f, ch1f
  1184.                     val = sqrt(val/30.) * 127.;
  1185.                     break;
  1186.                 case 30: case 35: case 36: case 37: // o1f1 sub o2am o3am  
  1187.                 case 38: case 39: case 40: case 41: case 42: case 43: // o1m o2m o3m o1n o2n o3n
  1188.                 case 38: case 39: case 40: case 41: case 42: case 43: // c1m c2m c1f c2f pan1 pan2 fmix 
  1189.                 case 54: case 55: case 56: case 71: case 72: case 75: case 76: case 77: // l1w l2w l3w e1b e2b e1s e2s e3s
  1190.                 // o1ph o2ph o3ph d1m d2m d1w d2w d1z d2z d1p d2p ch1s ch1d ch1z ch1m Rmix Rdamp Rdecay
  1191.                     val *= 100;
  1192.                     break;
  1193.                 //    val *= 50;                // c2t c1t ftrck ftrck2 o2ft1 o2ft3 o3ft1 o3ft2 
  1194.                 //    val = (val==0)? 0 : (getsr() / val) * 100;    // e2pre e3pre
  1195.                 //  val = (val==0)? 0 : (getsr() / val) * 2000;    // Rpre
  1196.                 //    val = (val==0)? 0 : (getsr() / val) * 500;    // limwin ch1b lima limr
  1197.                 //    val = 8.688 * Math.log(val); break; // limlvl atodb: 20 * log(v)/Math.LN10    
  1198.                 default:
  1199.             }
  1200.             // format 1011cccc 0ppppppp 0vvvvvvv, c=channel, p=cc#, v=val 
  1201.             // 11 *16 - 1 = 175
  1202.             sPnl[18].message(ochan + 175, val);
  1203.         }
  1204.     }
  1205. }
  1206. function midi_in(status, cc, val){
  1207.     if(dbg) post('midi in', status, cc, val);
  1208.     var type = status >> 4
  1209.     var chan = status & 16;
  1210.     chan += 1;
  1211.     if (chan != chana || (chan!= chanb && status!=13)){
  1212.          return;
  1213.     }else if(status==9){     // note, format 1001.cccc 0ppppppp 0vvvvvvv, c=chan, p=pitch, v=vel
  1214.         //('set', cc, val *.007874);
  1215.         key(cc, val);
  1216.     }else if(status==12){     // pgm#, format 1100.cccc 0ppppppp, c=chan, p=pgm#
  1217.         recall(cc +1);
  1218.     }else if(status==14){     // bend, format 1110.cccc 0uuuuuuu 0vvvvvvv, c=chan, u=lsb, v=msb
  1219.         //('bend', x);
  1220.     }else if(status==13){    // ctrl, format 1011.cccc 0ppppppp 0vvvvvvv, c=chan, p=cc#, v=val 
  1221.         if (cc > 203){
  1222.              return;
  1223.         } else if (cc==123){
  1224.             flush();
  1225.         } else {
  1226.             var param = ccparams[cc];
  1227.             if(dbg) post('midi in', param, val, '\n');
  1228.             switch(param){
  1229.                 //case 'rst':
  1230.                 //    outlet(7,'flush'); break;
  1231.                 case 27: case 28: case 29: // o1d o2d o3d
  1232.                     val -= -50; 
  1233.                     break;
  1234.                 case 1: case 2: case 3: case 44: case 45: // o1p, o2p, o3p, f1p, f2p
  1235.                     val -= 63; 
  1236.                     break;
  1237.                 case 7:                        //level, limwin
  1238.                       val -=70; 
  1239.                     break;
  1240.                 case 40: case 41:             // f1u, f2u
  1241.                      val *= 0.04; 
  1242.                     break;
  1243.                 case 51: case 52: case 53:     //l1f, l2f, l3f, ch1f
  1244.                     val = Math.pow(val/127., 2) * 15; 
  1245.                     break;
  1246.                 case 46: case 47:             // f1s, f2s, f1t, f2t, e1vs, e2vs, tempo, ch1b, limwin, lima, limr
  1247.                      val *= 0.5; 
  1248.                     break;
  1249.                 case 30: case 35: case 36: case 37: // o1f1 sub o2am o3am  
  1250.                 case 38: case 39: case 40: case 41: case 42: case 43: // o1m o2m o3m o1n o2n o3n
  1251.                 case 38: case 39: case 40: case 41: case 42: case 43: // c1m c2m c1f c2f pan1 pan2 fmix 
  1252.                 case 54: case 55: case 56: case 71: case 72: case 75: case 76: case 77: // l1w l2w l3w e1b e2b e1s e2s e3s
  1253.                 // o1ph o2ph o3ph d1m d2m d1w d2w d1z d2z d1p d2p ch1s ch1d ch1z ch1m Rmix Rdamp Rdecay
  1254.                     val *= 0.01;
  1255.                     break;
  1256.                 //case 'brange': case 'nrpn_lo': case 'nrpn_hi':
  1257.                 //    return;
  1258.                 // val *= 2; break;        // tempo, rPre
  1259.                  // val -= 36; break;        // limlvl
  1260.                 // val *= 0.02;                 // c2t c1t ftrck ftrck2 o2ft1 o2ft3 o3ft1 o3ft2 
  1261.                 default:
  1262.                     break;
  1263.             }
  1264.             pnl2buf(param, val);
  1265.         }
  1266.     }
  1267. }
  1268. //------------------------------------------------------------------------------------
  1269. // BUFFER SETUP
  1270. //------------------------------------------------------------------------------------
  1271. var scalesArray = [];
  1272. declareattribute('scalesArray','scales','initScales');
  1273. function scales(x, y){ 
  1274.     return scalesArray[x][y];
  1275. }
  1276. function initScales(){                                // init scales and microtune buffers
  1277.     var v = [];
  1278.     v[1]  = [0,   1,  2, 3, 4, 5, 6, 7, 8,  9, 10, 11];//chromatic
  1279.     v[2]  = [0,   0,  2, 2, 4, 5, 5, 7, 7,  9,  9, 11];//major
  1280.     v[3]  = [0,   0,  2, 3, 3, 5, 5, 7, 8,  8, 11, 11];//minor
  1281.     v[4]  = [0,   0,  2, 3, 3, 5, 5, 7, 8,  8, 10, 10];
  1282.     v[5]  = [0,   0,  2, 3, 5, 5, 7, 7, 9,  9, 10, 10];
  1283.     v[6]  = [0,   0,  1, 1, 3, 3, 5, 5, 8,  8, 10, 10];
  1284.     v[7]  = [0,   0,  2, 2, 4, 6, 6, 7, 7,  9,  9, 11];
  1285.     v[8]  = [0,   0,  2, 2, 4, 5, 5, 7, 7,  9,  9, 10];
  1286.     v[9]  = [0,   0,  2, 3, 3, 5, 7, 7, 8,  8, 10, 10];
  1287.     v[10] = [0,   0,  3, 3, 5, 5, 7, 7, 7, 10, 10, 10];
  1288.     v[11] = [0,   2,  2, 4, 4, 4, 7, 7, 7,  9,  9,  9];
  1289.     v[12] = [11, 10,  9, 8, 7, 6, 5, 4, 3,  2,  1,  0];//reverse
  1290.     v[13] = [0,   1, 11, 7, 4, 5, 6, 3, 8,  9, 10,  2];
  1291.     v[14] = [11,  2,  7, 4, 9, 5, 7, 5, 9,  2,  1,  0];
  1292.     v[15] = [0,   2,  4, 0, 1, 0, 5, 0, 4, 10,  9,  0];
  1293.  
  1294.     var b = [];
  1295.     b[1]  = [0,   1,  2, 3, 4, 5, 6, 7, 8, 9,  10, 11];                     // Equal tempered 12
  1296.     b[2]  = [0,          1.11731, 2.0391,   3.15641,  3.86314,  4.98045,
  1297.              6.09776, 7.01955, 8.13686,  8.84359,  9.9609,  10.8827];    // Albion 12
  1298.     b[3]  = [0,          0.9218,  2,         2.9609,   3.90225,  5,
  1299.              5.90225, 7,       7.94135,  8.95113,  9.98045, 10.9023];     // Bach 12
  1300.     b[4]  = [0,          0.679002,1.38573,  2.12253,  2.8921,   4.54214,
  1301.              5.43015, 6.36618, 8.0091,   8.40528,  9.52259, 10.717];    // Chinese 12
  1302.     b[5]  = [0,          1.11731, 2.0391,   3.15641,  3.86314,  4.98045,
  1303.              5.82512, 7.01955, 8.13686,  8.84359, 10.176,   10.8827];    // Just 12
  1304.     b[6]  = [0,          0.76049, 1.93157,  3.10265,  3.86314,  5.03422,
  1305.              5.79471, 6.96578, 7.72627,  8.89735, 10.0684,  10.8289];    // Meanquar 12
  1306.     b[7]  = [0,       1.1137,  2.039,    3.176,    4.078,    4.98, 
  1307.              6.117,   7.02,    8.156,    9.059,   10.2,     11.09];        // Pythagorean 12
  1308.     b[8]  = [0,          0.66,       2.02,     3.16,       3.99,     5.09,        
  1309.              6.4,      7.06,       8.03,     9.1,      10.11,    10.92];        // Santana 12
  1310.     b[9]  = [0,          1.00883, 2.00595,  3.00288,  4.00003,  5.0071,
  1311.              6.00704, 6.99977, 8.00684,  9.00399, 10.0009,  11.0011];    // Santura 12
  1312.     b[10] = [0,          0.706724,1.82404,  2.0391,   3.15641,  3.86314,
  1313.              4.98045, 7.01955, 7.72627,  8.13686,  8.84359, 10.8827];    // Scottish 12
  1314.     b[11] = [0,          0.94135, 1.9609,   2.98045,   3.9218,  5.01955,
  1315.              5.9218,  6.98045, 7.9609,   8.94135,  10,        10.9023];    // Orchestra 12
  1316.     b[12] = [0,       0.90225, 1.9218,   2.94135,  3.90225,  4.98045,
  1317.              5.8827,  6.9609,  7.9218,   8.8827,   9.9609,  10.9218];    // Werckmeister 12
  1318.     b[13] = [0,          1.76646, 2.0391,    2.39607,  4.70781, 4.43517,
  1319.              6.74691, 7.01955, 7.37652,   9.68826,  9.41562,11.7274];    // Young Piano 12
  1320.     b[14] = [0,          0,       1.82404,  2.66871,  4.27373,  5.10367,
  1321.                5.71726, 7.01955, 7.45786,  9.9609,   9.9609,  11.2632];    // Marimba 11
  1322.     b[15] = [0,          0,       1.3,      1.3,       3.45,     4.9,
  1323.                4.9,     6.3,     6.3,      8.5,       10.35,   11.37];        // Orchestra 11
  1324.     b[16] = [0,          0,       2.0391,   2.0391,   3.86314,  4.98045,
  1325.                4.98045, 7.01955, 7.01955,  8.84359,  8.84359, 10.176];    // Bagpipe 8
  1326.     b[17] = [0,          0,       2.35677,  2.66871,  3.86314,  5.51318,
  1327.              5.51318, 6.53185, 6.53185,  8.18189,  9.68826, 10.4936];    // Harmonics 8
  1328.     b[18] = [0.833333,0.833333,4,         4,            5,         7,
  1329.              7,          7.83333, 7.83333,  11,       11,        12];        // Orchestra 8
  1330.     b[19] = [0,          0,       2.0391,   2.0391,   4.0782,   4.98045,
  1331.              4.98045, 7.01955, 7.01955,  9.05865,  9.05865, 11.0977];    // Euler 7
  1332.     b[20] = [1.29,      1.29,    3.27,     3.27,       5.46,     6.34,
  1333.              6.34,      7.35,       7.35,    10.22,      10.22,    11.68];        // Fokker 7
  1334.     b[21] = [0,          0,       3.86314,  3.86314,  4.98045,  7.01955,
  1335.              7.01955, 8.84359, 8.84359,  8.84359, 10.8827,  10.8827];    // Gamelan 7
  1336.     b[22] = [0,       0,       2.31174,  2.31174,  4.62348,  4.62348,
  1337.              4.62348, 5.06478, 5.06478,  7.37652,  7.37652,  9.68826];  // Hexatron 7
  1338.     b[23]  = [0,       0,       3.86314,  3.86314,  4.98045,  7.01955,
  1339.               7.01955, 8.84359, 8.84359, 10.8827,  10.8827,  12];        // Bulgarian 6
  1340.     b[24] = [0,          0,       1.55003,  1.55003,  3.44805,  3.44805,
  1341.             3.44805,  6.93988, 6.93988,  8.23199,  8.23199,    12];         // Golden 5
  1342.     b[25] = [0,          0,        3.86314,     3.86314,  4.70781,  4.70781,
  1343.              4.70781, 7.01955, 7.01955,  8.40528,  8.40528, 12];        // Pygmy 5
  1344.     b[26] = [0,          0,       1.85,     1.85,     3.37,     3.37,
  1345.              3.37,    6.83,    6.83,     7.9,      7.9,     12];        // Tetragam 5
  1346.     b[27] = [0,          0,       2.31174,  2.31174,  4.70781,  4.70781,
  1347.              4.70781, 7.01955, 7.01955,  9.68826,  9.68826, 12];        // Xenakis 5
  1348.  
  1349.     var s = new Buffer('scales');                    
  1350.     var m = new Buffer('micro');                    
  1351.     var a = [];
  1352.     for (var x = 1; x < 16; x++) {
  1353.           scalesArray[x] = new Array(132);
  1354.         a[x] = new Array(132);
  1355.     }
  1356.     var c = [];
  1357.     for (x = 1; x < 28; x++) {
  1358.          c[x] = new Array(132);
  1359.     }
  1360.     var i;
  1361.     for(var oct=0;oct<132;oct +=12){
  1362.         for(var note=0; note<12; note++){
  1363.             i = oct + note;
  1364.             for(x=1; x<16; x++){
  1365.                 a[x][i] = oct + v[x][note];
  1366.                 c[x][i] = oct + b[x][note];
  1367.             }
  1368.             for(x=16; x<28; x++){
  1369.                 c[x][i] = oct + b[x][note];
  1370.             }
  1371.         }
  1372.     }
  1373.     for(x=1; x<16; x++){
  1374.         s.poke(x, 0, a[x]);
  1375.         scalesArray[x -1] = a[x];
  1376.         //if(dbg)post(a[x],'\n');
  1377.     }
  1378.     for(x=1; x<28; x++){
  1379.         m.poke(x, 0, c[x]);
  1380.         //if(dbg)post(c[x],'\n');
  1381.     }
  1382. }
  1383. function initPatterns(){
  1384.     var patterns = new Buffer('patterns');            //init pattern buffer
  1385.     var a = [];
  1386.     var v =[];
  1387.     v[1]  = [1,2,3,4];    v[2]  = [1,2,4,3];    v[3]  = [1,3,2,4];
  1388.     v[4]  = [1,3,4,2];    v[5]  = [1,4,2,3];    v[6]  = [1,4,3,2];
  1389.     v[7]  = [2,1,3,4];    v[8]  = [2,1,4,3];    v[9]  = [2,3,1,4];
  1390.     v[10] = [2,3,4,1];    v[11] = [2,4,1,3];    v[12] = [2,4,3,1];
  1391.     v[13] = [3,1,2,4];    v[14] = [3,1,4,2];    v[15] = [3,2,1,4];
  1392.     v[16] = [3,2,4,1];    v[17] = [3,4,2,1];    v[18] = [3,4,1,2];
  1393.     v[19] = [4,1,2,3];    v[20] = [4,1,3,2];    v[21] = [4,2,1,3];
  1394.     v[22] = [4,2,3,1];    v[23] = [4,3,1,2];    v[24] = [4,3,2,1];
  1395.     for(var w=1; w<25; w++){
  1396.         a[0] = 0;
  1397.         for(var x=0;x<32;x +=4){
  1398.             for (var y=0;y<4;y++){
  1399.                 a[x + y +1] = x + v[w][y];
  1400.             }
  1401.         }
  1402.         patterns.poke(w, 0, a);
  1403.     }
  1404. }
  1405. //-----------------------------------------------------------------------------
  1406. // WINDOW
  1407. //-----------------------------------------------------------------------------
  1408. var winsize = [0,0];                // window size
  1409.  
  1410. function winresize(){                                //setup zoom
  1411.     var s = this.patcher.wind.size;
  1412.     if(s[0] !=winsize[0] || s[1] !=winsize[1]){
  1413.         winsize[0] = s[0]; winsize[1] = s[1];
  1414.         this.patcher.zoomfactor(
  1415.             Math.min(s[0] / 1560, s[1] / 770));
  1416.         this.patcher.wind.scrollto(0, 0);
  1417.         if(dbg) post('window size: ' + s[0] + ' ' + s[1] + '\n');
  1418.     }
  1419.     return;
  1420. }
  1421. //-----------------------------------------------------------------------------
  1422. // MAIN PANEL TIPS
  1423. //-----------------------------------------------------------------------------
  1424. var tipstr = [];
  1425. declareattribute('tipstr','getTip','initTips');
  1426. function initTips(){
  1427.     tipstr[0] = [
  1428.     //    '0',    'gain',    'pan1',    'pan2',    'p0',    'o1p',    'o2p',    'o3p',    'o1s',    'o2s',    //0-9
  1429.         -1,        0,        1,        1,        -1,        2,        2,        2,        3,        3,
  1430.     //    'o3s',    'o1w',    'o2w',    'o3w',    'tune',    'o1d',    'o2d',    'o3d',    'o1ph',    'o2ph',    //10-19
  1431.         3,        4,        4,        4,        -1,        5,        5,        5,        6,        6,
  1432.     //    'o3ph',    'o1f1',    'o2f1',    'o2f3',    'o3f1',    'o3f2',    'sub',    'o2am',    'o3am',    'o1m',    //20-29
  1433.         6,        7,        8,        8,        8,        8,        9,        10,        10,        11,
  1434.     //    'o2m',    'o3m',    'o1n',    'o2n',    'o3n',    'c1m',    'c2m',    'c1d',    'c2d',    'c1f',    //30-39
  1435.         11,        11,        11,        11,        11,        12,        12,        13,        13,        14,
  1436.     //    'c2f',    'f1u',    'f2u',    'f1t',    'f2t',    'f1p',    'f2p',    'f1s',    'f2s',    'f1q',    //40-49
  1437.         14,        15,        15,        16,        16,        17,        17,        18,        18,        19,
  1438.     //    'f2q',    'fmix',    'l1f',    'l2f',    'l3f',    'l1w',    'l2w',    'l3w',    'e2pre','e3pre',//50-59
  1439.         19,        20,        21,        21,        21,        22,        22,        22,        23,        23,
  1440.     //    'e1a',    'e2a',    'e3a',    'e1d1',    'e2d1',    'e3d',    'e1b',    'e2b',    'e1d2',    'e2d2',    //60-69
  1441.         24,        24,        24,        25,        25,        26,        27,        27,        28,        28,
  1442.     //    'e1s',    'e2s',    'e3s',    'e1r',    'e2r',    'e3r',    'gtime','gpat',    'gang',    'm1s',    //70-79
  1443.         29,        29,        29,        30,        30,        30,        31,        32,        33,        34,
  1444.     //    'm2s',    'm3s',    'm4s',    'm5s',    'm6s',    'm7s',    'm8s',    'm9s',    'm10s',    'm11s',    //80-89
  1445.         34,        34,        34,        34,        34,        34,        34,        34,        34,        34,        
  1446.     //    'm12s',    'm13s',    'm14s',    'm15s',    'm1d',    'm2d',    'm3d',    'm4d',    'm5d',    'm6d',    //90-99
  1447.         34,        34,        34,        34,        35,        35,        35,        35,        35,        35,    
  1448.     //    'm7d',    'm8d',    'm9d',    'm10d',    'm11d',    'm12d',    'm13d',    'm14d',    'm15d',    'm1x',    //100-109
  1449.         35,        35,        35,        35,        35,        35,        35,        35,        35,        36,
  1450.     //    'm2x',    'm3x',    'm4x',    'm5x',    'm6x',    'm7x',    'm8x',    'm9x',    'm10x',    'm11x',    //110-119
  1451.         36,        36,        36,        36,        36,        36,        36,        36,        36,        36,        
  1452.     //    'm12x',    'm13x',    'm14x',    'm15x',    'lo1',    'lo2',    'lo3',    'lo4',    'lo5',    'lo6',    //120-129
  1453.         36,        36,        36,        36,        37,        37,        37,        37,        37,        37,    
  1454.     //    'lo7',    'lo8',    'lo9',    'lo10',    'lo11',    'lo12',    'lo13',    'lo14',    'lo15',    'e1m',    //130-139
  1455.         37,        37,        37,        37,        37,        37,        37,        37,        37,        38,
  1456.     //    'e2m',    'e3m',    'e1vs',    'e2vs',    'l1t',    'l2t',    'l3t',    'l1s',    'l2s',    'l3s',    //140-149
  1457.         38,        38,        39,        39,        40,        40,        40,        41,        41,        41,
  1458.     //    'o1snc','o2snc','o3snc','bend',    'wheel','foot',    'sust',    'port',    'sost',    'soft',    //150-159
  1459.         42,        42,        42,        43,        44,        45,        46,        47,        48,        49,
  1460.     //    'hold',    'o2ft1','o2ft3','o3ft1','o3ft2','c1t',    'c2t',    'ftrk',    'ftrk2','gtype',//160-169
  1461.         50,        51,        51,        51,        51,        52,        52,        53,        53,        54,
  1462.     //    'gscale','gkey','tempo','mon',    'cdm',     'cd1',  'cd2',  'cd3',     'cdx',  'cdy',  //170-179
  1463.         55,        55,        56,        57,        58,        59,        59,        59,        60,        60,
  1464.     //    'cdz',    'cdn',  'cda',  'cdp',  'aon',  'apat', 'amod',    'acnt', 'adur', 'arate',//180-189 
  1465.         60,        61,        61,        62,        63,        64,        65,        66,        67,        68,
  1466.     //    'adot',    'atrp', 'axp',    'd1m',    'd2m',    'd1l',    'd2l',    'd1r',    'd2r',    'd1p',  //190-199
  1467.         68,        68,        -1,        69,        69,        70,        70,        70,        70,        71,
  1468.     //    'd2p',    'd1w',  'd2w',    'd1z',    'd2z',    'd2d',    'd2h',    'ch1m',    'ch1b', 'ch1f', //200-209
  1469.         71,        72,        72,        73,        73,        74,        74,        75,        76,        77,
  1470.     //    'ch1s',    'ch1d', 'ch1z',    'Rmix',    'Rpre',    'Rcut',    'Rdamp','Rdecay','limon','limlvl',//210-219
  1471.         78,        79,        80,        81,        82,        83,        84,        85,        86,        87,
  1472.     //    'limwin','lima', 'limr'                                                            //220-222
  1473.         88,        89,        90    
  1474.     ];
  1475.     tipstr[1] = [
  1476.     //    '0',      'm1b',    'm2b',      'm3b',      'm4b',     'm5b',       'm6b',     'm7b',       'm8b',      'm9b',      // 0-9
  1477.         -1,          -1,        -1,          -1,          -1,          -1,        -1,          -1,        -1,          -1,            
  1478.     //    'm10b',      'm11b',    'm12b',      'm13b',      'm14b',     'm15b',   'lfo1',     'lfo2',   'lfo3',      'd1',          //10-19
  1479.         -1,          -1,        -1,          -1,          -1,          -1,        91,          91,        91,          -1,            
  1480.     //    'd2',      'd3',        'd4',      'd5',          'env1',     'env2',   'env3',     'ch1',       'ch2',      'ch3',      //20-29
  1481.         -1,          -1,        -1,          -1,          92,          92,        92,          -1,        -1,          -1,            
  1482.     //    'ch4',      'ch5',    'ch6',      'ch7',      'ch8',     'l1wave', 'l2wave', 'l3wave', 'o1wave',   'o2wave',  //30-39
  1483.         -1,          -1,        -1,          -1,          -1,          93,        93,          93,        94,          94,            
  1484.     //    'o3wave', 'f1grph', 'f2grph', 'debugnum', 'splash',  'eptr',   'pow25',  'graph',  'svfgain',  'wavesets',//40-49
  1485.         94,          95,        95,          -1,          -1,          -1,        -1,          -1,        -1,          -1,            
  1486.     //    'pgms',   'kslider','kslider2','ezdac',      'tiptxt',     'muter',  'scopes',                                   //50-59
  1487.         -1,          96,        -1,          97,          98,          -1,        99                     
  1488.     ];
  1489.     tipstr[2] = [
  1490.         'off1',     'off2',  'off3',  'off4',    'off5',    'off6',    'off7',    'off8',    'off9',    'off10',    
  1491.         'off11', 'off12', 'off13', 'off14',    'off15'
  1492.     ]
  1493.     tipstr[3] = [
  1494.     //    'off1',     'off2',  'off3',  'off4',    'off5',    'off6',    'off7',    'off8',    'off9',    'off10',    
  1495.         100,     100,      100,       100,        100,    100,    100,    100,    100,    100,    
  1496.     //    'off11', 'off12', 'off13', 'off14',    'off15'
  1497.         100,     100,      100,       100,        100
  1498.     ]
  1499.     tipstr[4] = [
  1500.     /*0*/"LEVEL. Sets output level in dB",
  1501.     /*1*/"FILTER PAN mix to effects and output. "
  1502.         +"* Pan A adjusts the mix of filter A to the left and right effect channels. "
  1503.         +"* Pan B adjusts the mix of filter B to the left and right effect channels. ",
  1504.     /*2*/"OSC TRANPOSE. Oscillator pitch transposition from input pitch, in MIDI units.",
  1505.     /*3*/"OSC WAVE SELECT. A list box allowing selection of one of 56 waveforms. ",
  1506.     /*4*/"OSC SHAPE. Sets the oscillator shape or duty cycle. "
  1507.         +"* For pulse waveforms, the oscillator is a square wave at 50%, and a rising/falling pulse at low/high settings. "
  1508.         +"* For wavesets, this selects one of 128 wave shapes in the waveset. "
  1509.         +"* For filtered noise oscillators,  this adjusts the filter resonance. "
  1510.         +"* For Karplus strings, it adjusts the damping. "
  1511.         +"* For random/noise, it adjusts the randomness (use higher pitches for good randomness).",
  1512.     /*5*/"OSC TUNE. Detune from input pitch, in cents.",
  1513.     /*6*/"OSC PHASE. Depends on Sync settings. "
  1514.         +"* With GATE sync, setting the phase is most useful when the two oscillators are the same pitch, "
  1515.             +" or different by octaves. "
  1516.         +"* With SOFT, at 0 the behavior is like that of standard hard sync. "
  1517.             +"At higher settings, more of this oscillators tonal quality is preserved, until at 1 the sync never occurs. "
  1518.         +"* With RAMP sync, varying soft syncs are possible even with pulse waves. ",
  1519.     /*7*/"OSC FEEDBACK. Oscillator FM-rate self feedback. * At 0, there's no feedback. * At higher values the feedback distorts "
  1520.         +"the output into noise.",
  1521.     /*8*/"OSC FM DEPTH. At zero, there's no FM. At higher values, the FM depth is set in MIDI semitones. "
  1522.         +"For example, if the current note is middle C, and FM is set to 72 (with no FM track), the modulator ratio is 2:1. "
  1523.         +"This design assists in creating harmonic FM tones.",
  1524.     /*9*/"SUB OSCILLATOR LEVEL. Sets level of antialiased square wave one octave below oscillator pitch, "
  1525.         +"to fatten sound.",
  1526.     /*10*/"OSC RING. Oscillator ring modulation. The unity output of both oscillators is multiplied together "
  1527.         +"and mixed with the oscillator mix. "
  1528.         +"* At 0, there is no ring modulation. "
  1529.         +"At 50, there's an equal amount of ring modulation and oscillator mix. "
  1530.         +"At 100, only ring modulation is output.",
  1531.     /*11*/"1>A, 1>B, 2>A, 2>B, 3>A, 3>B. Sets the oscillator level sent to filter channels. If the sum of the levels "
  1532.         +"for the A or B channel are more than 100%, the oscillators' levels are relatively scaled to keep their sum "
  1533.         +"in the unity gain range. Otherwise, if the oscillator levels add up to <100%, the oscillators are simply "
  1534.         +"added together. If you want equal mix at max. level or 2 or more oscillators, simply set their mix levels "
  1535.         +"all the way to the right.",
  1536.     /*12*/"COMB FILTER MIX. * At 0, there's no comb filter. * At 100, the output is fully combed. "
  1537.         +"*Intermediate values mix the comb filter output with the source.",
  1538.     /*13*/"COMB DEPTH. Comb filter base delay, in 10ths of milliseconds.",
  1539.     /*14*/"COMB FEEDBACK. At 0, there's no feedback. * At low levels the comb filter acts more like a phasor. "
  1540.         +"* At higher levels the comb acts more like a flanger. The feedback level is clipped to prevdent self oscillation. ",
  1541.     /*15*/"FILTER POLES. This sets the number of poles AND mixes the filter with the input from the comb filter. "
  1542.         +"* At left, the output is directly from the comb filter. "
  1543.         +"* At midpoint, the input passes only through a two-pole filter. "
  1544.         +"* At far right, the input pases through a four-pole filter. "
  1545.         +"* Intermediate values provide a mix of the input and filter types.",
  1546.     /*16*/"FILTER TYPE. * At far left, the output is low-pass filtered. "
  1547.         +"* At midpoint, it is band-pass filtered. "
  1548.         +"* At far right, it is high-pass filtered. * Intermediate values pan between the filter types. ",
  1549.     /*17*/"FILTER CUTOFF. The offset of the filter cutoff from the note pitch, set in MIDI note values "
  1550.         +"before modulation and tracking.",
  1551.     /*18*/"FILTER DRIVE, with saturation. "
  1552.         +"* Between 0 and 100, the amount of filter saturation gradually increases, "
  1553.         +"and as the filter is gain compensated. the proportion of self oscillation "
  1554.         +"to filtered sound increases (if there is no self oscillation, there is no apparent effect in this range). "
  1555.         +"Between 100 and 200, the gain compensation is gradually removed, and the output passed through "
  1556.         +"a parabolic saturator with hard clipping at +24dB input.",
  1557.     /*19*/"FILTER RESONANCE. At 0, there is no resonance. "
  1558.         +"* At 100 resonance is actually 1.1. This control is logarithmically adjusted to provide finer control "
  1559.         +"at higher resonance settings.",
  1560.     /*20*/"SERIAL/PARALLEL. * At full left, in parallel mode, oscs panA > combA > filterA > filter A pan, "
  1561.         +"while oscs' panB > comb B > FilterB. * At full right, in serial mode, oscs' panA > combA > filterA > combB > "
  1562.         +"filterB (so both oscs' panB have no output in fully serial mode). "
  1563.         +"* At intermediate values there is a mix of serial and parallel filter output to the effects chain.",
  1564.     /*21*/"LFO FREQUENCY. This control is exponentially scaled to provide more control at lower frequencies.",
  1565.     /*22*/"LFO SHAPE or duty cycle. The current waveform is displayed in the panel",
  1566.     /*23*/"ENVELOPE PREDELAY, in milliseconds. If this is set, the automatic predelay described in the tip for 'attack'"
  1567.         +" is skipped. Setting this to zero can produce clicks on playing notes, which may be desirable in some cases.",
  1568.     /*24*/"ENVELOPE ATTACK DURATION, during which the envelope rises to the gale llevel. If the envelope is already outputting "
  1569.         +"sound, a pre-attack phase of 5ms is added, during which the output drops to zero before the attack phase begins, "
  1570.         +"ensuring full attack on all notes. Duration is scaled logarithmically in the same way for all envelope phase "
  1571.         +"durations, as follows: Min is 3ms. At 25% (32), the duration: 28ms, Half way (64), the duration is 244ms. "
  1572.         +"Three quarters (96) is 21 sec, The max is 18 sec.",
  1573.     /*25*/"ENVELOPE DECAY 1 DURATION. During this phase the envelope drops to the breakpoint level, unless the breakpoint level "
  1574.         +"is 1, in which case this phase is skipped, the breakpoint is ignored, and the envelope behaves as a traditional "
  1575.         +"ADSR envelope, with dec2 setting the decay duration. Duration is scaled logarithmically in the same way for all "
  1576.         +"envelope phase durations, as follows: 0=3ms, 16=10ms, 32=32ms, 48=102ms, 64=327ms, 80=1sec, 96=3.3sec max=31sec.",
  1577.     /*26*/"ENVELOPE DECAY DURATION. During this phase the envelope drops to the sustain level. Duration is scaled "
  1578.         +"logarithmically in the same way for all envelope phase durations, as follows: 0=3ms, 16=10ms, 32=32ms, 48=102ms, "
  1579.         +"64=327ms, 80=1sec, 96=3.3sec max=31sec.",
  1580.     /*27*/"ENVELOPE BREAKPOINT. Level, as a fraction of the gale level. If you do not want a breakpoint, "
  1581.         +"set this to 1. See the dec1 tip.",
  1582.     /*28*/"ENVELOPE DECAY 2 DURATION, during which the output level transitions from  breakpoint level to sustain level. While "
  1583.         +"conventionally called 'decay 2', the output level may actually rise if the breakpoint is lower than the sustain "
  1584.         +"level. Duration is scaled logarithmically in the same way for all envelope phase durations, as follows: "
  1585.         +"0=3ms, 16=10ms, 32=32ms, 48=102ms, 64=327ms, 80=1sec, 96=3.3sec max=31sec.",
  1586.     /*29*/"ENVELOPE SUSTAIN. Level, as a fraction of the gale level, except for Envelope 3, which has unity gain. ",
  1587.     /*30*/"ENVELOPE RELEASE DURATION. Duration is scaled logarithmically in the same way for all envelope phase durations, "
  1588.         +"as follows: 0=3ms, 16=10ms, 32=32ms, 48=102ms, 64=327ms, 80=1sec, 96=3.3sec max=31sec.",
  1589.     /*31*/"GLIDE/GLISSANDO RATE. To determine the actual rate, the tempo is divided by this number of quarter notes.",
  1590.     /*32*/"GLISSANDO PATTERN. This pattern is repeated over the glissando range, and reverses when the glissando "
  1591.         +"direction is down. All tetrad combinations are available. ",
  1592.     /*33*/"MODULATION GANG sets the range for all matrix nodes with LOW enabled simultaneously.",
  1593.     /*34*/"MODULATION SOURCE. All sources are polyphonic and unipolar, except for LFOs, which are bipolar.",
  1594.     /*35*/"MODULATION DESTINATION. Pitch destinations are in semitones. Tunes are in cents. Choosing MATRIX LEVELS "
  1595.         +"allows modulation of another matrix modulation's output level. Either setting the source off, or the "
  1596.         +"destination off, or the amount to zero saves some CPU.  CONSTANT provides a linear 0~1 value for "
  1597.         +"scaling destinations. PARABOLA and INVERTED PARABOLA are like CONSTANT, but shape the output value in a curve.",
  1598.     /*36*/"MODULATION AMOUNT as a percentage of the source signal. Negative values invert the modulation. If either "
  1599.         +"the source, destination, or level is off, CPU usuage is reduced. LFOs and bend are bipolar; other sources "
  1600.         +"are unipolar. The design proivides maximum modulation range for all contrlols. When the accumulated value "
  1601.         +"for a destination exceeds its possible range, the value is clipped.",
  1602.     /*37*/"MODULATION LO. Reduces the range of the modulation output to provide finer control at lower settings. "
  1603.         +"The range is set by the GANG value. Changing the GANG value changes the range for all matrix nodes with LOW enabled.",
  1604.     /*38*/"ENVELOPE MODE. Env1 is the amplitude envelope in all modes. "
  1605.         +"* SINGLE. only retriggers the envelope if no other notes are playing (note pitch is still changed regardless). "
  1606.         +"* LOOP. is like SINGLE, but when the envelope reaches the end of the decay phase, "
  1607.         +"the attack phase restarts from the sustain level. CLOCK. The envelope retriggers from the clock.",
  1608.     /*39*/"ENVELOPE LEVEL SENSITIVITY to note velocity. At 0, the envelope level is 1. At 1, the envelope level is "
  1609.         +"directly set by velocty. As 2, the envelope level is double velocity. Intermediate settings provide "
  1610.         +"intermediate values.",
  1611.     /*40*/"LFO SYNC. When enabled, a positive gate transition resets the LFO to the beginning of its wave.",
  1612.     /*41*/"LFO WAVEFORM. * Off: Disables the wave, reducing CPU usage. * Sine/2sine: A sine fades from the base "
  1613.         +"frequency, to an equal mix of the base frequency plus a sinewave one active higher. * Ramp/Triangle: "
  1614.         +"Varies between downward-falling sawtooth, through triangle, to upward-rising sawtooth. * Pulse/Square: "
  1615.         +"Varies between an up-rising pulse, through square, to a down-falling pulse. * S&H: A random sample-and-hold "
  1616.         +"signal, varying to noise. ",
  1617.     /*42*/"OSC SYNC. Sync is available on all waveforms except noise. "
  1618.         +"* OFF: no sync."
  1619.         +"* GATE: note-on events reset the wave tp the phase set by PHASE. "
  1620.         +"* SOFT: when the other oscillator crosses zero, it resets this oscillator "
  1621.             + "if this oscillator's output level is above that set by PHASE. "
  1622.         +"* RAMP~ like SOFT, but uses this oscillator's duty cycle instead of level. "
  1623.         +"* SOFTER and RAMPER are similar, but both oscillators must be over PHASE for reset to occur.",
  1624.     /*43*/"BEND. pitch bend. When clicking and dragging the pannel control, then releasing it, the bend slowly returns "
  1625.         +"to center like it is on a spring. See the SETTINGS panel to set spring sensitivity.",
  1626.     /*44*/"WHEEL. mod wheel in range 0~100.",
  1627.     /*45*/"FOOT. MIDI foot controller in range 0~100",
  1628.     /*46*/"SUSTAIN. MIDI sustain pedal (off or on).",
  1629.     /*47*/"PORTAMENTO. MIDI portamento pedal (off or on).",
  1630.     /*48*/"SOSTENUTO. MIDI sostenuto pedal (off or on).",
  1631.     /*49*/"SOFT. MIDI soft pedal (off or on).",
  1632.     /*50*/"HOLD. MIDI hold pedal (off or on).",
  1633.     /*51*/"OSC FM PITCH TRACKING. * When 0 there's no tracking. * When 1, FM depth tracks keyboard pitch exactly. "
  1634.         +"* At 2 it tracks twice as much. Typically tracking is set to 0 or 1, in the latter case, "
  1635.         +"with an offset added by FM depth. For example with tracking at 1 and FM depth at 12, "
  1636.         +"the modulator is one octave above the carrier. Tracking can be set below 1 to reduce harmonics "
  1637.         +"in higher-pitched notes, or vice versa.",
  1638.     /*52*/"COMB PITCH TRACK. At 0, there's no pitch track. "
  1639.         +"* At 1, the delay exactly matches the wavelength of an oscillator set to note pitch. "
  1640.         +"At values lower than 1, delay tracks less than pitch. "
  1641.         +"* At values higher than 1, delay tracks higher than pitch. Tracking delays are added to the base filter delay.",
  1642.     /*53*/"FILTER TRACK. Sets the amount of the filter cutoff point tracks note pitch. "
  1643.         +"* At 0, there's no keyboard tracking. "
  1644.         +"* At 1, the filter tracks the keyboard pitch exactly. "
  1645.         +"At 2, the tracking is twice the note pitch.",
  1646.     /*54*/"GLIDE/GLISSANDO MODE. * Glide Fixed, Gliss fixed: the rate of glide or glissando depends on the number of "
  1647.         +"intervening note,s that is, the rate for each note in the glide or glissando is fixed. * Glide auto, Gliss "
  1648.         +"auto: the rate is always the same, regardless the amount of difference between the current and previous note. "
  1649.         +"tempo. base tempo in bpm, also used for the delay times and the envelopes in clocked mode.",
  1650.     /*55*/"SCALE AND KEY. Thids effects notes from the keyboard, arpeggiator, and pitch from glissando. "
  1651.         +"When 'chromatic', no scale is applied. With other settings, the notes "
  1652.         +"are those in the chosen scale and key.",
  1653.     /*56*/"TEMPO in bpm. The tempo drives the arpeggiator rate, glide/glssando rate, delay time, "
  1654.         +"and the envelopes when they are in clocked mode.",
  1655.     /*57*/"MONITOR. With the MON control in the center of the synth panel, you can monitor taps throughout the design. "
  1656.         +"The amp envelope and amp modulation is applied to all modes."
  1657.         +"* OSC1~2 outputs only one oscillator (any sync and FM from the other oscillator will still be enabled). "
  1658.         +"* OSC3 plays both oscillators after pan. "
  1659.         +"* COMB outputs that comb filters, enabling both oscillators to feed it. "
  1660.         +"* FILT1 adds filter 1 output."
  1661.         +"* FILT2 enables the 2nd filter without any serial feed from the 1st. "
  1662.         +"* SYNTH outputs both filters with serial~parallel mix and pan. "
  1663.         +"* EFFECTS adds the effects chain.",
  1664.     /*58*/"CHORD SELECT. Selects the chord which may be added to base notes from keyboard/MIDI and/or arpeggiator. ",
  1665.     /*59*/"CHORD NOTE VELOCITES. Scales the relative velocity of notes added by the chord generator."
  1666.         +"*When 1, the velocity is the same. Lower and higher values decrease and increase the velocities, respectively",
  1667.     /*60*/"CHORD NOTE DURATIONS. Scales the relative durations of notes added by the chord generator for arpeggiations. "
  1668.         +"*When 1, the duration is the same. Lower and higher values decrease and increase the duration, respectively",
  1669.     /*61*/"CHORD ENABLE. If a chord is selected, enables the chord generation separately for notes from keyboard/MIDI "
  1670.         +"and from the arpeggiator. ",
  1671.     /*62*/"NOTE TRANSPOSE. This affects the notes from keyboard/MIDI, arpeggiator, and chord generator at the time the "
  1672.         +"notes start. ",
  1673.     /*63*/"ARPEGGIATOR ON. When enabled, any playing notes are first turned off, then notes are loaded from the program store "
  1674.         +"and sequenced in the order originally played. Up to 32 notes may be stored in the arpeggiation sequence. "
  1675.         +"When HOLD is enabled, the same notes may be stored in the arpeggiation multiple times",
  1676.     /*64*/"ARPEGGIATOR PATTERN. This alters the order in which notes are played by the arpeggiator",
  1677.     /*65*/"ARPEGGIATOR MODULO. This adds a modulo to the notes from the arpeggiator, and only plays them on modulo increments, "
  1678.         +"allowing the creation of complex algorithmic patterns. ",
  1679.     /*66*/"ARPEGGIATOR NOTE COUNT. * AUTO: the same number of notes are played as stored. * Lower values cause the arpeggiation "
  1680.         +"sequence to be truncated. Higher values cause rests to be added into the sequence. ",
  1681.     /*67*/"ARPEGGIATOR NOTE DURATION. Set as percentage of the arpegiation rate. At values higher than 100%, the notes overlap.",
  1682.     /*68*/"ARPEGGIATOR RATE. Set as number of dotted and/or triplets with tempo division.",
  1683.     /*69*/"DELAY OUTPUT MIX. On delay1, it sets the mix of the filter output with the delay output. On delay 2, the first "
  1684.         +"delay's output is mixed with the first delay's output. When MIX is 0, the effect is bypassed and CPU reduced.",
  1685.     /*70*/"DELAY TIME for the left and right channels is set separately in quarter-note units. The TEMPO sets the duration "
  1686.         +"of a single note. * When 0, the delay line is bypassed, so either the left or right or both source inputs can be "
  1687.         +"delayed or not, as desired. * When 4/1, the delay is one beat. * When 4/4, the delay is a quarter beat. * When 4/32, "
  1688.  
  1689.         +"the delay is a 32nd note.",
  1690.     /*71*/"DELAY INPUT PAN. * When 0, the left source channel goes to the left delay line, and the right source channel "
  1691.         +"goes to the right delay line. * At center, the left and right channels are mixed equally to the delay lines. "
  1692.         +"* When max, the inputs are swapped - the left input goes to the right delay line, and the right input goes to "
  1693.         +"the left. For delay1, the source is the filter. for delay2, the source is delay1.",
  1694.     /*72*/"DELAY CROSS FEEDBACK. * When 0, the left and right delay lines act as two separate mono delay lines. "
  1695.         +"* When max, all delay from the left delay line goes to the right delay line, and vice versa. "
  1696.         +"* Intermediate values mix the amount of mono and cross feedback.",
  1697.     /*73*/"DELAY FEEDBACK AMOUNT. * When 0, there is no feedback, and the source is delayed only once. * The max value is "
  1698.         +"just below self oscillation.",
  1699.     /*74*/"DELAY FILTER. The cutoff point, in MIDI units, for 1-pole static filters on the inputs to the delay lines.",
  1700.     /*75*/"CHORUS OUTPUT MIX. * At 0, the chorus is disabled and CPU reduced. * At max, the output is only chorus. * At "
  1701.         +"intermediate values the input is mixed with the chorus output. Both left and right channels are controlled "
  1702.         +"by the mix in the same way.",
  1703.     /*76*/"CHORUS BASE DELAY. Set in milliseconds, around which the modulations work. ",
  1704.     /*77*/"CHORUS BASE FREQUENCY, in HZ.",
  1705.     /*78*/"CHORUS DELAY SPREAD. * At zero, all eight chorus delay lines have the same base delay. * At higher values, the "
  1706.         +"base delay varies increasingly across each delay line.",
  1707.     /*79*/"CHORUS MODULATION FREQUENCY SPREAD. * At 0 the 8 chorus modulators have the same frequency. *At 1 they are spread "
  1708.         +"the most.",
  1709.     /*80*/"CHORUS MODULATION DEPTH. * At zero, the sine waves have no effect on the chorus output. "
  1710.         +"* At higher values, the amount of modulation increases.",
  1711.     /*81*/"REVERB OUTPUT MIX. At 0, the reverb is disabled and cpu reduced. At max, the output is only reverb. At "
  1712.         +"intermediate values the input is mixed with the reverb output. Both left and right channels are controlled "
  1713.         +"by the mix in the same way.",
  1714.     /*82*/"REVERB PREDELAY. Base delay for early reflections, in milliseconds.",
  1715.     /*83*/"REVERB FILTER. Early reflection filtering. * At zero there is no filtering. * At higher values the amount of early "
  1716.         +"reflections are increasingly reduced.",
  1717.     /*84*/"REVERB DAMP. Damps late reflections, which can truncate their duration at higher settings.",
  1718.     /*85*/"REVERB SIZE. The duration of the late reflections",
  1719.     /*86*/"LIMITER ENABLE. When off, the effect is bypassed and CPU reduced.",
  1720.     /*87*/"LIMITER LEVEL. When the input signal exceeds this level, the output signal is adjusted not to exceed this level. "
  1721.         +"When the signal is below this level, the limiter turns off any gain reduction. There are separate limiters "
  1722.         +"on the left and right channels.",
  1723.     /*88*/"LIMITER WINDOW, The time period over which the input level is sampled before any change in limiting level occurs.",
  1724.     /*89*/"LIMITER RESPONSE. when the signal level rises, and the signal was above the limit level in the last sample "
  1725.         +"window, this sets the number of milliseconds over which the limiter increases the gain reduction.",
  1726.     /*90*/"LIMITER RELEASE. when the signal level falls, and the signal was above the limit level in the last sample "
  1727.         +"window, the sets the number of milliseconds over which the limiter reduces the gain reduction.",
  1728.     /*91*/"LFO LEVEL. Displays the current LFO output level for the most recent voice.",
  1729.     /*92*/"ENVELOPE LEVEL. Displays the current envelope level for the most recent voice. ",
  1730.     /*93*/"LFO DISPLAY. Displays the current waveform shape for the most recent voice.",
  1731.     /*94*/"OSCILLATOR DISPLAY. For most oscillator types, displays current oscillator waveform. "
  1732.         +"For Karplus oscillators, displays a wave representation of the amount of damping. "
  1733.         +"For noise oscillators, displays the frequency response curve of the noise filter.",
  1734.     /*95*/"FILTER DISPLAY. The two filters are identical and continuously variable in five dimensions. "
  1735.         +"The filters used table-based gain compensation with adjustable gain/saturation depending on the drive setting",
  1736.     /*96*/"TOGGLE-MODE KEYBOARD. Click a note to turn it on. Click again to turn it off. Click and drag to make a "
  1737.         +"glissando. When you click a note while another is on, envelopes in SINGLE and LOOP mode don't retrigger. "
  1738.         +"Also displays current arpeggiated notes (in yellow, or green if overlapping with current held note). ",
  1739.     /*97*/"AUDIO, Turns audio on and off",
  1740.     /*98*/"TIPS. Turn off in SETTINGS panel if you don't want to see tips when the mouse is over a panel control.",
  1741.     /*99*/"SCOPES Displays the current waveform output for left (red) and right(green) channels. ",
  1742.     /*100*/"MODULATION OFF. Sets the modulation amount slider to zero.",
  1743.     /*101*/"Quick oscillator wave select. Spins the list box. The panel displays the currently output waveform. "
  1744.         + "Waveforms change at zero-crossings, so waveforms can be modulated at audio rate without introducing clicks",
  1745.     /*102*/"PRESET. Hover over bubbles to see program number. Clicking on the bubbles opens a preset. "
  1746.         +"Shift-clicking a bubble saves a program to that slot. "
  1747.         +"You can also use the PRESET# to enter presets and see the current preset selection.",
  1748.     /*103*/"DEFAULT. button to set all paramaters to default values (does not affect preset).",
  1749.     /*104*/"DELETE. deletes the currently selected program",
  1750.     /*105*/"STORE. stores the currently selected preset in the same preset slot, together with the keyboard state "
  1751.         + "(note on or off). If stored with note off, and a note is playing when the preset is recalled, "
  1752.         + "the note wiil be turned off.",
  1753.     /*106*/"RESTORE. Recalls the current preset, discarding any panel changes to it.",
  1754.     /*107*/"WELCOME TO YOFIEL SYNTHCORE ** Synthcore has its own Audio and MIDI settings panel Please check its "
  1755.         +"settings tab on first lanch ** Hover over controls for more tips."
  1756.     ];
  1757. }
  1758. function getTip(s){ 
  1759.     s = s.toString();
  1760.     var i = params.indexOf(s);
  1761.     if(i > -1){
  1762.         i = tipstr[0][i];
  1763.         //if(dbg) post('getTip()', s, i, '\n');
  1764.         return tipstr[4][i];
  1765.     }else{
  1766.         i = displayParams.indexOf(s);
  1767.         if(i > -1){
  1768.             i = tipstr[1][i];
  1769.             //if(dbg) post('getTip()', s, i, '\n');
  1770.             return tipstr[4][i];
  1771.         }else{
  1772.             i = tipstr[2].indexOf(s);
  1773.             if(i > -1){
  1774.                 i = tipstr[3][i];
  1775.                 //if(dbg) post('getTip()', s, i, '\n');
  1776.                 return tipstr[4][i];
  1777.             }
  1778.         }
  1779.     }
  1780.     return "PANEL TIPS: ** For precise control, click on dials and enter values numerically "
  1781.         +"with your keyboard; or use UP & DOWN change values by single increments. ** Dials with triangles have center "
  1782.         +"defaults. When highlighted, the dial is at its default value. Click on the triangle to jump the dial "
  1783.         +"to its center.";
  1784. }
  1785. var tiptask = 0;
  1786. var tipnamenew = '0'; 
  1787. var tipnameold = 'tip';
  1788. function hover(s){
  1789.     if(tips){
  1790.         tipnamenew = s;
  1791.     }
  1792. }
  1793. function unfocus(s){
  1794.     tipnamenew = '0';
  1795.     dPnl[54].message('set', "PANEL TIPS: ** For precise control, click on dials and enter values numerically "
  1796.         +"with your keyboard; or use UP & DOWN change values by single increments. ** Dials with triangles have center "
  1797.         +"defaults. When highlighted, the dial is at its default value. Click on the triangle to jump the dial "
  1798.         +"to its center.");
  1799. }
  1800. function dotips(){
  1801.     if(tipnamenew != '0' && tipnamenew != tipnameold) {
  1802.         args    = [];
  1803.         args[0] = tipnamenew;
  1804.         tiptask = new Task(tippipe, this, args);
  1805.         tiptask.schedule(199);
  1806.         //if(dbg) post(tipnamenew +'\n');
  1807.         tipnameold = tipnamenew;
  1808.     }
  1809. }
  1810. function tippipe(){
  1811.     var tipname = arguments[0];
  1812.     //if(dbg) post('tippipe()', tipname, tipnamenew, '\n');
  1813.     if(tipnamenew == tipname){
  1814.         dPnl[54].message('set', getTip(tipname));
  1815.         //if(dbg) post('tippipe()', getTip(tipname),'\n');
  1816.     }
  1817. }
  1818. //-----------------------------------------------------------------------------
  1819. // SETTINGS PANEL TIPS
  1820. //-----------------------------------------------------------------------------
  1821. var settingsTipText = [];
  1822. declareattribute('settingsTipText','getSettingsTipText','setSettingsTipText');
  1823. function getSettingsTipText(i){
  1824.     return settingsTipText[i];
  1825. }
  1826. function setSettingsTipText(){
  1827.     settingsTipText[0] ='MIDI port and channel selection.';
  1828.     settingsTipText[1] ='MIDI enable for input and output.';
  1829.     settingsTipText[2] ='Driver settings. As the entire instrument is in compiled code, ' 
  1830.         +'you do not need a small signal vector size. Generally you can set both I/O and signal '
  1831.         +'vector size to 256 for better performance. The tempo clock is also in compiled code, '
  1832.         +'so you do not need overdrive.';
  1833.     settingsTipText[3] ='Bend sensitivity in semitones.';
  1834.     settingsTipText[4] ='Audio and MIDI settings.'; 
  1835.         +'* Note on/off, program change, bend, mod wheel, volume, foot controller, '
  1836.         +'sustain, hold, soft, portamento, sostenuto, and "all notes off" are supported.';
  1837.     settingsTipText[5] ='Opens a file dialog window to store and load preset banks.';
  1838.     settingsTipText[6] ='UI display.'
  1839.         + '* ALWAYS: all scopes and panel indicators are on all the time.' 
  1840.         + '* ONLY WHEN NOTE ON: turns on the scopes and indicators when a note starts,' 
  1841.             + ' then freezes them, when the amplitude envelope reaches zero.' 
  1842.         + '* NEVER: all scopes and panel indicators are disabled to reduce CPU usage.';
  1843. }
  1844. function focusSettings(){
  1845.     return 0;
  1846. }
  1847. function unfocusSettings(){
  1848.     return 0;
  1849. }
  1850. //-----------------------------------------------------------------------------
  1851. // TASKS 
  1852. //-----------------------------------------------------------------------------
  1853. function startTasks(){
  1854.     taskinit= new Task(ticker,this);                        //set up tasks
  1855.     taskinit.interval = 40;
  1856.     taskinit.repeat(-1);
  1857.     if(dbg) post('tasks started, ui is ', ui, '\n');
  1858. }
  1859. function ticker(){
  1860.     if(dbg==2) outlet(4,'start');
  1861.     y = setmute();
  1862.     draw(y);
  1863.     dotips();
  1864.     winresize();
  1865.     if(dbg==2) outlet(4,'end');
  1866.  
  1867. }
  1868. var zChan=1
  1869. function setmute(){
  1870.     if(dbg) dPnl[43].message('set',drawbuf.peek(1,44,1)); 
  1871.     // dPnl[43].message(drawbuf.peek(1,43,1) );
  1872.     x = drawbuf.peek(2,0,vmax+1);// get audio state, inc. 0 offset
  1873.     var y = ui;
  1874.     lastv = age.indexOf(1);
  1875.     if(lastv != zlastv){
  1876.         outlet(0,'lastv',lastv);
  1877.         zlastv = lastv;
  1878.     }
  1879.     zChan = curChan;
  1880.     for(var i=1; i <= vmax; i++){    // set up mutes
  1881.         if(i >4 && x[i]==0 && lvl[i]>0 ){
  1882.             xchange.poke(i, 0, dspBlckClr);
  1883.             xchange.poke(i +vmax, 0, dspBlckClr);
  1884.             outlet(0,'mute',i,1);
  1885.             //if(dbg) post('setmute',i,'\n');
  1886.         }    
  1887.         lvl[i] = x[i];
  1888.     }
  1889.     if(y==1 && numv ==0){
  1890.          y = 0;
  1891.     }
  1892.     //outlet(0,'mutemap',1);
  1893.     if(dbg) outlet(4,x.slice(1,vmax+1));
  1894.     return y;
  1895. }
  1896. function draw(en){
  1897.     if(en >0){                                // display
  1898.         var y;
  1899.         x = drawbuf.peek(1,0,41);
  1900.         //if(dbg) post(x, '\n');        
  1901.         for(var i=1; i<27; i++){
  1902.             y = x[i];//mtx 1-15,lfo 16-18,del 19-22,23 tmpo
  1903.             if(y != zdraw[i]){
  1904.                 dPnl[i].message('set', y);
  1905.                 zdraw[i] = y;        
  1906.                 if(i>23 && zdraw[i]==0){// 24-26 env
  1907.                     dPnl[i].message('peakreset');
  1908.                 }
  1909.             }
  1910.         }
  1911.         for(i=27; i<35; i++){    // 27-34 chorus LEDs
  1912.             dPnl[i].message('offcolor',x[i],0.,0.);
  1913.         }
  1914.         for(i=35; i<38; i++){    // 35-37 lfo wave display
  1915.             y = x[i];
  1916.             if(y != zdraw[i]){
  1917.                 dPnl[i].message('refer','wavesets',1, y, y+5.805);
  1918.                 zdraw[i] = y;
  1919.             }
  1920.         }
  1921.         for(i=38; i<41; i++){    // 38-40 osc wave display
  1922.             y = x[i]; 
  1923.             if(y != zdraw[i]){
  1924.                 if(y>=0){
  1925.                     dPnl[i].message('refer','wavesets',1, y, y+5.805);
  1926.                 }else{
  1927.                     switch(i){
  1928.                         case 35: dPnl[i].message(drawbuf3); break;
  1929.                         case 36: dPnl[i].message(drawbuf4); break;
  1930.                         case 37: dPnl[i].message(drawbuf5); break;
  1931.                     }
  1932.                 }
  1933.                 zdraw[i] = y;
  1934.             }
  1935.         }//41-42 filt display managed in gen
  1936.         if(scopeflag==1){
  1937.             outlet(3, 'trigger',1);
  1938.             scopeflag = 0;
  1939.         }
  1940.     }else{                                    // clear scopes
  1941.         if(scopeflag==0){
  1942.             outlet(3, 'trigger',0);
  1943.             scopeflag = 1;
  1944.         }
  1945.     }
  1946. }

Availability

Synthcore 2.1 is currently available on private request to MAX/MSP owners. To obtain a copy, please place your request with the contact form on this site, after registering.