Added second data set

Added second data set

/*
Data on Acid hack

Iain Emsley

SSI hack March 2015

*/

Flute flute => Pan2 p => PoleZero f => JCRev r => dac;
.8 => r.gain;
.05 => r.mix;
.99 => f.blockZero;

.2 => float timeSt;
//recording
dac => Gain g => WvOut w => blackhole;

// print out all arguments
me.arg(0) => string original;
me.arg(1) => string copy;
me.arg(2) => string outname;

int texta[5000];
int textb[5000];
int size;
//create the array and push into a variable
readInts(original) @=> texta;
readInts(copy) @=> textb;

outname => w.wavFilename;

// any gain you want for the output
.5 => g.gain;

//start recording
1 => w.record;

for (0 => int i; i<size;i++) {
      play(flute,texta[i],.5,p,-1);
      play(flute,textb[i],.5,p,1);
}

//stop recording
0 => w.record;

// temporary workaround to automatically close file on remove-shred
null @=> w;

// play the note
// play the note
fun void play(Flute flute, int note, float velocity, Pan2 p, float textpan) {
    // start the note
    Std.mtof( note ) => flute.freq;
    velocity => flute.noteOn;
    .6      => flute.gain;
    textpan => p.pan;
    100::ms => now;
    velocity => flute.noteOff;

}

// read the ints into an array
// http://wiki.cs.princeton.edu/index.php/ChucK/Dev/IO/FileIO
fun int[] readInts(string path) {

    // open the file
    FileIO file;
    if (!file.open(path, FileIO.READ)) {
        <<< "file read failed" >>>;
        <<< path >>>;
        int ret[0]; // error opening the specified file
        return ret;
    }

    // read the size of the array
    file => size;
    // now read in the contents
    int ret[size];
    for (0 => int i; i < size; i++)
        file => ret[i];

    file.close();
    return ret;
}

/*
Data on Acid hack

Iain Emsley

SSI hack March 2015

*/

//SawOsc s => dac;
Flute flute => PoleZero f => JCRev r => dac;
.95 => r.gain;
.05 => r.mix;
.99 => f.blockZero;

.2 => float timeSt;
//recording
dac => Gain g => WvOut w => blackhole;

// print out all arguments
me.arg(0) => string inname;
me.arg(1) => string outname;

int drama[5000];
//create the array and push into a variable
readInts(inname) @=> drama;

outname => w.wavFilename;

// any gain you want for the output
.5 => g.gain;

//start recording
1 => w.record;

for (0 => int i; i<drama.cap();i++) {
      play(flute,drama[i],.5);
}

//stop recording
0 => w.record;

// temporary workaround to automatically close file on remove-shred
null @=> w;

// play the note
fun void play(Flute flute, int note, float velocity) {
    // start the note
    Std.mtof( note ) => flute.freq;
    velocity => flute.noteOn;
    .6      => flute.gain;
    100::ms => now;
    velocity => flute.noteOff;
    //10::ms => now;
}

// read the ints into an array
// http://wiki.cs.princeton.edu/index.php/ChucK/Dev/IO/FileIO
fun int[] readInts(string path) {

    // open the file
    FileIO file;
    if (!file.open(path, FileIO.READ)) {
        <<< "file read failed" >>>;
        <<< path >>>;
        int ret[0]; // error opening the specified file
        return ret;
    }

    // read the size of the array
    //4096 => int size;
    file => int size;
    // now read in the contents
    int ret[size];
    for (0 => int i; i < size; i++)
        file => ret[i];

    file.close();
    return ret;
}


More extensive threshold tests

More extensive threshold tests

<<< ">>> Testing Threshold class", "" >>>;

<<< ">>> Loading class", "">>>;
Threshold thr => dac;
spork ~ thr.on();

<<< ">>> Loading audio files", "">>>;
SndBuf buf;
me.dir() + "/../sounds/test_sound_01.wav" => buf.read;
1 => buf.loop;

<<< ">>> Running test", "">>>;
buf => thr;

<<< "\n--- Current params:", "">>>;
<<< "--- Level: ", "0.75">>>;
0.75 => thr.set_threshold;
10::second => now;

<<< "\n--- Current params:", "">>>;
<<< "--- Level: ", "0.5">>>;
0.5 => thr.set_threshold;
10::second => now;

<<< ">>> Testing Threshold class", "" >>>;

<<< ">>> Loading class", "">>>;
Threshold thr => dac;
0.75 => thr.set_threshold;
spork ~ thr.on();

<<< ">>> Loading audio files", "">>>;
SndBuf buf_1;
me.dir() + "/../sounds/test_sound_01.wav" => buf_1.read;

// TODO change parameters to test if it works
<<< ">>> Running test", "">>>;
buf_1 => thr;
10::second => now;


Stablized

Stablized

class Chord
{
    0=>static int mode;
    0=>int style;
    Chord @ next[];
    int notes[];
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probabilities[][];              //probability for each next state
    Chord @ modulationSequence[][];
    Chord @ modulationChord[];
    int modulationTarget[];
    fun void init(int root, int type, Chord next[], float probabilities[][])
    {
        setRoot(root);
        setType(type);
        setNext(next);
        setProbabilities(probabilities);
        setNotes();
    }
    fun void setRoot(int i)
    {
        i=>root;
    }
    fun void setType(int i)
    {
        i=>type;
    }
    fun void setNext(Chord c[])
    {
        c@=>next;
    }
    fun void setProbabilities(float f[][])
    {
        f@=>probabilities;
    }
    fun Chord getNextChord()
    {
        return getNextChord(mode);
    }
    fun Chord getNextChord(int i)
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        getProbabilities(i)@=>float p[];
        for (0=>int i; i<p.cap()-1;i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return next[next.cap()-1];
    }
    fun float[] getProbabilities(int i)
    {
        return probabilities[i];
    }
    fun string toString()
    {
        [["I","i","Idim","Iaug","Isus4","I7"],
         ["bII","bii"],
         ["II","ii","IIdim","IIaug","IIsus4","II7","ii7"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","iv"],
         ["bV","bv","bVdim","bVaug","bVsus4","bV7","bv7"],
         ["V","v","Vdim","Vaug","Vsus4","V7"],
         ["bVI","bvi"],
         ["VI","vi","VIdim","VIaug","VIsus4"],
         ["bVII","bvii"],
         ["VII","vii"]]@=>string s[][];
        return s[root][type];
    }
    fun void setNotes()
    {
        if (type==0)
        {
            [root,root+4,root+7]@=>notes;
        }
        if (type==1)
        {
            [root,root+3,root+7]@=>notes;
        }
        if (type==2)
        {
            [root,root+3,root+6]@=>notes;
        }
        if (type==3)
        {
            [root,root+4,root+8]@=>notes;
        }
        if (type==4)
        {
            [root,root+5,root+7]@=>notes;
        }
        if (type==5)
        {
            [root,root+4,root+7,root+10]@=>notes;
        }
        if (type==6)
        {
            [root,root+3,root+7,root+10]@=>notes;
        }

    }
    fun int[] getNotesWithin()
    {
        return notes;
    }
    fun void setModulation(Chord modulation[][], int target[], Chord chord[])
    {
        modulation@=>modulationSequence;
        target@=>modulationTarget;
        chord@=>modulationChord;
    }
    fun Chord[][] getModulationSequence()
    {
        return modulationSequence;
    }
    fun int[] getModulationTarget()
    {
        return modulationTarget;
    }
    fun Chord[] getModulationChord()
    {
        return modulationChord;
    }
}

class IntList
{
    0=>int size;
    IntNode @ first;
    IntNode @ last;

    fun void offer(int o)
    {
        IntNode n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun int poll()
    {
        if (size==0)
            return -1;
        size--;
        first @=> IntNode n;
        n.next @=> first;
        return n.object;
    }
}
class IntNode
{
    int object;
    IntNode @ next;
    fun void init(int o)
    {
        o=>object;
    }
}
class LinkedList                   //great pain to write a linked list in chuck
{
    0=>int size;
    Node @ first;
    Node @ last;

    fun void offer(Object o)
    {
        Node n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun Object poll()
    {
        if (size==0)
            return null;
        size--;
        first @=> Node n;
        n.next @=> first;
        return n.object;
    }
    fun Object add(Object o[])
    {
        for (0=>int i; i<o.cap(); i++)
        {
            offer(o[i]);
        }
    }
    fun Object getFirst()
    {
        return first.object;
    }
    fun Object getLast()
    {
        return last.object;
    }
}
class Node
{
    Object @ object;
    Node @ next;
    fun void init(Object o)
    {
        o@=>object;
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
Chord I;
Chord I7;
Chord ii;
Chord II;
Chord IIdim;
Chord ii7;
Chord iii;
Chord III;
Chord bv7;
Chord IV;
Chord iv;
Chord V;
Chord V7;
Chord vi;
Chord VI;
Chord Isus4;
Chord VIsus4;
I.init(0,0,[I,ii,III,IV,V,vi,ii7],[[0.1,0.1,0.1,0.3,0.2,0.1,0.1],[0.1,0.1,0.1,0.1,0.1,0.4,0.1]]);
I7.init(0,5,[I7],[[1.0],[1.0]]);
ii.init(2,1,[iii,III,V,vi],[[0.2,0.3,0.4,0.1],[0.4,0.3,0.2,0.1]]);
II.init(2,0,[II],[[1.0],[1.0]]);
IIdim.init(2,2,[V],[[1.0],[1.0]]);
ii7.init(2,6,[I,V],[[0.3,0.7],[0.3,0.7]]);
iii.init(4,1,[V,IV,vi],[[0.4,0.4,0.2],[0.2,0.3,0.5]]);
III.init(4,0,[IV,vi,iv],[[0.5,0.3,0.2],[0.2,0.6,0.2]]);
IV.init(5,0,[I,V,V7,III,bv7],[[0.3,0.3,0.2,0.1,0.1],[0.2,0.4,0.1,0.2,0.1]]);
iv.init(5,1,[IV,V,vi],[[0.3,0.4,0.3],[0.2,0.4,0.4]]);
bv7.init(6,6,[V],[[1.0],[1.0]]);
V.init(7,0,[I,vi,ii,iii,Isus4,V7],[[0.2,0.2,0.1,0.2,0.1,0.2],[0.2,0.1,0.1,0.2,0.2,0.2]]);
V7.init(7,5,[I,vi],[[0.8,0.2],[0.4,0.6]]);
vi.init(9,1,[I,ii,iii,IV,V,IIdim],[[0.2,0.2,0.1,0.3,0.1,0.1],[0.2,0.2,0.2,0.2,0.1,0.1]]);
Isus4.init(0,4,[I],[[1.0],[1.0]]);
VIsus4.init(9,4,[vi],[[1.0],[1.0]]);
VI.init(9,0,[VI,ii],[[0.1,0.9],[0.1,0.9]]);
III.setModulation([[VIsus4]],[-3],[I]);
I.setModulation([[VI],[I7],[VI]],[2,5,7],[I,I,V]);
Rhodey  instruments[4];
IntList beats;
IntList keys;
LinkedList chords;
chords.offer(I);
keys.offer(3);
beats.offer(4);
0=>int rhythmCounter;
fun void generateChords()
{
    chords.getLast() $ Chord @=> Chord lastChord;
    if (lastChord.getModulationSequence()!=null && Math.random2f(0, 1)<0.2)
    {
        lastChord.getModulationSequence()@=>Chord modSqs[][];
        lastChord.getModulationTarget()@=>int modKeys[];
        lastChord.getModulationChord()@=>Chord targetChords[];
        Math.random2f(0,modSqs.cap()) $ int  =>int choice;
        modSqs[choice]@=>Chord modSq[];
        modKeys[choice]=>int keyChange;
        targetChords[choice]@=>Chord targetChord;
        for (0=>int i; i<modSq.cap(); i++)
        {
            chords.offer(modSq[i]);
            keys.offer(keys.last.object);
        }
        chords.offer(targetChord);
        keys.offer((keys.last.object+keyChange+12)%12);
    }
    else
    {
        chords.offer(lastChord.getNextChord(1));
        keys.offer(keys.last.object);
    }
}
fun void generateBeats()
{
    Math.random2f(0,1) => float p;
    if (p<=0.6)
    {
        beats.offer(4);
    }
    else if (p<=0.7)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(2);
    }
    else if (p<=0.8)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
    }
    else if (p<=0.9)
    {
        beats.offer(6);
        beats.offer(2);
    }
    else
    {
        beats.offer(3);
        beats.offer(2);
        beats.offer(3);
    }
}

for (0=>int i; i < instruments.cap(); i++)
{
    instruments[i]=>dac;
}

fun void playChord(Chord current, int key, int beat)
{
    if (beats.size==0)
    {
        generateBeats();
    }
    current.root=>int root;
    current.type=>int type;
    send.startMsg("/key/root/type", "i i i");
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    current.getNotesWithin()@=>int notes[];
    <<< "Chord Name: ", current.toString() >>>;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    <<< "Beats Played: ", beat>>>;
    for (0=>int j;j<beat;j++)
    {
        0.5::second=>now;
        float dyn;
        if (rhythmCounter == 0)
            0.2=>dyn;
        else if (rhythmCounter == 2)
            0.11=>dyn;
        else
            0.07=>dyn;
        Std.mtof(36+(key+notes[0]%12))=>instruments[0].freq;
        dyn=>instruments[0].noteOn;
        for (1=>int i; i < instruments.cap(); i++)
        {
            Std.mtof(48+(key+notes[i%notes.cap()])%12)=>instruments[i].freq;
            if (j==0)
                dyn=>instruments[i].noteOn;
            else if (Math.random2f(0,1)<0.7)
                dyn=>instruments[i].noteOn;
        }
        <<<"beat: ",  rhythmCounter>>>;
        (rhythmCounter+1)%4=>rhythmCounter;
    }
}
while (true)
{
    if (chords.size<5)
    {
        generateChords();
    }
    if (beats.size<5)
    {
        generateBeats;
    }
    playChord(chords.poll()$Chord, keys.poll(), beats.poll());
}

class Chord
{
    0=>static int mode;
    0=>int style;
    Chord @ next[];
    int notes[];
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probabilities[][];              //probability for each next state
    Chord @ modulationSequence[][];
    Chord @ modulationChord[];
    int modulationTarget[];
    fun void init(int root, int type, Chord next[], float probabilities[][])
    {
        setRoot(root);
        setType(type);
        setNext(next);
        setProbabilities(probabilities);
        setNotes();
    }
    fun void setRoot(int i)
    {
        i=>root;
    }
    fun void setType(int i)
    {
        i=>type;
    }
    fun void setNext(Chord c[])
    {
        c@=>next;
    }
    fun void setProbabilities(float f[][])
    {
        f@=>probabilities;
    }
    fun Chord getNextChord()
    {
        return getNextChord(mode);
    }
    fun Chord getNextChord(int i)
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        getProbabilities(i)@=>float p[];
        for (0=>int i; i<p.cap()-1;i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return next[next.cap()-1];
    }
    fun float[] getProbabilities(int i)
    {
        return probabilities[i];
    }
    fun string toString()
    {
        [["I","i","Idim","Iaug","Isus4","I7"],
         ["bII","bii"],
         ["II","ii","IIdim","IIaug","IIsus4","II7","ii7"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","iv"],
         ["bV","bv","bVdim","bVaug","bVsus4","bV7","bv7"],
         ["V","v","Vdim","Vaug","Vsus4","V7"],
         ["bVI","bvi"],
         ["VI","vi","VIdim","VIaug","VIsus4"],
         ["bVII","bvii"],
         ["VII","vii"]]@=>string s[][];
        return s[root][type];
    }
    fun void setNotes()
    {
        if (type==0)
        {
            [root,root+4,root+7]@=>notes;
        }
        if (type==1)
        {
            [root,root+3,root+7]@=>notes;
        }
        if (type==2)
        {
            [root,root+3,root+6]@=>notes;
        }
        if (type==3)
        {
            [root,root+4,root+8]@=>notes;
        }
        if (type==4)
        {
            [root,root+5,root+7]@=>notes;
        }
        if (type==5)
        {
            [root,root+4,root+7,root+10]@=>notes;
        }
        if (type==6)
        {
            [root,root+3,root+7,root+10]@=>notes;
        }

    }
    fun int[] getNotesWithin()
    {
        return notes;
    }
    fun void setModulation(Chord modulation[][], int target[], Chord chord[])
    {
        modulation@=>modulationSequence;
        target@=>modulationTarget;
        chord@=>modulationChord;
    }
    fun Chord[][] getModulationSequence()
    {
        return modulationSequence;
    }
    fun int[] getModulationTarget()
    {
        return modulationTarget;
    }
    fun Chord[] getModulationChord()
    {
        return modulationChord;
    }
}

class IntList
{
    0=>int size;
    IntNode @ first;
    IntNode @ last;

    fun void offer(int o)
    {
        IntNode n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun int poll()
    {
        if (size==0)
            return -1;
        size--;
        first @=> IntNode n;
        n.next @=> first;
        return n.object;
    }
}
class IntNode
{
    int object;
    IntNode @ next;
    fun void init(int o)
    {
        o=>object;
    }
}
class LinkedList                   //great pain to write a linked list in chuck
{
    0=>int size;
    Node @ first;
    Node @ last;

    fun void offer(Object o)
    {
        Node n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun Object poll()
    {
        if (size==0)
            return null;
        size--;
        first @=> Node n;
        n.next @=> first;
        return n.object;
    }
    fun Object add(Object o[])
    {
        for (0=>int i; i<o.cap(); i++)
        {
            offer(o[i]);
        }
    }
    fun Object getFirst()
    {
        return first.object;
    }
    fun Object getLast()
    {
        return last.object;
    }
}
class Node
{
    Object @ object;
    Node @ next;
    fun void init(Object o)
    {
        o@=>object;
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
Chord I;
Chord I7;
Chord ii;
Chord II;
Chord IIdim;
Chord ii7;
Chord iii;
Chord III;
Chord bv7;
Chord IV;
Chord iv;
Chord V;
Chord V7;
Chord vi;
Chord VI;
Chord Isus4;
Chord VIsus4;
I.init(0,0,[I,ii,III,IV,V,vi,ii7],[[0.1,0.1,0.1,0.3,0.2,0.1,0.1],[0.1,0.1,0.1,0.1,0.1,0.4,0.1]]);
I7.init(0,5,[I7],[[1.0],[1.0]]);
ii.init(2,1,[iii,III,V,vi],[[0.2,0.3,0.4,0.1],[0.4,0.3,0.2,0.1]]);
II.init(2,0,[II],[[1.0],[1.0]]);
IIdim.init(2,2,[V],[[1.0],[1.0]]);
ii7.init(2,6,[I,V],[[0.3,0.7],[0.3,0.7]]);
iii.init(4,1,[V,IV,vi],[[0.4,0.4,0.2],[0.2,0.3,0.5]]);
III.init(4,0,[IV,vi,iv],[[0.5,0.3,0.2],[0.2,0.6,0.2]]);
IV.init(5,0,[I,V,V7,III,bv7],[[0.3,0.3,0.2,0.1,0.1],[0.2,0.4,0.1,0.2,0.1]]);
iv.init(5,1,[IV,V,vi],[[0.3,0.4,0.3],[0.2,0.4,0.4]]);
bv7.init(6,6,[V],[[1.0],[1.0]]);
V.init(7,0,[I,vi,ii,iii,Isus4,V7],[[0.2,0.2,0.1,0.2,0.1,0.2],[0.2,0.1,0.1,0.2,0.2,0.2]]);
V7.init(7,5,[I,vi],[[0.8,0.2],[0.4,0.6]]);
vi.init(9,1,[I,ii,iii,IV,V,IIdim],[[0.2,0.2,0.1,0.3,0.1,0.1],[0.2,0.2,0.2,0.2,0.1,0.1]]);
Isus4.init(0,4,[I],[[1.0],[1.0]]);
VIsus4.init(9,4,[vi],[[1.0],[1.0]]);
VI.init(9,0,[VI],[[1.0],[1.0]]);
III.setModulation([[VIsus4]],[-3],[I]);
I.setModulation([[VI],[I7],[VI]],[2,5,7],[I,I,V]);
Rhodey  instruments[4];
IntList beats;
IntList keys;
LinkedList chords;
chords.offer(IV);
keys.offer(3);
beats.offer(4);
0=>int rhythmCounter;
fun void generateChords()
{
    chords.getLast() $ Chord @=> Chord lastChord;
    if (lastChord.getModulationSequence()!=null && Math.random2f(0, 1)<0.2)
    {
        lastChord.getModulationSequence()@=>Chord modSqs[][];
        lastChord.getModulationTarget()@=>int modKeys[];
        lastChord.getModulationChord()@=>Chord targetChords[];
        Math.random2f(0,modSqs.cap()) $ int  =>int choice;
        modSqs[choice]@=>Chord modSq[];
        modKeys[choice]=>int keyChange;
        targetChords[choice]@=>Chord targetChord;
        for (0=>int i; i<modSq.cap(); i++)
        {
            chords.offer(modSq[i]);
            keys.offer(keys.last.object);
        }
        chords.offer(targetChord);
        keys.offer((keys.last.object+keyChange+12)%12);
    }
    else
    {
        chords.offer(lastChord.getNextChord(1));
        keys.offer(keys.last.object);
    }
}
fun void generateBeats()
{
    Math.random2f(0,1) => float p;
    if (p<=0.6)
    {
        beats.offer(4);
    }
    else if (p<=0.7)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(2);
    }
    else if (p<=0.8)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
    }
    else if (p<=0.9)
    {
        beats.offer(6);
        beats.offer(2);
    }
    else
    {
        beats.offer(3);
        beats.offer(2);
        beats.offer(3);
    }
}

for (0=>int i; i < instruments.cap(); i++)
{
    instruments[i]=>dac;
}

fun void playChord(Chord current, int key, int beat)
{
    if (beats.size==0)
    {
        generateBeats();
    }
    current.root=>int root;
    current.type=>int type;
    send.startMsg("/key/root/type", "i i i");
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    current.getNotesWithin()@=>int notes[];
    <<< "Chord Name: ", current.toString() >>>;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    <<< "Beats Played: ", beat>>>;
    for (0=>int j;j<beat;j++)
    {
        0.5::second=>now;
        float dyn;
        if (rhythmCounter == 0)
            0.2=>dyn;
        else if (rhythmCounter == 2)
            0.11=>dyn;
        else
            0.07=>dyn;
        Std.mtof(36+(key+notes[0]%12))=>instruments[0].freq;
        dyn=>instruments[0].noteOn;
        for (1=>int i; i < instruments.cap(); i++)
        {
            Std.mtof(48+(key+notes[i%notes.cap()])%12)=>instruments[i].freq;
            if (j==0)
                dyn=>instruments[i].noteOn;
            else if (Math.random2f(0,1)<0.7)
                dyn=>instruments[i].noteOn;
        }
        <<<"beat: ",  rhythmCounter>>>;
        (rhythmCounter+1)%4=>rhythmCounter;
    }
}
while (true)
{
    if (chords.size<5)
    {
        generateChords();
    }
    if (beats.size<5)
    {
        generateBeats;
    }
    playChord(chords.poll()$Chord, keys.poll(), beats.poll());
}


Update common_functions.ck

Update common_functions.ck

join_int_array

// Machine.add("utilities.ck");

/*
    definitions

    fun void repr_int_array(int arr[]){}
    fun void repr_string_array(string arr[]){}

    fun int random_from(int arr[]){}
    fun int inArray(int token, int arr[]){}
    fun int indexOfClosest(int ival, int arr[]){}
    fun int to_note(string str){}
    fun int[] join_int_arrays(int arr1[], int arr2[]){}
    fun int[] set_from(int arr[]){}
    fun int[] randomArray_from(int arr[], int length){}
    fun int[] range(int start, int end){}
    fun int[] narray(int start, int next, int up_to){}
    fun int[] expand_scale(int scale[], int start_stop[]){
    fun int[][] stepify(string sequence_data[]){}

    fun float average(int arr[]){}

    fun string repr(int arr[]){}
    fun string repr(string arr[]){}
    fun string[] split(string arr, string token){}

    fun SndBuf load_sample(string wavname){}

    https://gist.github.com/anonymous/7206152

*/

fun string[] split_str(string str, string token){

    string collect[0];
    int pos;
    int pos2;
    while( str.find(token) >0){
        str.find(token) => pos2;
        collect << str.substring(pos, pos2);
        str.substring(pos2+1) => str;
    }
    collect << str;
    return collect;
}

fun int random_from(int arr[]){
    return arr[Math.random2(0, arr.cap()-1)];
}

fun int[] join_int_arrays(int arr1[], int arr2[]){
    for(0 => int i; i<arr2.cap(); i++){
        arr1 << arr2[i];
    }
    return arr1;
}

fun int[] randomArray_from(int arr[], int length){
    // return new array of capacity length chosing elements from arr
    int generated_arr[0];
    for(0 => int i; i<length; i++){
        generated_arr << random_from(arr); // append element
    }
    return generated_arr;
}

fun int[] range(int start, int end){
    // includes start and end
    int arr[0];
    for(start => int i; i<=end; i++) arr << i;
    return arr;
}

fun int[] narray(int start, int next, int up_to){
    // (start, end..up_to)  (inclusive)
    int arr[0];
    start => int cval;
    next - start => int jump;
    for(cval; cval<=up_to; jump +=> cval){
        arr << cval;
    }
    return arr;  // matey!
}

fun int[] expand_scale(int scale[], int start_stop[]){

    // assumes we start somewhere above 0
    start_stop[0] => int start;
    start_stop[1] => int end;

    int expand_array[0];
    -1 => int last;
    int current;
    for(start => int i; i < end; i++){
        for(0 => int n; n<scale.cap(); n++){
            // avoids doubles, if the incoming scale ends an
            // octave above the first note
            scale[n] + (i*12) => current;
            if (!(current == last)){
                expand_array << current;
                current => last;
            }
        }
    }
    return expand_array;
}

fun string repr(int arr[]){
    /*
    this returns a string representation of an int array,
    useful for debug printing.
    */
    "[" + Std.itoa(arr[0]) => string s;
    for (1 => int i; i < arr.cap(); i++){
        "," + Std.itoa(arr[i]) +=> s;
    }
    return s + "]";
}

fun string repr(string arr[]){

    //this returns a string representation of a string array,
    //useful for debug printing.

    "[" + arr[0] => string s;
    for (1 => int i; i < arr.cap(); i++){
        "," + arr[i] +=> s;
    }
    return s + "]";
}

fun void repr_int_array(int arr[])
{
    arr.cap() => int num_items;
    chout <= "[";
    for(0 => int i; i<num_items; i++){
        if (i>0) chout <= ",";
        chout <= arr[i];
    }
    chout <= "]";
    chout <= IO.newline();
}

fun void repr_string_array(string arr[])
{
    arr.cap() => int num_items;
    chout <= "[";
    for(0 => int i; i<num_items; i++){
        if (i>0) chout <= ",";
        chout <= arr[i];
    }
    chout <= "]";
    chout <= IO.newline();
}

fun int inArray(int token, int arr[]){
    /*
    tests membership of an array
    */
    for(0 => int i; i<arr.cap(); i++){
        if (arr[i]==token) return 1;
    }
    return 0;
}

fun int to_note(string str){
    if (str == "...") return -1;
    if (str == "OFF") return -2;
    if (str == "===") return -3;

    // check if within supported range
    str.substring(2) => Std.atoi => int oct;
    if (oct < 0 || oct > 10) return -4;

    str.substring(0,2) => str;

    [   "C-","C#","D-","D#","E-","F-",
        "F#","G-","G#","A-","A#","B-"
    ] @=> string notes_list[];

    // note must be in this list, else return -3 at the end
    for (0 => int i; i < notes_list.cap(); i++){
        if (str == notes_list[i]){
            return (i + oct * 12);
        }
    }
    return -5;
}

fun int[][] stepify(string sequence_data[]){
    /*
    this function converts a string array to an int array,
    it accepts fuzzy formatting:
    "1..1..1..1.." becomes [1,0,0,1,0,0,1,0,0,1,0,0]
    "1..1.   .1..1.." also becomes [1,0,0,1,0,0,1,0,0,1,0,0]
    */

    sequence_data.cap() => int parts;
    32 => int steps;  // hard code for now
    <<< parts, steps >>>;

    int data_store[parts][steps];
    for(0 => int i; i<sequence_data.cap(); i++){

        sequence_data[i] => string seq_string;
        int part_data[0];
        int trigger;
        //<<< seq_string >>>;
        for(0 => int j; j < seq_string.length(); j++){
            seq_string.substring(j,1) => string token; // crazy

            if (token == " ") continue;
            if (token == ".") 0 => trigger;
            else if (token == "1") 1 => trigger;

            part_data << trigger;
        }
        //<<< repr_int_array(part_data)>>>;
        part_data @=> data_store[i];
    }
    return data_store;
}

fun SndBuf load_sample(string wavname){

    // usage
    // load_sample("kick_02") @=> SndBuf kick => dac;

    // turn incoming wavname into   path/wavename.wav
    // return a reference to a new buffer object.
    SndBuf temp_buff;
    me.dir() + "/audio/" + wavname  + ".wav" => temp_buff.read;

    // set to end, and set gain, then return the object
    temp_buff.samples() => temp_buff.pos;
    0.8 => temp_buff.gain;
    return temp_buff;
}

fun float average(int arr[]){
    int sum;
    arr.cap() => int num_items;
    for(0 => int i; i < num_items; i++){
        arr[i] +=> sum;
    }
    sum $ float => float fsum;
    num_items $ float => float fcap;
    return fsum / fcap;
}

fun int indexOfClosest(int ival, int arr[]){
    // will find the closest value to ival in arr
    // if there are multiple, it will return the first.
    Math.INT_MAX => int min_distance;
    0 => int diff;
    -1 => int idx_tracker;

    for(0 => int i; i<arr.cap(); i++)
    {
        Math.abs(arr[i] - ival) => diff;
        if (diff < min_distance)
        {
            diff => min_distance;
            i => idx_tracker;
        }
    }
    return idx_tracker;

}

fun int[] set_from(int arr[]){
    // no order guaranteed
    // requires  inArray() to be present.
    int new_arr[0];
    new_arr << arr[0];

    for(1 => int i; i<arr.cap(); i++){
        if (inArray(arr[i], new_arr) == 0){
            new_arr << arr[i];
        }
    }
    return new_arr;
}

// Machine.add("utilities.ck");

/*
    definitions

    fun void repr_int_array(int arr[]){}
    fun void repr_string_array(string arr[]){}

    fun int random_from(int arr[]){}
    fun int inArray(int token, int arr[]){}
    fun int indexOfClosest(int ival, int arr[]){}
    fun int to_note(string str){}
    fun int[] set_from(int arr[]){}
    fun int[] randomArray_from(int arr[], int length){}
    fun int[] range(int start, int end){}
    fun int[] narray(int start, int next, int up_to){}
    fun int[] expand_scale(int scale[], int start_stop[]){
    fun int[][] stepify(string sequence_data[]){}

    fun float average(int arr[]){}

    fun string repr(int arr[]){}
    fun string repr(string arr[]){}
    fun string[] split(string arr, string token){}

    fun SndBuf load_sample(string wavname){}

    https://gist.github.com/anonymous/7206152

*/

fun string[] split_str(string str, string token){

    string collect[0];
    int pos;
    int pos2;
    while( str.find(token) >0){
        str.find(token) => pos2;
        collect << str.substring(pos, pos2);
        str.substring(pos2+1) => str;
    }
    collect << str;
    return collect;
}

fun int random_from(int arr[]){
    return arr[Math.random2(0, arr.cap()-1)];
}

fun int[] randomArray_from(int arr[], int length){
    // return new array of capacity length chosing elements from arr
    int generated_arr[0];
    for(0 => int i; i<length; i++){
        generated_arr << random_from(arr); // append element
    }
    return generated_arr;
}

fun int[] range(int start, int end){
    // includes start and end
    int arr[0];
    for(start => int i; i<=end; i++) arr << i;
    return arr;
}

fun int[] narray(int start, int next, int up_to){
    // (start, end..up_to)  (inclusive)
    int arr[0];
    start => int cval;
    next - start => int jump;
    for(cval; cval<=up_to; jump +=> cval){
        arr << cval;
    }
    return arr;  // matey!
}

fun int[] expand_scale(int scale[], int start_stop[]){

    // assumes we start somewhere above 0
    start_stop[0] => int start;
    start_stop[1] => int end;

    int expand_array[0];
    -1 => int last;
    int current;
    for(start => int i; i < end; i++){
        for(0 => int n; n<scale.cap(); n++){
            // avoids doubles, if the incoming scale ends an
            // octave above the first note
            scale[n] + (i*12) => current;
            if (!(current == last)){
                expand_array << current;
                current => last;
            }
        }
    }
    return expand_array;
}

fun string repr(int arr[]){
    /*
    this returns a string representation of an int array,
    useful for debug printing.
    */
    "[" + Std.itoa(arr[0]) => string s;
    for (1 => int i; i < arr.cap(); i++){
        "," + Std.itoa(arr[i]) +=> s;
    }
    return s + "]";
}

fun string repr(string arr[]){

    //this returns a string representation of a string array,
    //useful for debug printing.

    "[" + arr[0] => string s;
    for (1 => int i; i < arr.cap(); i++){
        "," + arr[i] +=> s;
    }
    return s + "]";
}

fun void repr_int_array(int arr[])
{
    arr.cap() => int num_items;
    chout <= "[";
    for(0 => int i; i<num_items; i++){
        if (i>0) chout <= ",";
        chout <= arr[i];
    }
    chout <= "]";
    chout <= IO.newline();
}

fun void repr_string_array(string arr[])
{
    arr.cap() => int num_items;
    chout <= "[";
    for(0 => int i; i<num_items; i++){
        if (i>0) chout <= ",";
        chout <= arr[i];
    }
    chout <= "]";
    chout <= IO.newline();
}

fun int inArray(int token, int arr[]){
    /*
    tests membership of an array
    */
    for(0 => int i; i<arr.cap(); i++){
        if (arr[i]==token) return 1;
    }
    return 0;
}

fun int to_note(string str){
    if (str == "...") return -1;
    if (str == "OFF") return -2;
    if (str == "===") return -3;

    // check if within supported range
    str.substring(2) => Std.atoi => int oct;
    if (oct < 0 || oct > 10) return -4;

    str.substring(0,2) => str;

    [   "C-","C#","D-","D#","E-","F-",
        "F#","G-","G#","A-","A#","B-"
    ] @=> string notes_list[];

    // note must be in this list, else return -3 at the end
    for (0 => int i; i < notes_list.cap(); i++){
        if (str == notes_list[i]){
            return (i + oct * 12);
        }
    }
    return -5;
}

fun int[][] stepify(string sequence_data[]){
    /*
    this function converts a string array to an int array,
    it accepts fuzzy formatting:
    "1..1..1..1.." becomes [1,0,0,1,0,0,1,0,0,1,0,0]
    "1..1.   .1..1.." also becomes [1,0,0,1,0,0,1,0,0,1,0,0]
    */

    sequence_data.cap() => int parts;
    32 => int steps;  // hard code for now
    <<< parts, steps >>>;

    int data_store[parts][steps];
    for(0 => int i; i<sequence_data.cap(); i++){

        sequence_data[i] => string seq_string;
        int part_data[0];
        int trigger;
        //<<< seq_string >>>;
        for(0 => int j; j < seq_string.length(); j++){
            seq_string.substring(j,1) => string token; // crazy

            if (token == " ") continue;
            if (token == ".") 0 => trigger;
            else if (token == "1") 1 => trigger;

            part_data << trigger;
        }
        //<<< repr_int_array(part_data)>>>;
        part_data @=> data_store[i];
    }
    return data_store;
}

fun SndBuf load_sample(string wavname){

    // usage
    // load_sample("kick_02") @=> SndBuf kick => dac;

    // turn incoming wavname into   path/wavename.wav
    // return a reference to a new buffer object.
    SndBuf temp_buff;
    me.dir() + "/audio/" + wavname  + ".wav" => temp_buff.read;

    // set to end, and set gain, then return the object
    temp_buff.samples() => temp_buff.pos;
    0.8 => temp_buff.gain;
    return temp_buff;
}

fun float average(int arr[]){
    int sum;
    arr.cap() => int num_items;
    for(0 => int i; i < num_items; i++){
        arr[i] +=> sum;
    }
    sum $ float => float fsum;
    num_items $ float => float fcap;
    return fsum / fcap;
}

fun int indexOfClosest(int ival, int arr[]){
    // will find the closest value to ival in arr
    // if there are multiple, it will return the first.
    Math.INT_MAX => int min_distance;
    0 => int diff;
    -1 => int idx_tracker;

    for(0 => int i; i<arr.cap(); i++)
    {
        Math.abs(arr[i] - ival) => diff;
        if (diff < min_distance)
        {
            diff => min_distance;
            i => idx_tracker;
        }
    }
    return idx_tracker;

}

fun int[] set_from(int arr[]){
    // no order guaranteed
    // requires  inArray() to be present.
    int new_arr[0];
    new_arr << arr[0];

    for(1 => int i; i<arr.cap(); i++){
        if (inArray(arr[i], new_arr) == 0){
            new_arr << arr[i];
        }
    }
    return new_arr;
}


more sketching now usable with control!

more sketching now usable with control!

function void drone(int midinote, int t) {
    SinOsc s1 => Gain g => ADSR a => dac;
    SinOsc s2 => g;
    SinOsc s3 => g;
    SinOsc s4 => g;
    1.0 => a.target;
    1000::ms => a.attackTime;
    0.5 => a.sustainLevel;
    1000::ms => a.decayTime;
    1000::ms => a.releaseTime;
    0.25 => g.gain;
    Std.mtof(midinote) => s1.freq;
    2*s1.freq() => s3.freq => s4.freq;
    <<< ("Starting", me.id(), "For", t/1000, "at", s1.freq()) >>>;
    1 => a.keyOn;
    for (0 => int i; i < t; i + 1 => i) {
        s1.freq() * Std.rand2f(0.999,1.001) => s1.freq;
        s1.freq() * Std.rand2f(1.001,1.003) => s2.freq;
        s3.freq() * Std.rand2f(0.999,1.001) => s3.freq;
        s3.freq() * Std.rand2f(1.001,1.003) => s4.freq;
        if (t - 1000 == i) {
            1 => a.keyOff;
            <<< ("Ending", me.id()) >>>;
        }
        1::ms => now;
    }
}

1.001 => float s1m;
1.003 => float s3m;

fun void lfun(SinOsc s1, SinOsc s2, SinOsc s3, SinOsc s4) {
    while(1::ms => now) {
        s1.freq() * Std.rand2f(2.0 - s1m,s1m) => s1.freq;
        s1.freq() * Std.rand2f(s1m,s3m) => s2.freq;
        s3.freq() * Std.rand2f(2.0 -  s1m,s1m) => s3.freq;
        s3.freq() * Std.rand2f(s1m,s3m) => s4.freq;
    }
}
0 => int count;
function void simpledrone(int midinote, int t) {
    SinOsc s1 => Gain g => ADSR a => dac;
    SinOsc s2 => g;
    SinOsc s3 => g;
    SinOsc s4 => g;
    1.0 => a.target;
    1000::ms => a.attackTime;
    0.5 => a.sustainLevel;
    1000::ms => a.decayTime;
    1000::ms => a.releaseTime;
    count + 1 => count;
    //0.25 => g.gain;
    0.25 * 1.0/count => g.gain;
    Std.mtof(midinote) => s1.freq;
    2*s1.freq() => s3.freq => s4.freq;
    <<< ("Starting", me.id(), "For", t/1000, "at", s1.freq()) >>>;
    1 => a.keyOn;
    spork ~ lfun(s1,s2,s3,s4);
    t :: ms => now;
    1 => a.keyOff;
    1000 :: ms => now;
    count - 1 => count;
}

Std.rand2(30,65) => int midi;
Std.rand2(1000,10000) => int t;
spork ~ simpledrone(midi, t);
//10::second => now;

//for ( 0 => i; i < 64;
//Create an OscRecv object:
OscRecv orec;
//Tell the OscRecv object the port:
10000 => orec.port;
//Tell the OscRecv object to start listening for OSC messages on that port:
orec.listen();

function void fourch(OscEvent fourchEvent) {
    while ( true ) {
        <<< "waiting" >>>;
        fourchEvent => now; //wait for events to arrive.
        while( fourchEvent.nextMsg() != 0 ) {
            fourchEvent.getFloat() => float f1;
            fourchEvent.getFloat() => float f2;
            fourchEvent.getFloat() => float f3;
            fourchEvent.getFloat() => float f4;
            <<< (f1,f2,f3,f4) >>>;
            1.0 + 0.25*(f3-64)/64 => s1m;
            1.0 + 0.25*(f4-64)/64 => s3m;
            spork ~ simpledrone(f1 $ int, (f2*500) $ int);
        }
    }
}

function void multiPitchLength(OscEvent multiEvent) {
    while ( true ) {
        <<< "waiting for multi" >>>;
        multiEvent => now; //wait for events to arrive.
        while( multiEvent.nextMsg() != 0 ) {
            <<< "Got Multi" >>>;
            multiEvent.getFloat() * 127 => float f1;
            multiEvent.getFloat() * 127 => float f2;
            <<< (f1,f2) >>>;
            if (count < 40) {
                spork ~ simpledrone(f1 $ int, (20+f2*500) $ int);
                2::ms => now;
            } else {
                <<< "TOO MUCH!" >>>;
                2::ms => now;
            }
        }
    }
}

function void multiRange(OscEvent multiEvent) {
    while ( true ) {
        <<< "waiting for multi" >>>;
        multiEvent => now; //wait for events to arrive.
        while( multiEvent.nextMsg() != 0 ) {
            <<< "Got Multi" >>>;
            multiEvent.getFloat() * 127 => float f1;
            multiEvent.getFloat() * 127 => float f2;
            //<<< (f1,f2) >>>;
            1.0 + 0.25*(f1-64)/64 => s1m;
            1.0 + 0.25*(f2-64)/64 => s3m;
            <<< (s1m,s3m) >>>;
            2::ms => now;
        }
    }
}

orec.event("/mixer/fourch, f, f, f, f") @=> OscEvent fourchEvent;
spork ~ fourch(fourchEvent);
orec.event("/multi/1, f, f") @=> OscEvent multiEvent;
spork ~  multiPitchLength(multiEvent);
orec.event("/multi/2, f, f") @=> OscEvent multiEvent2;
spork ~  multiRange(multiEvent2);

while( true ) {
    10000::ms => now;
    <<< "sleeping" >>>;
}

function void drone(int midinote, int t) {
    SinOsc s1 => Gain g => ADSR a => dac;
    SinOsc s2 => g;
    SinOsc s3 => g;
    SinOsc s4 => g;
    1.0 => a.target;
    1000::ms => a.attackTime;
    0.5 => a.sustainLevel;
    1000::ms => a.decayTime;
    1000::ms => a.releaseTime;
    0.25 => g.gain;
    Std.mtof(midinote) => s1.freq;
    2*s1.freq() => s3.freq => s4.freq;
    <<< ("Starting", me.id(), "For", t/1000, "at", s1.freq()) >>>;
    1 => a.keyOn;
    for (0 => int i; i < t; i + 1 => i) {
        s1.freq() * Std.rand2f(0.999,1.001) => s1.freq;
        s1.freq() * Std.rand2f(1.001,1.003) => s2.freq;
        s3.freq() * Std.rand2f(0.999,1.001) => s3.freq;
        s3.freq() * Std.rand2f(1.001,1.003) => s4.freq;
        if (t - 1000 == i) {
            1 => a.keyOff;
            <<< ("Ending", me.id()) >>>;
        }
        1::ms => now;
    }
}

1.001 => float s1m;
1.003 => float s3m;

fun void lfun(SinOsc s1, SinOsc s2, SinOsc s3, SinOsc s4) {
    while(1::ms => now) {
        s1.freq() * Std.rand2f(2.0 - s1m,s1m) => s1.freq;
        s1.freq() * Std.rand2f(s1m,s3m) => s2.freq;
        s3.freq() * Std.rand2f(2.0 -  s1m,s1m) => s3.freq;
        s3.freq() * Std.rand2f(s1m,s3m) => s4.freq;
    }
}
0 => int count;
function void simpledrone(int midinote, int t) {
    SinOsc s1 => Gain g => ADSR a => dac;
    SinOsc s2 => g;
    SinOsc s3 => g;
    SinOsc s4 => g;
    1.0 => a.target;
    1000::ms => a.attackTime;
    0.5 => a.sustainLevel;
    1000::ms => a.decayTime;
    1000::ms => a.releaseTime;
    count + 1 => count;
    //0.25 => g.gain;
    0.25 * 1.0/count => g.gain;
    Std.mtof(midinote) => s1.freq;
    2*s1.freq() => s3.freq => s4.freq;
    <<< ("Starting", me.id(), "For", t/1000, "at", s1.freq()) >>>;
    1 => a.keyOn;
    spork ~ lfun(s1,s2,s3,s4);
    t :: ms => now;
    1 => a.keyOff;
    1000 :: ms => now;
    count - 1 => count;
}

Std.rand2(30,65) => int midi;
Std.rand2(1000,10000) => int t;
spork ~ simpledrone(midi, t);
//10::second => now;

//for ( 0 => i; i < 64;
//Create an OscRecv object:
OscRecv orec;
//Tell the OscRecv object the port:
10000 => orec.port;
//Tell the OscRecv object to start listening for OSC messages on that port:
orec.listen();

orec.event("/mixer/fourch, f, f, f, f") @=> OscEvent fourchEvent;

while ( true ) {
    <<< "waiting" >>>;
    fourchEvent => now; //wait for events to arrive.
    while( fourchEvent.nextMsg() != 0 ) {
        fourchEvent.getFloat() => float f1;
        fourchEvent.getFloat() => float f2;
        fourchEvent.getFloat() => float f3;
        fourchEvent.getFloat() => float f4;
        <<< (f1,f2,f3,f4) >>>;
        1.0 + 0.1*(f3-64)/64 => s1m;
        1.0 + 0.1*(f4-64)/64 => s3m;
        spork ~ simpledrone(f1 $ int, (f2*500) $ int);
    }
}


debugged chordProgression

debugged chordProgression

class Chord
{
    0=>static int mode;
    0=>int style;
    Chord @ next[];
    int notes[];
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probabilities[][];              //probability for each next state
    Chord @ modulationSequence[][];
    Chord @ modulationChord[];
    int modulationTarget[];
    fun void init(int root, int type, Chord next[], float probabilities[][])
    {
        setRoot(root);
        setType(type);
        setNext(next);
        setProbabilities(probabilities);
        setNotes();
    }
    fun void setRoot(int i)
    {
        i=>root;
    }
    fun void setType(int i)
    {
        i=>type;
    }
    fun void setNext(Chord c[])
    {
        c@=>next;
    }
    fun void setProbabilities(float f[][])
    {
        f@=>probabilities;
    }
    fun Chord getNextChord()
    {
        return getNextChord(mode);
    }
    fun Chord getNextChord(int i)
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        getProbabilities(i)@=>float p[];
        for (0=>int i; i<p.cap()-1;i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return next[next.cap()-1];
    }
    fun float[] getProbabilities(int i)
    {
        return probabilities[i];
    }
    fun string toString()
    {
        [["I","i","Idim","Iaug","Isus4","I7"],
         ["bII","bii"],
         ["II","ii","IIdim","IIaug","IIsus4","II7","ii7"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","iv"],
         ["bV","bv","bVdim","bVaug","bVsus4","bV7","bv7"],
         ["V","v","Vdim","Vaug","Vsus4","V7"],
         ["bVI","bvi"],
         ["VI","vi","VIdim","VIaug","VIsus4"],
         ["bVII","bvii"],
         ["VII","vii"]]@=>string s[][];
        return s[root][type];
    }
    fun void setNotes()
    {
        if (type==0)
        {
            [root,root+4,root+7]@=>notes;
        }
        if (type==1)
        {
            [root,root+3,root+7]@=>notes;
        }
        if (type==2)
        {
            [root,root+3,root+6]@=>notes;
        }
        if (type==3)
        {
            [root,root+4,root+8]@=>notes;
        }
        if (type==4)
        {
            [root,root+5,root+7]@=>notes;
        }
        if (type==5)
        {
            [root,root+4,root+7,root+10]@=>notes;
        }
        if (type==6)
        {
            [root,root+3,root+7,root+10]@=>notes;
        }

    }
    fun int[] getNotesWithin()
    {
        return notes;
    }
    fun void setModulation(Chord modulation[][], int target[], Chord chord[])
    {
        modulation@=>modulationSequence;
        target@=>modulationTarget;
        chord@=>modulationChord;
    }
    fun Chord[][] getModulationSequence()
    {
        return modulationSequence;
    }
    fun int[] getModulationTarget()
    {
        return modulationTarget;
    }
    fun Chord[] getModulationChord()
    {
        return modulationChord;
    }
}

class IntList
{
    0=>int size;
    IntNode @ first;
    IntNode @ last;

    fun void offer(int o)
    {
        IntNode n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun int poll()
    {
        if (size==0)
            return -1;
        size--;
        first @=> IntNode n;
        n.next @=> first;
        return n.object;
    }
}
class IntNode
{
    int object;
    IntNode @ next;
    fun void init(int o)
    {
        o=>object;
    }
}
class LinkedList                   //great pain to write a linked list in chuck
{
    0=>int size;
    Node @ first;
    Node @ last;

    fun void offer(Object o)
    {
        Node n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun Object poll()
    {
        if (size==0)
            return null;
        size--;
        first @=> Node n;
        n.next @=> first;
        return n.object;
    }
    fun Object add(Object o[])
    {
        for (0=>int i; i<o.cap(); i++)
        {
            offer(o[i]);
        }
    }
    fun Object getFirst()
    {
        return first.object;
    }
    fun Object getLast()
    {
        return last.object;
    }
}
class Node
{
    Object @ object;
    Node @ next;
    fun void init(Object o)
    {
        o@=>object;
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
Chord I;
Chord I7;
Chord ii;
Chord II;
Chord IIdim;
Chord ii7;
Chord iii;
Chord III;
Chord bv7;
Chord IV;
Chord iv;
Chord V;
Chord V7;
Chord vi;
Chord VI;
Chord Isus4;
Chord VIsus4;
I.init(0,0,[I,ii,III,IV,V,vi,ii7],[[0.1,0.1,0.1,0.3,0.2,0.1,0.1],[0.1,0.1,0.1,0.1,0.1,0.4,0.1]]);
I7.init(0,5,[I7],[[1.0],[1.0]]);
ii.init(2,1,[iii,III,V,vi],[[0.2,0.3,0.4,0.1],[0.4,0.3,0.2,0.1]]);
II.init(2,0,[II],[[1.0],[1.0]]);
IIdim.init(2,2,[V],[[1.0],[1.0]]);
ii7.init(2,6,[I,V],[[0.3,0.7],[0.3,0.7]]);
iii.init(4,1,[V,IV,vi],[[0.4,0.4,0.2],[0.2,0.3,0.5]]);
III.init(4,0,[IV,vi,iv],[[0.5,0.3,0.2],[0.2,0.6,0.2]]);
IV.init(5,0,[I,V,V7,III,bv7],[[0.3,0.3,0.2,0.1,0.1],[0.2,0.4,0.1,0.2,0.1]]);
iv.init(5,1,[IV,V,vi],[[0.3,0.4,0.3],[0.2,0.4,0.4]]);
bv7.init(6,6,[V],[[1.0],[1.0]]);
V.init(7,0,[I,vi,ii,iii,Isus4,V7],[[0.2,0.2,0.1,0.2,0.1,0.2],[0.2,0.1,0.1,0.2,0.2,0.2]]);
V7.init(7,5,[I,vi],[[0.8,0.2],[0.4,0.6]]);
vi.init(9,1,[I,ii,iii,IV,V,IIdim],[[0.2,0.2,0.1,0.3,0.1,0.1],[0.2,0.2,0.2,0.2,0.1,0.1]]);
Isus4.init(0,4,[I],[[1.0],[1.0]]);
VIsus4.init(9,4,[vi],[[1.0],[1.0]]);
VI.init(9,0,[VI],[[1.0],[1.0]]);
III.setModulation([[VIsus4]],[-3],[I]);
I.setModulation([[VI],[I7],[VI]],[2,5,7],[I,I,V]);
Rhodey  instruments[4];
IntList beats;
IntList keys;
LinkedList chords;
chords.offer(IV);
keys.offer(3);
beats.offer(4);
0=>int rhythmCounter;
fun void generateChords()
{
    chords.getLast() $ Chord @=> Chord lastChord;
    if (lastChord.getModulationSequence()!=null && Math.random2f(0, 1)<0.2)
    {
        lastChord.getModulationSequence()@=>Chord modSqs[][];
        lastChord.getModulationTarget()@=>int modKeys[];
        lastChord.getModulationChord()@=>Chord targetChords[];
        Math.random2f(0,modSqs.cap()) $ int  =>int choice;
        modSqs[choice]@=>Chord modSq[];
        modKeys[choice]=>int keyChange;
        targetChords[choice]@=>Chord targetChord;
        for (0=>int i; i<modSq.cap(); i++)
        {
            chords.offer(modSq[i]);
            keys.offer(keys.last.object);
        }
        chords.offer(targetChord);
        keys.offer((keys.last.object+keyChange+12)%12);
    }
    else
    {
        chords.offer(lastChord.getNextChord(1));
        keys.offer(keys.last.object);
    }
}
fun void generateBeats()
{
    Math.random2f(0,1) => float p;
    if (p<=0.6)
    {
        beats.offer(4);
    }
    else if (p<=0.7)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(2);
    }
    else if (p<=0.8)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
    }
    else if (p<=0.9)
    {
        beats.offer(6);
        beats.offer(2);
    }
    else
    {
        beats.offer(3);
        beats.offer(2);
        beats.offer(3);
    }
}

for (0=>int i; i < instruments.cap(); i++)
{
    instruments[i]=>dac;
}

fun void playChord(Chord current, int key, int beat)
{
    if (beats.size==0)
    {
        generateBeats();
    }
    current.root=>int root;
    current.type=>int type;
    send.startMsg("/key/root/type", "i i i");
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    current.getNotesWithin()@=>int notes[];
    <<< "Chord Name: ", current.toString() >>>;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    <<< "Beats Played: ", beat>>>;
    for (0=>int j;j<beat;j++)
    {
        0.5::second=>now;
        float dyn;
        if (rhythmCounter == 0)
            0.2=>dyn;
        else if (rhythmCounter == 2)
            0.11=>dyn;
        else
            0.07=>dyn;
        Std.mtof(36+(key+notes[0]%12))=>instruments[0].freq;
        dyn=>instruments[0].noteOn;
        for (1=>int i; i < instruments.cap(); i++)
        {
            Std.mtof(48+(key+notes[i%notes.cap()])%12)=>instruments[i].freq;
            if (j==0)
                dyn=>instruments[i].noteOn;
            else if (Math.random2f(0,1)<0.7)
                dyn=>instruments[i].noteOn;
        }
        <<<"beat: ",  rhythmCounter>>>;
        (rhythmCounter+1)%4=>rhythmCounter;
    }
}
while (true)
{
    if (chords.size<5)
    {
        generateChords();
    }
    if (beats.size<5)
    {
        generateBeats;
    }
    playChord(chords.poll()$Chord, keys.poll(), beats.poll());
}

class Chord
{
    0=>static int mode;
    0=>int style;
    Chord @ next[];
    int notes[];
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probabilities[][];              //probability for each next state
    Chord @ modulationSequence[][];
    Chord @ modulationChord[];
    int modulationTarget[];
    fun void init(int root, int type, Chord next[], float probabilities[][])
    {
        setRoot(root);
        setType(type);
        setNext(next);
        setProbabilities(probabilities);
        setNotes();
    }
    fun void setRoot(int i)
    {
        i=>root;
    }
    fun void setType(int i)
    {
        i=>type;
    }
    fun void setNext(Chord c[])
    {
        c@=>next;
    }
    fun void setProbabilities(float f[][])
    {
        f@=>probabilities;
    }
    fun Chord getNextChord()
    {
        return getNextChord(mode);
    }
    fun Chord getNextChord(int i)
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        getProbabilities(i)@=>float p[];
        for (0=>int i; i<p.cap()-1;i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return next[next.cap()-1];
    }
    fun float[] getProbabilities(int i)
    {
        return probabilities[i];
    }
    fun string toString()
    {
        [["I","i","Idim","Iaug","Isus4","I7"],
         ["bII","bii"],
         ["II","ii","IIdim","IIaug","IIsus4","II7","ii7"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","iv"],
         ["bV","bv","bVdim","bVaug","bVsus4","bV7","bv7"],
         ["V","v","Vdim","Vaug","Vsus4","V7"],
         ["bVI","bvi"],
         ["VI","vi","VIdim","VIaug","VIsus4"],
         ["bVII","bvii"],
         ["VII","vii"]]@=>string s[][];
        return s[root][type];
    }
    fun void setNotes()
    {
        if (type==0)
        {
            [root,root+4,root+7]@=>notes;
        }
        if (type==1)
        {
            [root,root+3,root+7]@=>notes;
        }
        if (type==2)
        {
            [root,root+3,root+6]@=>notes;
        }
        if (type==3)
        {
            [root,root+4,root+8]@=>notes;
        }
        if (type==4)
        {
            [root,root+5,root+7]@=>notes;
        }
        if (type==5)
        {
            [root,root+4,root+7,root+10]@=>notes;
        }
        if (type==6)
        {
            [root,root+3,root+7,root+10]@=>notes;
        }

    }
    fun int[] getNotesWithin()
    {
        return notes;
    }
    fun void setModulation(Chord modulation[][], int target[], Chord chord[])
    {
        modulation@=>modulationSequence;
        target@=>modulationTarget;
        chord@=>modulationChord;
    }
    fun Chord[][] getModulationSequence()
    {
        return modulationSequence;
    }
    fun int[] getModulationTarget()
    {
        return modulationTarget;
    }
    fun Chord[] getModulationChord()
    {
        return modulationChord;
    }
}

class IntList
{
    0=>int size;
    IntNode @ first;
    IntNode @ last;

    fun void offer(int o)
    {
        IntNode n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun int poll()
    {
        if (size==0)
            return -1;
        size--;
        first @=> IntNode n;
        n.next @=> first;
        return n.object;
    }
}
class IntNode
{
    int object;
    IntNode @ next;
    fun void init(int o)
    {
        o=>object;
    }
}
class LinkedList                   //great pain to write a linked list in chuck
{
    0=>int size;
    Node @ first;
    Node @ last;

    fun void offer(Object o)
    {
        Node n;
        n.init(o);
        if (size==0)
        {
            n@=>first;
            n@=>last;
        }
        else
        {
            n@=>last.next;
            n@=>last;
        }
        size++;
    }
    fun Object poll()
    {
        if (size==0)
            return null;
        size--;
        first @=> Node n;
        n.next @=> first;
        return n.object;
    }
    fun Object add(Object o[])
    {
        for (0=>int i; i<o.cap(); i++)
        {
            offer(o[i]);
        }
    }
    fun Object getFirst()
    {
        return first.object;
    }
    fun Object getLast()
    {
        return last.object;
    }
}
class Node
{
    Object @ object;
    Node @ next;
    fun void init(Object o)
    {
        o@=>object;
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
Chord I;
Chord I7;
Chord ii;
Chord II;
Chord IIdim;
Chord ii7;
Chord iii;
Chord III;
Chord bv7;
Chord IV;
Chord iv;
Chord V;
Chord V7;
Chord vi;
Chord VI;
Chord Isus4;
Chord VIsus4;
I.init(0,0,[I,ii,III,IV,V,vi,ii7],[[0.1,0.1,0.1,0.3,0.2,0.1,0.1],[0.1,0.1,0.1,0.1,0.1,0.4,0.1]]);
I7.init(0,5,[I7],[[1.0],[1.0]]);
ii.init(2,1,[iii,III,V,vi],[[0.2,0.3,0.4,0.1],[0.4,0.3,0.2,0.1]]);
II.init(2,0,[II],[[1.0],[1.0]]);
IIdim.init(2,2,[V],[[1.0],[1.0]]);
ii7.init(2,6,[I,V],[[0.3,0.7],[0.3,0.7]]);
iii.init(4,1,[V,IV,vi],[[0.4,0.4,0.2],[0.2,0.3,0.5]]);
III.init(4,0,[IV,vi,iv],[[0.5,0.3,0.2],[0.2,0.6,0.2]]);
IV.init(5,0,[I,V,V7,III,bv7],[[0.3,0.3,0.2,0.1,0.1],[0.2,0.4,0.1,0.2,0.1]]);
iv.init(5,1,[VI,V,vi],[[0.3,0.4,0.3],[0.2,0.4,0.4]]);
bv7.init(6,6,[V],[[1.0],[1.0]]);
V.init(7,0,[I,vi,ii,iii,Isus4,V7],[[0.2,0.2,0.1,0.2,0.1,0.2],[0.2,0.1,0.1,0.2,0.2,0.2]]);
V7.init(7,5,[I,vi],[[0.8,0.2],[0.4,0.6]]);
vi.init(9,1,[I,ii,iii,IV,V,IIdim],[[0.2,0.2,0.1,0.3,0.1,0.1],[0.2,0.2,0.2,0.2,0.1,0.1]]);
Isus4.init(0,4,[I],[[1.0],[1.0]]);
VIsus4.init(9,4,[vi],[[1.0],[1.0]]);
VI.init(9,0,[VI],[[1.0],[1.0]]);
III.setModulation([[VIsus4]],[-3],[I]);
I.setModulation([[VI],[I7],[VI]],[2,5,7],[I,I,V]);
Rhodey  instruments[4];
IntList beats;
IntList keys;
LinkedList chords;
chords.offer(IV);
keys.offer(3);
beats.offer(4);
0=>int rhythmCounter;
fun void generateChords()
{
    chords.getLast() $ Chord @=> Chord lastChord;
    if (lastChord.getModulationSequence()!=null && Math.random2f(0, 1)<0.2)
    {
        lastChord.getModulationSequence()@=>Chord modSqs[][];
        lastChord.getModulationTarget()@=>int modKeys[];
        lastChord.getModulationChord()@=>Chord targetChords[];
        Math.random2f(0,modSqs.cap()) $ int  =>int choice;
        modSqs[choice]@=>Chord modSq[];
        modKeys[choice]=>int keyChange;
        targetChords[choice]@=>Chord targetChord;
        for (0=>int i; i<modSq.cap(); i++)
        {
            chords.offer(modSq[i]);
            keys.offer(keys.last.object);
        }
        chords.offer(targetChord);
        keys.offer((keys.last.object+keyChange+12)%12);
    }
    else
    {
        chords.offer(lastChord.getNextChord(1));
        keys.offer(keys.last.object);
    }
}
fun void generateBeats()
{
    Math.random2f(0,1) => float p;
    if (p<=0.6)
    {
        beats.offer(4);
    }
    else if (p<=0.7)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(2);
    }
    else if (p<=0.8)
    {
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
        beats.offer(3);
    }
    else if (p<=0.9)
    {
        beats.offer(6);
        beats.offer(2);
    }
    else
    {
        beats.offer(3);
        beats.offer(2);
        beats.offer(3);
    }
}

for (0=>int i; i < instruments.cap(); i++)
{
    instruments[i]=>dac;
}

fun void playChord(Chord current, int key, int beat)
{
    if (beats.size==0)
    {
        generateBeats();
    }
    current.root=>int root;
    current.type=>int type;
    send.startMsg("/key/root/type", "i i i");
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    current.getNotesWithin()@=>int notes[];
    <<< "Chord Name: ", current.toString() >>>;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    <<< "Beats Played: ", beat>>>;
    for (0=>int j;j<beat;j++)
    {
        0.5::second=>now;
        float dyn;
        if (rhythmCounter == 0)
            0.2=>dyn;
        else if (rhythmCounter == 2)
            0.11=>dyn;
        else
            0.07=>dyn;
        Std.mtof(36+(key+notes[0]%12))=>instruments[0].freq;
        dyn=>instruments[0].noteOn;
        for (1=>int i; i < instruments.cap(); i++)
        {
            Std.mtof(48+(key+notes[i%notes.cap()])%12)=>instruments[i].freq;
            if (j==0)
                dyn=>instruments[i].noteOn;
            else if (Math.random2f(0,1)<0.7)
                dyn=>instruments[i].noteOn;
        }
        <<<"beat: ",  rhythmCounter>>>;
        (rhythmCounter+1)%4=>rhythmCounter;
    }
}
while (true)
{
    if (chords.size<5)
    {
        generateChords();
    }
    if (beats.size<5)
    {
        generateBeats;
    }
    playChord(chords.poll()$Chord, keys.poll(), beats.poll());
}


Slight changes

Slight changes

class Chord
{
    0=>int style;
    Chord @ next[];
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probabilities[][];              //probability for each next state
    fun void init(int root, int type, Chord next[], float probabilities[][])
    {
        setRoot(root);
        setType(type);
        setNext(next);
        setProbabilities(probabilities);
    }
    fun void setRoot(int i)
    {
        i=>root;
    }
    fun void setType(int i)
    {
        i=>type;
    }
    fun void setNext(Chord c[])
    {
        c@=>next;
    }
    fun void setProbabilities(float f[][])
    {
        f@=>probabilities;
    }
    fun Chord getNextChord()
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        getProbabilities()@=>float p[];
        for (0=>int i; i<p.cap();i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return this;
    }
    fun float[] getProbabilities()
    {
        return getProbabilities(0);
    }
    fun float[] getProbabilities(int i)
    {
        return probabilities[i];
    }
    fun string toString()
    {
        [["I","i"],
         ["bII","bii"],
         ["II","ii"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","vi"],
         ["bV","bv"],
         ["V","v"],
         ["bVI","bvi"],
         ["VI","vi"],
         ["bVII","bvii"],
         ["VII","vii"]]@=>string s[][];
        return s[root][type];
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
Chord I;
Chord ii;
Chord iii;
Chord III;
Chord IV;
Chord V;
Chord vi;
I.init(0,0,[I,ii,III,IV,V],[[0.1,0.1,0.1,0.4,0.3]]);
ii.init(2,1,[I,iii,III,V,vi],[[0.1,0.1,0.3,0.4,0.1]]);
iii.init(4,1,[V,IV,vi],[[0.2,0.4,0.4]]);
III.init(4,0,[IV,vi],[[0.4,0.6]]);
IV.init(5,0,[I,V,III],[[0.3,0.6,0.1]]);
V.init(7,0,[I,vi,ii],[[0.6,0.3,0.1]]);
vi.init(9,1,[I,ii,iii,IV,V,vi],[[0.1,0.3,0.1,0.3,0.1,0.1]]);
I @=> current;
while (true)
{
    <<< "Chord Name: ", current.toString() >>>;
    0=>int key;
    current.root=>int root;
    current.type=>int type;
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    current.getNextChord()@=>current;
    6::second=>now;
}

/* As you can see, this is a very raw Markov chain for chord progressions
 * It would be great if melodies can be generated according to this state machine
 * I use classes only because a ton of "else if" looks really messy, though the object-oriented of this language is really bad
 * The blank funcion is intended for future data receiving
 * It sends basic information of a chord
 * I hope melody can be generated according to the chord
 */

//the very basic chord base
class Chord
{
    string name;                      //how you call it
    string nextChord[];               //next states
    int root;                         //the root key
    int type;                         //major,minor,etc
    float probability[];              //probability for each next state
    fun string getNextChordName()     //randomly choose the next chord
    {
        Std.rand2f(0, 1)=>float rand;
        0=>float c;
        for (0=>int i; i<probability.cap();i++)
        {
            probability[i]+=>c;
            if (rand<=c)
                return nextChord[i];
        }
        return this.name;
    }
    fun void setStyle(){}            //may be used to change probabilities
}

class ChordMajor extends Chord
{
    0=>type;
}

class ChordMinor extends Chord
{
    1=>type;
}

class ChordI extends ChordMajor
{
    "I"=>name;
    0=>root;
    ["I", "ii","III","IV","V"]@=>nextChord;
    [0.1,0.1,0.1,0.4,0.3]@=>probability;
}
class Chordii extends ChordMinor
{
    "ii"=>name;
    2=>root;
    ["I","iii","III","V","vi"]@=>nextChord;
    [0.1,0.1,0.3,0.4,0.1]@=>probability;
}
class Chordiii extends ChordMinor
{
    "iii"=>name;
    4=>root;
    ["V","IV","vi"]@=>nextChord;
    [0.2,0.4,0.4]@=>probability;
}
class ChordIII extends ChordMajor
{
    "III"=>name;
    4=>root;
    ["IV","vi"]@=>nextChord;
    [0.4,0.6]@=>probability;
}
class ChordIV extends ChordMajor
{
    "IV"=>name;
    5=>root;
    ["I","V","III"]@=>nextChord;
    [0.3,0.6,0.1]@=>probability;
}
class ChordV extends ChordMajor
{
    "V"=>name;
    7=>root;
    ["I","vi","ii"]@=>nextChord;
    [0.6,0.3,0.1]@=>probability;
}class Chordvi extends ChordMinor
{
    "vi"=>name;
    9=>root;
    ["I","ii","iii","IV","V","vi"]@=>nextChord;
    [0.1,0.3,0.1,0.3,0.1,0.1]@=>probability;
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord current;
ChordI I;
Chordii ii;
Chordiii iii;
ChordIII III;
ChordIV IV;
ChordV V;
Chordvi vi;
fun Chord getChord(string s)
{
    if (s=="I")
        return I;
    if (s=="ii")
        return ii;
    if (s=="iii")
        return iii;
    if (s=="III")
        return III;
    if (s=="IV")
        return IV;
    if (s=="V")
        return V;
    if (s=="vi")
        return vi;
    return null;
}
I @=> current;
while (true)
{
    <<< "Chord Name: ", current.name >>>;
    0=>int key;
    current.root=>int root;
    current.type=>int type;
    key => send.addInt;
    root => send.addInt;
    type => send.addInt;
    <<< "Sent key: ", key, "root: ", root, ", type: ", type >>>;
    getChord(current.getNextChordName())@=>current;
    6::second=>now;
}


Test commit on a dev branch

Test commit on a dev branch


Remove temp file

Remove temp file

public class MalTimeMs extends MalSubr
{
    fun MalObject call(MalObject args[])
    {
        // HACK: Std.system returns the status code only...
        "/tmp/chuck-date." + Std.rand2(1000,9999) => string temp_file;
        Std.system("date +%s%3N > " + temp_file);

        FileIO f;
        f.open(temp_file, FileIO.READ);
        f => int timestamp;
        f.close();

        Std.system("rm " + temp_file);

        return MalInt.create(timestamp);
    }
}

public class MalTimeMs extends MalSubr
{
    fun MalObject call(MalObject args[])
    {
        // HACK: Std.system returns the status code only...
        "/tmp/chuck-date." + Std.rand2(1000,9999) => string temp_file;
        Std.system("date +%s%3N > " + temp_file);

        FileIO f;
        f.open(temp_file, FileIO.READ);
        f => int timestamp;
        f.close();

        return MalInt.create(timestamp);
    }
}


main comment

main comment

/**
 * This is an example main.ck file. It way produced
 * as a main file to play my concerts, so everything
 * is working and tested. The problem with it and
 * the rest of classes is that ChucK supports
 * Mac OSX *much* better than other platforms
 * Linux is the least supported. This is why
 * SndBuf was used instead of LiSa. :shrug:
 * Some bugs and strange "shortcuts" can be
 * the ffect of that situation. At the moment
 * the main problem with Beta Vulgaris is:
 *
 *   1. Lack of perlin noise in ChucK. I use simple
 *      applet written in Processing and sending
 *      perlin noise control signal via OSC :sad:
 *
 *   2. MIDI can't handle two MIDI events at one time
 *      It's horrible, so in future MIDI-to-OSC
 *      interface will be produced in Processing or sth.
 *
 * Have fun!!
 */

// midi communication
MidiIn midi_in;
MidiMsg midi_msg;
// midi event
MidiEvent midi_event;

// keyboard communication
KBHit kb;
// keyboard event
KeyEvent e;

// osc receiver
// all osc events in this code come from Processing applet
// that produces 1Dimensional perlin noise
// Maybe in future it will provide an interface to
// malfunctioning MIDI control
OscRecv osc_receiver;
5601 => osc_receiver.port;
osc_receiver.listen();

Looper looper[Globals.NUM_OF_TRACKS];
Cutter cutter[Globals.NUM_OF_TRACKS];
Panner panner[Globals.NUM_OF_TRACKS];
Threshold threshold[Globals.NUM_OF_TRACKS];
Stammer stammer[Globals.NUM_OF_TRACKS];
Gainer gainer[Globals.NUM_OF_TRACKS];
Gain master[Globals.NUM_OF_TRACKS];

Gain left, right;

for(0 => int i; i < Globals.NUM_OF_TRACKS; ++i) {
    looper[i].play();
    looper[i] => Loader.load_sound_files;

    cutter[i].play();
    osc_receiver.event("/f" + (i+1) + ",f") => panner[i].osc_event;
    panner[i].play();
    threshold[i].play();
    stammer[i].play();
    osc_receiver.event("/f" + (i+21) + ",f") => gainer[i].osc_event;
    gainer[i].play();
}

{ // track 0
  // this code has to be reimplemented as a separate class!!
    looper[0].connect(stammer[0]);
    stammer[0].connect(master[0]);
    master[0] => dac;
}
{ // track 1
    looper[1].connect(master[1]);
    master[1] => dac;
}
{ // track 2
    looper[2].connect(master[2]);
    master[2] => dac;
}
{ // track 3
  // this code has to be reimplemented as a separate class!!
    looper[3].connect(cutter[3]);
    cutter[3].connect(threshold[3]);
    threshold[3].connect(gainer[3]);
    gainer[3].connect(master[3]);
    master[3] => panner[3].input();
    panner[3].connect(dac);
}
{ // track 4
  // this code has to be reimplemented as a separate class!!
    looper[4].connect(cutter[4]);
    cutter[4].connect(threshold[4]);
    threshold[4].connect(gainer[4]);
    gainer[4].connect(master[4]);
    master[4] => panner[4].input();
    panner[4].connect(dac);
}
{ // track 5
  // this code has to be reimplemented as a separate class!!
    Delay d1, d2, d3;

    15005::ms => d1.max => d2.max => d3.max;
    5::second => d1.delay;
    10::second => d2.delay;
    15::second => d3.delay;

    Cutter c1, c2, c3;
    4.0 => c1.set_freq;
    8.0 => c1.set_freq;
    15.0 => c1.set_freq;
    c1.play();
    c2.play();
    c3.play();

    Gainer g1, g2, g3;
    osc_receiver.event("/f" + 11 + ",f") => g1.osc_event;
    osc_receiver.event("/f" + 12 + ",f") => g2.osc_event;
    osc_receiver.event("/f" + 13 + ",f") => g3.osc_event;
    g1.play();
    g2.play();
    g3.play();

    Panner p1, p2, p3;
    osc_receiver.event("/f" + 14 + ",f") => p1.osc_event;
    osc_receiver.event("/f" + 15 + ",f") => p2.osc_event;
    osc_receiver.event("/f" + 16 + ",f") => p3.osc_event;
    p1.play();
    p2.play();
    p3.play();

    looper[5].connect(cutter[5]);
    looper[5]._output => d1;
    d1 => c1.input();
    looper[5]._output => d2;
    d2 => c2.input();
    looper[5]._output => d3;
    d3 => c3.input();

    cutter[5].connect(gainer[5]);
    c1.connect(g1);
    c2.connect(g2);
    c3.connect(g3);

    gainer[5].connect(panner[5]);
    g1.connect(p1);
    g2.connect(p2);
    g3.connect(p3);

    // is it a bug that Pan2 goes mono
    // when connected to Gain?
    panner[5].connect_left(left);
    panner[5].connect_right(right);
    p1.connect_left(left);
    p1.connect_right(right);
    p2.connect_left(left);
    p2.connect_right(right);
    p3.connect_left(left);
    p3.connect_right(right);

    left  => dac.left;
    right => dac.right;
}

// midi listener
spork ~ midi_listener();
spork ~ midi_handler(midi_event);

// main time loop
while(true) {
    1::samp => now;
}

// these function are here, because they need
// an acces to Beets and UGens on tracks
// to be completely re-implemented
// with event handlers inside classes
// just like with OSC messages
// possible solution is to write external MIDI-to-OSC
// interface as ChucK handles MIDI really bad
fun void midi_handler(MidiEvent e) {
    float first_track_gain_reminder;
    int first_track_mute;

    float last_track_gain_reminder;
    int last_track_mute;

    while(true) {
        show_state();

        // wait for the midi event to come
        e => now;

        (e.cc_number / 10) - 1 => int track_num;
        e.cc_number % 10 => int control_num;

        // first four controls have the same function
        // for all the tracs, so are handled by control_num

        //  V O L U M E
        if(control_num == 1) {
            if(track_num == 0 && first_track_mute == 1) {
                Utils.map_midi(e.cc_value) => first_track_gain_reminder;
                continue;
            }
            if(track_num == 5) {
                if(last_track_mute == 1) {
                    Utils.map_midi(e.cc_value) => last_track_gain_reminder;
                }
                else {
                    Utils.map_midi(e.cc_value) => left.gain;
                    Utils.map_midi(e.cc_value) => right.gain;
                }
                continue;
            }

            Utils.map_midi(e.cc_value) => master[track_num].gain;
            continue;
        }
        //  M U T E
        if(control_num == 2) {
            if(track_num == 0) {
                if(e.cc_value == 127) {
                    master[track_num].gain() => first_track_gain_reminder;
                    0.0 => master[track_num].gain;
                    1 => first_track_mute;
                }
                else {
                    first_track_gain_reminder => master[track_num].gain;
                    0 => first_track_mute;
                }
                continue;
            }
            if(track_num == 5) {
                if(e.cc_value == 127) {
                    left.gain() => last_track_gain_reminder;
                    0.0 => left.gain;
                    0.0 => right.gain;

                    1 => last_track_mute;
                }
                else {
                    last_track_gain_reminder => left.gain;
                    last_track_gain_reminder => right.gain;

                    0 => last_track_mute;
                }
                continue;
            }

            Utils.map_midi(e.cc_value) $ int => int mute;
            if(mute == 0) {
                looper[track_num].play();
            }
            else {
                looper[track_num].stop();
            }
            continue;
        }
        if(control_num == 3) {
            // nothing going on there
            continue;
        }
        //  F I L E   S E L E C T I O N
        if(control_num == 4) {
            Utils.map_midi(e.cc_value, 0.0, looper[track_num].length() - 1.01) => float index;
            index $ int => looper[track_num].current_file;
            continue;
        }
        //  P L A Y B A C K   R A T E
        if(control_num == 5) {
            Utils.map_midi(e.cc_value, -2.0, 2.0) => looper[track_num].set_speed;
            continue;
        }

        // the rest of controls have different functions
        // for each track, so they are handled by track_num
        //  T R A C K 1
        //  T R A C K 2
        //  T R A C K 3
        if(track_num == 0 && control_num == 6) {
            Utils.map_midi(e.cc_value, 2.0, 9.0) => stammer[track_num].set_freq;
            continue;
        }
        if(track_num == 3 || track_num == 4) {
            if(control_num == 7) {
                Utils.map_midi(e.cc_value, 0.0, 1.0) => threshold[track_num].set_threshold;
                continue;
            }
            if(control_num == 8) {
                Utils.map_midi(e.cc_value, 2.0, 25.0) => cutter[track_num].set_freq;
                continue;
            }
        }
    }
}

fun void midi_listener() {
    if(!midi_in.open(1)) {
        <<< ">>>", "MIDI can't be open" >>>;
        me.exit();
    }

    while(true) {
        midi_in => now;

        while(midi_in.recv(midi_msg)) {
            // get cc number
            midi_msg.data2 => midi_event.cc_number;
            // get cc value
            midi_msg.data3 => midi_event.cc_value;

            // uncomment it to see, what is actually going on with MIDI
            // <<< midi_event.cc_number, "::", midi_event.cc_value >>>;

            // broadcast new data
            midi_event.broadcast();
        }
    }
}

fun void show_state() {
    Utils.clear_screen();

    for(0 => int i; i < Globals.NUM_OF_TRACKS; ++i) {
        <<< "Track", (i+1) >>>;
        <<< looper[i].show_current_state() >>>;
        <<< "-------------", "-----------" >>>;
    }
}

/**
 * This is an example main.ck file. It way produced
 * as a main file to play my concerts, so everything
 * is working and tested. The problem with it and
 * the rest of classes is that ChucK supports
 * Mac OSX *much* better than other platforms
 * Linux is the least supported. This is why
 * SndBuf was used instead of LiSa. :shrug:
 * Some bugs and strange "shortcuts" can be
 * the ffect of that situation. At the moment
 * the main problem with Beta Vulgaris is:
 *
 *   1. Lack of perlin noise in ChucK. I use simple
 *      applet written in Processing and sending
 *      perlin noise control signal via OSC
 *
 *   2. MIDI can't handle two MIDI events at one time
 *      It's horrible, so in future MIDI-to-OSC
 *      interface will be produced in Processing or sth.
 *
 * Have fun!!
 */

// midi communication
MidiIn midi_in;
MidiMsg midi_msg;
// midi event
MidiEvent midi_event;

// keyboard communication
KBHit kb;
// keyboard event
KeyEvent e;

// osc receiver
// all osc events in this code come from Processing applet
// that produces 1Dimensional perlin noise
// Maybe in future it will provide an interface to
// malfunctioning MIDI control
OscRecv osc_receiver;
5601 => osc_receiver.port;
osc_receiver.listen();

Looper looper[Globals.NUM_OF_TRACKS];
Cutter cutter[Globals.NUM_OF_TRACKS];
Panner panner[Globals.NUM_OF_TRACKS];
Threshold threshold[Globals.NUM_OF_TRACKS];
Stammer stammer[Globals.NUM_OF_TRACKS];
Gainer gainer[Globals.NUM_OF_TRACKS];
Gain master[Globals.NUM_OF_TRACKS];

Gain left, right;

for(0 => int i; i < Globals.NUM_OF_TRACKS; ++i) {
    looper[i].play();
    looper[i] => Loader.load_sound_files;

    cutter[i].play();
    osc_receiver.event("/f" + (i+1) + ",f") => panner[i].osc_event;
    panner[i].play();
    threshold[i].play();
    stammer[i].play();
    osc_receiver.event("/f" + (i+21) + ",f") => gainer[i].osc_event;
    gainer[i].play();
}

{ // track 0
  // this code has to be reimplemented as a separate class!!
    looper[0].connect(stammer[0]);
    stammer[0].connect(master[0]);
    master[0] => dac;
}
{ // track 1
    looper[1].connect(master[1]);
    master[1] => dac;
}
{ // track 2
    looper[2].connect(master[2]);
    master[2] => dac;
}
{ // track 3
  // this code has to be reimplemented as a separate class!!
    looper[3].connect(cutter[3]);
    cutter[3].connect(threshold[3]);
    threshold[3].connect(gainer[3]);
    gainer[3].connect(master[3]);
    master[3] => panner[3].input();
    panner[3].connect(dac);
}
{ // track 4
  // this code has to be reimplemented as a separate class!!
    looper[4].connect(cutter[4]);
    cutter[4].connect(threshold[4]);
    threshold[4].connect(gainer[4]);
    gainer[4].connect(master[4]);
    master[4] => panner[4].input();
    panner[4].connect(dac);
}
{ // track 5
  // this code has to be reimplemented as a separate class!!
    Delay d1, d2, d3;

    15005::ms => d1.max => d2.max => d3.max;
    5::second => d1.delay;
    10::second => d2.delay;
    15::second => d3.delay;

    Cutter c1, c2, c3;
    4.0 => c1.set_freq;
    8.0 => c1.set_freq;
    15.0 => c1.set_freq;
    c1.play();
    c2.play();
    c3.play();

    Gainer g1, g2, g3;
    osc_receiver.event("/f" + 11 + ",f") => g1.osc_event;
    osc_receiver.event("/f" + 12 + ",f") => g2.osc_event;
    osc_receiver.event("/f" + 13 + ",f") => g3.osc_event;
    g1.play();
    g2.play();
    g3.play();

    Panner p1, p2, p3;
    osc_receiver.event("/f" + 14 + ",f") => p1.osc_event;
    osc_receiver.event("/f" + 15 + ",f") => p2.osc_event;
    osc_receiver.event("/f" + 16 + ",f") => p3.osc_event;
    p1.play();
    p2.play();
    p3.play();

    looper[5].connect(cutter[5]);
    looper[5]._output => d1;
    d1 => c1.input();
    looper[5]._output => d2;
    d2 => c2.input();
    looper[5]._output => d3;
    d3 => c3.input();

    cutter[5].connect(gainer[5]);
    c1.connect(g1);
    c2.connect(g2);
    c3.connect(g3);

    gainer[5].connect(panner[5]);
    g1.connect(p1);
    g2.connect(p2);
    g3.connect(p3);

    // is it a bug that Pan2 goes mono
    // when connected to Gain?
    panner[5].connect_left(left);
    panner[5].connect_right(right);
    p1.connect_left(left);
    p1.connect_right(right);
    p2.connect_left(left);
    p2.connect_right(right);
    p3.connect_left(left);
    p3.connect_right(right);

    left  => dac.left;
    right => dac.right;
}

// midi listener
spork ~ midi_listener();
spork ~ midi_handler(midi_event);

// main time loop
while(true) {
    1::samp => now;
}

// these function are here, because they need
// an acces to Beets and UGens on tracks
// to be completely re-implemented
// with event handlers inside classes
// just like with OSC messages
// possible solution is to write external MIDI-to-OSC
// interface as ChucK handles MIDI really bad
fun void midi_handler(MidiEvent e) {
    float first_track_gain_reminder;
    int first_track_mute;

    float last_track_gain_reminder;
    int last_track_mute;

    while(true) {
        show_state();

        // wait for the midi event to come
        e => now;

        (e.cc_number / 10) - 1 => int track_num;
        e.cc_number % 10 => int control_num;

        // first four controls have the same function
        // for all the tracs, so are handled by control_num

        //  V O L U M E
        if(control_num == 1) {
            if(track_num == 0 && first_track_mute == 1) {
                Utils.map_midi(e.cc_value) => first_track_gain_reminder;
                continue;
            }
            if(track_num == 5) {
                if(last_track_mute == 1) {
                    Utils.map_midi(e.cc_value) => last_track_gain_reminder;
                }
                else {
                    Utils.map_midi(e.cc_value) => left.gain;
                    Utils.map_midi(e.cc_value) => right.gain;
                }
                continue;
            }

            Utils.map_midi(e.cc_value) => master[track_num].gain;
            continue;
        }
        //  M U T E
        if(control_num == 2) {
            if(track_num == 0) {
                if(e.cc_value == 127) {
                    master[track_num].gain() => first_track_gain_reminder;
                    0.0 => master[track_num].gain;
                    1 => first_track_mute;
                }
                else {
                    first_track_gain_reminder => master[track_num].gain;
                    0 => first_track_mute;
                }
                continue;
            }
            if(track_num == 5) {
                if(e.cc_value == 127) {
                    left.gain() => last_track_gain_reminder;
                    0.0 => left.gain;
                    0.0 => right.gain;

                    1 => last_track_mute;
                }
                else {
                    last_track_gain_reminder => left.gain;
                    last_track_gain_reminder => right.gain;

                    0 => last_track_mute;
                }
                continue;
            }

            Utils.map_midi(e.cc_value) $ int => int mute;
            if(mute == 0) {
                looper[track_num].play();
            }
            else {
                looper[track_num].stop();
            }
            continue;
        }
        if(control_num == 3) {
            // nothing going on there
            continue;
        }
        //  F I L E   S E L E C T I O N
        if(control_num == 4) {
            Utils.map_midi(e.cc_value, 0.0, looper[track_num].length() - 1.01) => float index;
            index $ int => looper[track_num].current_file;
            continue;
        }
        //  P L A Y B A C K   R A T E
        if(control_num == 5) {
            Utils.map_midi(e.cc_value, -2.0, 2.0) => looper[track_num].set_speed;
            continue;
        }

        // the rest of controls have different functions
        // for each track, so they are handled by track_num
        //  T R A C K 1
        //  T R A C K 2
        //  T R A C K 3
        if(track_num == 0 && control_num == 6) {
            Utils.map_midi(e.cc_value, 2.0, 9.0) => stammer[track_num].set_freq;
            continue;
        }
        if(track_num == 3 || track_num == 4) {
            if(control_num == 7) {
                Utils.map_midi(e.cc_value, 0.0, 1.0) => threshold[track_num].set_threshold;
                continue;
            }
            if(control_num == 8) {
                Utils.map_midi(e.cc_value, 2.0, 25.0) => cutter[track_num].set_freq;
                continue;
            }
        }
    }
}

fun void midi_listener() {
    if(!midi_in.open(1)) {
        <<< ">>>", "MIDI can't be open" >>>;
        me.exit();
    }

    while(true) {
        midi_in => now;

        while(midi_in.recv(midi_msg)) {
            // get cc number
            midi_msg.data2 => midi_event.cc_number;
            // get cc value
            midi_msg.data3 => midi_event.cc_value;

            // uncomment it to see, what is actually going on with MIDI
            // <<< midi_event.cc_number, "::", midi_event.cc_value >>>;

            // broadcast new data
            midi_event.broadcast();
        }
    }
}

fun void show_state() {
    Utils.clear_screen();

    for(0 => int i; i < Globals.NUM_OF_TRACKS; ++i) {
        <<< "Track", (i+1) >>>;
        <<< looper[i].show_current_state() >>>;
        <<< "-------------", "-----------" >>>;
    }
}


vital one note change

vital one note change


I still don't think this works.

I still don't think this works.

OscRev recv;
6449 => recv.port;
recv.listen();


modified control

modified control

// keyboard
Hid kb;
// hid message
HidMsg msg;

// open
if( !kb.openKeyboard(0) ) me.exit();
<<< "KB open:", kb.name() >>>;
spork ~ kbf();

// patch
SndBuf L => dac.left;
SndBuf R => dac.right;

// envelope followers
L => OnePole envL => blackhole; L => envL; 3 => envL.op;
R => OnePole envR => blackhole; R => envR; 3 => envR.op;
.9995 => envL.pole => envR.pole;

// load
me.dir() + "../audio/turenas-L.aiff" => L.read;
me.dir() + "../audio/turenas-R.aiff" => R.read;
L.samples() => L.pos;
R.samples() => R.pos;
0 => L.gain => R.gain;

-100 => float FRONT;
FRONT * .5 => float FRONT_FENCE;
100 => float BACK;
BACK * .5 => float BACK_FENCE;

// entities
VREntity es[0];
vec3 v;
polar p;
complex c;
fun void makeOne()
{
    // make a some points
    VR.makeEntity("one"+es.size(),"mesh") @=> VREntity mesh;
    // make
    mesh.eval( "vertex -1 -1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex 1 -1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex -1 1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex 1 1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    // draw as triangle
    mesh.eval( "draw trianglestrip" );
    // add to world
    VR.root().addChild( mesh );
    // loc
    Math.random2f(5,100) => p.mag;
    Math.random2f(-pi,pi) => p.phase;
    p$complex => c;
    c.re => mesh.loc.x;
    c.im => mesh.loc.z;
    Math.random2f(FRONT,FRONT_FENCE) => mesh.loc.y;

    Math.random2f(.1,1) => mesh.rgba.r;
    Math.random2f(.1,1) => mesh.rgba.g;
    Math.random2f(.1,1) => mesh.rgba.b;
    Math.random2f(0,0) => mesh.rgba.a;
    Math.random2f(0,360) => mesh.ori.y;

    // add
    es << mesh;
}

VREntity @ es2[0];
float es2t[0];

fun void makeTwo()
{
    // make a some points
    VR.makeEntity("two"+es.size(),"flare") @=> VREntity f;
    // set the texture
    f.setString( "texture", "texture:flare-1");
    // loc
    Math.random2f(5,100) => p.mag;
    Math.random2f(-pi,pi) => p.phase;
    p$complex => c;
    c.re => f.loc.x;
    c.im => f.loc.y;
    f.sca.setAll(10);
    Math.random2f(FRONT,FRONT_FENCE) => f.loc.z;

    Math.random2f(1,1) => f.rgba.r;
    Math.random2f(1,1) => f.rgba.g;
    Math.random2f(1,1) => f.rgba.b;
    Math.random2f(0,0) => f.rgba.a;

    // add
    es2 << f;
    es2t << Math.random2f(0,2*pi);

    // add to world
    VR.root().addChild( f );
}

VREntity @ es3[0];
float es3t[0];

-500 => float FRONT3;
FRONT3 * .5 => float FRONT_FENCE3;
300 => float BACK3;
BACK3 * .5 => float BACK_FENCE3;

fun void makeThree( float inner, float outer, float whereY, float varyY )
{
    // make a some points
    VR.makeEntity("three"+es.size(),"mesh") @=> VREntity f;
    // set the texture
    f.setString( "texture", "texture:flare-1");

    f.eval( "draw points" );
    repeat(4000)
    {
        // loc
        Math.random2f(inner,outer) => p.mag;
        Math.random2f(-pi,pi) => p.phase;
        p$complex => c;
        c.re => v.x;
        Math.random2f(-1,1) => v.y;
        c.im => v.z;
        f.eval( "vertex", v );
    }

    0 => f.loc.x;
    0 => f.loc.z;
    Math.random2f(whereY,whereY*varyY) => f.loc.y;

    Math.random2f(1,1) => f.rgba.r;
    Math.random2f(1,1) => f.rgba.g;
    Math.random2f(1,1) => f.rgba.b;
    Math.random2f(0,0) => f.rgba.a;

    // add
    es3 << f;
    es3t << .0000002 / Math.pow((inner+outer)/6.0/outer,10);
    // <<< "spin:", es3t[es3t.size()-1] >>>;

    // add to world
    VR.root().addChild( f );
}

//repeat(4)
//    for(int i; i < 10; i++ )
//        makeThree( 2*(20+i*15), 4*(20+i*15+5), FRONT3*3, .6 );

//repeat(4)
//    for(int i; i < 10; i++ )
//        makeThree( 2*(20+i*15), 4*(20+i*15+5), FRONT3*6, .6 );

//repeat(4)
//    for(int i; i < 10; i++ )
//        makeThree( 2*(20+i*15), 4*(20+i*15+5), FRONT3*12, .6 );

// disable lights
VR.allLightsOn();

// bang detector
fun void bangDetect()
{
    while( true )
    {
        if( envL.last() > 0.0001 )
        {
            <<< "BANG!!", now/second >>>;
            100::ms => now;
        }
        10::ms => now;
    }
}

// detector
// spork ~ bangDetect();
VREntity @ e;

// loop
while( true )
{
    for( int i; i < es.size(); i++ )
    {
        es[i] @=> e;
        if( e.loc.y <= FRONT_FENCE )
            1-Math.fabs((e.loc.y-FRONT_FENCE)/(FRONT-FRONT_FENCE)) => e.rgba.a;
        else if( e.loc.y >= BACK_FENCE )
            1-Math.fabs((e.loc.y-BACK_FENCE)/(BACK-BACK_FENCE)) => e.rgba.a;
        else
            1 => e.rgba.a;

        if( e.rgba.a < 0 ) 0 => e.rgba.a;
        else if( e.rgba.a > 1 ) 1 => e.rgba.a;

        5 +=> e.ori.y;
        .5 +=> e.loc.y;
        if( e.loc.y > BACK ) FRONT => e.loc.y;
    }

    for( int i; i < es2.size(); i++ )
    {
        es2[i] @=> e;
        if( e.loc.z <= FRONT_FENCE )
            1-Math.fabs((e.loc.z-FRONT_FENCE)/(FRONT-FRONT_FENCE)) => e.rgba.a;
        else if( e.loc.z >= BACK_FENCE )
            1-Math.fabs((e.loc.z-BACK_FENCE)/(BACK-BACK_FENCE)) => e.rgba.a;
        else
            1 => e.rgba.a;

        if( e.rgba.a < 0 ) 0 => e.rgba.a;
        else if( e.rgba.a > 1 ) 1 => e.rgba.a;

        Math.pow(envL.last(),1)*100 *=> e.rgba.a;

        5 * (1 + .2*Math.sin(es2t[i])) => e.sca.setAll; .1 +=> es2t[i];
        .2 +=> e.loc.z;
        if( e.loc.z > BACK ) FRONT => e.loc.z;
    }

    for( int i; i < es3.size(); i++ )
    {
        es3[i] @=> e;
        if( e.loc.y <= FRONT_FENCE3 )
            1-Math.fabs((e.loc.y-FRONT_FENCE3)/(FRONT3-FRONT_FENCE3)) => e.rgba.a;
        else if( e.loc.y >= BACK_FENCE3 )
            1-Math.fabs((e.loc.y-BACK_FENCE3)/(BACK3-BACK_FENCE3)) => e.rgba.a;
        else
            1 => e.rgba.a;

        if( e.rgba.a < 0 ) 0 => e.rgba.a;
        else if( e.rgba.a > 1 ) 1 => e.rgba.a;

        es3t[i] +=> e.ori.y;
        .5 +=> e.loc.y;
        if( e.loc.y > BACK3 ) FRONT3 => e.loc.y;
    }

    // VR.root().rgba.setAll(Math.pow(envL.last(),.75)*500);

    // synch with display
    VR.displaySync() => now;
}

fun void kbf()
{
    while( true )
    {
        // wait
        kb => now;
        // wait
        while( kb.recv(msg) )
        {
            if( !msg.isButtonDown() )
                continue;

            if( msg.ascii == 48 ) // 1
            {
                0 => L.pos => R.pos;
                1 => L.gain => R.gain;
            }
            // <<< "kb:", msg.ascii >>>;
            if( msg.ascii == 49 ) // 1
            {
                repeat(10) makeOne();
            }
            else if( msg.ascii == 50 ) // 2
            {
                repeat(10) makeTwo();
            }
            else if( msg.ascii == 51 ) // 3
            {
                for(int i; i < 10; i++ )
                    makeThree( 2*(20+i*15), 4*(20+i*15+5), FRONT3*2.5, .75 );
            }
        }
    }
}

// keyboard
Hid kb;
// hid message
HidMsg msg;

// open
if( !kb.openKeyboard(2) ) me.exit();
<<< "KB open:", kb.name() >>>;
spork ~ kbf();

// patch
SndBuf L => dac.left;
SndBuf R => dac.right;

// envelope followers
L => OnePole envL => blackhole; L => envL; 3 => envL.op;
R => OnePole envR => blackhole; R => envR; 3 => envR.op;
.9995 => envL.pole => envR.pole;

// load
me.dir() + "../audio/turenas-L.aiff" => L.read;
me.dir() + "../audio/turenas-R.aiff" => R.read;

-100 => float FRONT;
FRONT * .5 => float FRONT_FENCE;
100 => float BACK;
BACK * .5 => float BACK_FENCE;

// entities
VREntity es[0];
vec3 v;
polar p;
complex c;
fun void makeOne()
{
    // make a some points
    VR.makeEntity("one"+es.size(),"mesh") @=> VREntity mesh;
    // make
    mesh.eval( "vertex -1 -1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex 1 -1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex -1 1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    mesh.eval( "vertex 1 1 0" );
    //mesh.eval( "color 1 1 1" );
    mesh.eval( "normal 0 0 1" );
    // draw as triangle
    mesh.eval( "draw trianglestrip" );
    // add to world
    VR.root().addChild( mesh );
    // loc
    Math.random2f(5,100) => p.mag;
    Math.random2f(-pi,pi) => p.phase;
    p$complex => c;
    c.re => mesh.loc.x;
    c.im => mesh.loc.z;
    Math.random2f(FRONT,FRONT_FENCE) => mesh.loc.y;

    Math.random2f(.1,1) => mesh.rgba.r;
    Math.random2f(.1,1) => mesh.rgba.g;
    Math.random2f(.1,1) => mesh.rgba.b;
    Math.random2f(0,0) => mesh.rgba.a;
    Math.random2f(0,360) => mesh.ori.y;

    // add
    es << mesh;
}

VREntity @ es2[0];
float es2t[0];

fun void makeTwo()
{
    // make a some points
    VR.makeEntity("two"+es.size(),"flare") @=> VREntity f;
    // set the texture
    f.setString( "texture", "texture:flare-1");
    // loc
    Math.random2f(5,100) => p.mag;
    Math.random2f(-pi,pi) => p.phase;
    p$complex => c;
    c.re => f.loc.x;
    c.im => f.loc.y;
    f.sca.setAll(10);
    Math.random2f(FRONT,FRONT_FENCE) => f.loc.z;

    Math.random2f(1,1) => f.rgba.r;
    Math.random2f(1,1) => f.rgba.g;
    Math.random2f(1,1) => f.rgba.b;
    Math.random2f(0,0) => f.rgba.a;

    // add
    es2 << f;
    es2t << Math.random2f(0,2*pi);

    // add to world
    VR.root().addChild( f );
}

VREntity @ es3[0];
float es3t[0];

-500 => float FRONT3;
FRONT3 * .5 => float FRONT_FENCE3;
300 => float BACK3;
BACK3 * .5 => float BACK_FENCE3;

fun void makeThree( float inner, float outer )
{
    // make a some points
    VR.makeEntity("three"+es.size(),"mesh") @=> VREntity f;
    // set the texture
    f.setString( "texture", "texture:flare-1");

    f.eval( "draw points" );
    repeat(4000)
    {
        // loc
        Math.random2f(inner,outer) => p.mag;
        Math.random2f(-pi,pi) => p.phase;
        p$complex => c;
        c.re => v.x;
        Math.random2f(-1,1) => v.y;
        c.im => v.z;
        f.eval( "vertex", v );
    }

    0 => f.loc.x;
    0 => f.loc.z;
    Math.random2f(FRONT3,FRONT_FENCE3) => f.loc.y;

    Math.random2f(1,1) => f.rgba.r;
    Math.random2f(1,1) => f.rgba.g;
    Math.random2f(1,1) => f.rgba.b;
    Math.random2f(0,0) => f.rgba.a;

    // add
    es3 << f;
    es3t << .0000002 / Math.pow((inner+outer)/6.0/outer,10);
    <<< "spin:", es3t[es3t.size()-1] >>>;

    // add to world
    VR.root().addChild( f );
}

// disable lights
VR.allLightsOn();

// bang detector
fun void bangDetect()
{
    while( true )
    {
        if( envL.last() > 0.0001 )
        {
            <<< "BANG!!", now/second >>>;
            100::ms => now;
        }
        10::ms => now;
    }
}

// detector
// spork ~ bangDetect();
VREntity @ e;

// loop
while( true )
{
    for( int i; i < es.size(); i++ )
    {
        es[i] @=> e;
        if( e.loc.y <= FRONT_FENCE )
            1-Math.fabs((e.loc.y-FRONT_FENCE)/(FRONT-FRONT_FENCE)) => e.rgba.a;
        else if( e.loc.y >= BACK_FENCE )
            1-Math.fabs((e.loc.y-BACK_FENCE)/(BACK-BACK_FENCE)) => e.rgba.a;
        else
            1 => e.rgba.a;
        5 +=> e.ori.y;
        .5 +=> e.loc.y;
        if( e.loc.y > BACK ) FRONT => e.loc.y;
    }

    for( int i; i < es2.size(); i++ )
    {
        es2[i] @=> e;
        if( e.loc.z <= FRONT_FENCE )
            1-Math.fabs((e.loc.z-FRONT_FENCE)/(FRONT-FRONT_FENCE)) => e.rgba.a;
        else if( e.loc.z >= BACK_FENCE )
            1-Math.fabs((e.loc.z-BACK_FENCE)/(BACK-BACK_FENCE)) => e.rgba.a;
        else
            1 => e.rgba.a;

        Math.pow(envL.last(),1)*100 *=> e.rgba.a;

        5 * (1 + .2*Math.sin(es2t[i])) => e.sca.setAll; .1 +=> es2t[i];
        .2 +=> e.loc.z;
        if( e.loc.z > BACK ) FRONT => e.loc.z;
    }

    for( int i; i < es3.size(); i++ )
    {
        es3[i] @=> e;
        if( e.loc.y <= FRONT_FENCE3 )
            1-Math.fabs((e.loc.y-FRONT_FENCE3)/(FRONT3-FRONT_FENCE3)) => e.rgba.a;
        else if( e.loc.y >= BACK_FENCE3 )
            1-Math.fabs((e.loc.y-BACK_FENCE3)/(BACK3-BACK_FENCE3)) => e.rgba.a;
        else
            1 => e.rgba.a;

        es3t[i] +=> e.ori.y;
        .5 +=> e.loc.y;
        if( e.loc.y > BACK3 ) FRONT3 => e.loc.y;
    }

    // VR.root().rgba.setAll(Math.pow(envL.last(),.75)*500);

    // synch with display
    VR.displaySync() => now;
}

fun void kbf()
{
    while( true )
    {
        // wait
        kb => now;
        // wait
        while( kb.recv(msg) )
        {
            if( !msg.isButtonDown() )
                continue;

            // <<< "kb:", msg.ascii >>>;
            if( msg.ascii == 49 ) // 1
            {
                repeat(10) makeOne();
            }
            else if( msg.ascii == 50 ) // 2
            {
                repeat(10) makeTwo();
            }
            else if( msg.ascii == 51 ) // 3
            {
                for(int i; i < 10; i++ )
                    makeThree( 2*(20+i*15), 4*(20+i*15+5) );
            }
        }
    }
}