Add some chords

Add some chords

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());
}

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"],
         ["bIII","biii"],
         ["III","iii"],
         ["IV","iv"],
         ["bV","bv"],
         ["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;
        }

    }
    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 iii;
Chord III;
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],[[0.1,0.1,0.1,0.3,0.3,0.1],[0.1,0.1,0.1,0.1,0.1,0.5]]);
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]]);
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],[[0.3,0.4,0.2,0.1],[0.2,0.4,0.1,0.3]]);
iv.init(5,1,[VI,V,vi],[[0.3,0.4,0.3],[0.2,0.4,0.4]]);
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],[[0.2,0.3,0.1,0.3,0.1],[0.2,0.2,0.2,0.2,0.2]]);
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(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());
}


Removed the multi stream from master

Removed the multi stream from master

/*
Data on Acid hack

Iain Emsley

SSI hack March 2015

*/

Flute flute => 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 outname;

int texta[5000];

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

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);
}

//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) {
    // start the note
    Std.mtof( note ) => flute.freq;
    velocity => flute.noteOn;
    .6      => flute.gain;
    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

*/

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;
}


add greeter function

add greeter function

fun string greeter( string a )
{
    <<< "Hello " + a >>>;
}

greeter("DevFest") => string greet;

"monkey" => string name;
<<< "hello " + name >>>;


Update to_stereo_wav_with_gainParams.ck

Update to_stereo_wav_with_gainParams.ck

added gain possibility.

//me.arg(0) => string filename;
//if( filename.length() == 0 ) "foo.wav" => filename;

dac => Mix2 regulator => WvOut2 w => blackhole;
//"data/session" => w.autoPrefix;

regulator.gain(1.0);
"woooot.wav" => w.wavFilename;
1 => w.record;
3::second => now;

// everything in between gets recorded.

0 => w.record;

//me.arg(0) => string filename;
//if( filename.length() == 0 ) "foo.wav" => filename;

dac => WvOut2 w => blackhole;
//"data/session" => w.autoPrefix;
"woooot.wav" => w.wavFilename;
1 => w.record;
3::second => now;

// everything in between

0 => w.record;


Better debug info printing

Better debug info printing

<<< ">>> Testing Stammer class", "">>>;

<<< ">>> Loading class", "">>>;
Stammer stm => dac;
2.0 => stm.set_freq;
spork ~ stm.on();

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

<<< ">>> Running test", "">>>;
buf_2 => stm;
10::second => now;

buf_2 =< stm;
buf_1 => stm;
10::second => now;

buf_2 => stm;
10::second => now;

<<< "Testing Stammer class" >>>;

<<< "Loading class" >>>;
Stammer stm => dac;
2.0 => stm.set_freq;
spork ~ stm.on();

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

<<< "Running test" >>>;
buf_2 => stm;
10::second => now;

buf_2 =< stm;
buf_1 => stm;
10::second => now;

buf_2 => stm;
10::second => now;


created instrument object, added instrument buffers

2000 => int padding;
2 => int instrument_buffers;

// instrument object
class Instrument {
    string filename;
    SndBuf buf[8];
    int plays;
}

// data files
me.sourceDir() + "/data/ck_instruments.csv" => string instruments_file;
me.sourceDir() + "/data/ck_sequence.csv" => string sequence_file;

// read data files
FileIO instruments_fio;
FileIO sequence_fio;
instruments_fio.open( instruments_file, FileIO.READ );
sequence_fio.open( sequence_file, FileIO.READ );

// check if files are valid
if( !instruments_fio.good() || !sequence_fio.good() )
{
    cherr <= "can't open instrument and/or sequence files for reading..."
          <= IO.newline();
    me.exit();
}

// create instruments array
Instrument instruments[128];

// read instruments file
while( instruments_fio.more() )
{
    // read instrument index and filename
    Std.atoi(instruments_fio.readLine()) => int instrument_index;
    me.sourceDir() + "/" + instruments_fio.readLine() => instruments[instrument_index].filename;
    0 => instruments[instrument_index].plays;
    // create buffers from filename
    for( 0 => int i; i < instrument_buffers; i++ )
    {
        instruments[instrument_index].filename => instruments[instrument_index].buf[i].read;
        // set position to end, so it won't play immediately upon open
        instruments[instrument_index].buf[i].samples() => instruments[instrument_index].buf[i].pos;
        instruments[instrument_index].buf[i] => dac;
    }

}

// Add padding
padding::ms => now;

// read sequence from file
while( sequence_fio.more() ) {
    Std.atoi(sequence_fio.readLine()) => int instrument_index;
    Std.atoi(sequence_fio.readLine()) => int position;
    Std.atof(sequence_fio.readLine()) => float gain;
    Std.atof(sequence_fio.readLine()) => float rate;
    Std.atoi(sequence_fio.readLine()) => int milliseconds;

    // wait duration
	if (milliseconds > 0)
    {
        milliseconds::ms => now;
    }

    // choose buffer index
    instruments[instrument_index].plays % instrument_buffers => int buffer_index;
    instruments[instrument_index].plays++;

    // play the instrument
    position => instruments[instrument_index].buf[buffer_index].pos;
    gain => instruments[instrument_index].buf[buffer_index].gain;
    rate => instruments[instrument_index].buf[buffer_index].rate;
}

// Add padding
padding::ms => now;

<<< "Done." >>>;

2000 => int padding;

// data files
me.sourceDir() + "/data/ck_instruments.csv" => string instruments_file;
me.sourceDir() + "/data/ck_sequence.csv" => string sequence_file;

// read data files
FileIO instruments_fio;
FileIO sequence_fio;
instruments_fio.open( instruments_file, FileIO.READ );
sequence_fio.open( sequence_file, FileIO.READ );

// check if files are valid
if( !instruments_fio.good() || !sequence_fio.good() )
{
    cherr <= "can't open instrument and/or sequence files for reading..."
          <= IO.newline();
    me.exit();
}

// create instruments from file
SndBuf instruments[120];
while( instruments_fio.more() )
{
    Std.atoi(instruments_fio.readLine()) => int instrument_index;
    me.sourceDir() + "/" + instruments_fio.readLine() => string filename;
    filename => instruments[instrument_index].read;
    // set position to end, so it won't play immediately upon open
    instruments[instrument_index].samples() => instruments[instrument_index].pos;
    instruments[instrument_index] => dac;
}

// Add padding
padding::ms => now;

// read sequence from file
while( sequence_fio.more() ) {
    Std.atoi(sequence_fio.readLine()) => int instrument_index;
    Std.atoi(sequence_fio.readLine()) => int position;
    Std.atof(sequence_fio.readLine()) => float gain;
    Std.atof(sequence_fio.readLine()) => float rate;
    Std.atoi(sequence_fio.readLine()) => int milliseconds;

	if (milliseconds > 0)
    {
        milliseconds::ms => now;
    }

    position => instruments[instrument_index].pos;
    gain => instruments[instrument_index].gain;
    rate => instruments[instrument_index].rate;
}

// Add padding
padding::ms => now;

<<< "Done." >>>;


Revert "Implementation change"

Revert "Implementation change"

This reverts commit 0933f1697aec78d908f17c10e2acef03b5c3641a.

/* 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;
}

/* 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
{
    0=>int style;
    string name;                      //how you call it
    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;
        getPrabablities()@=>float p[];
        for (0=>int i; i<p.cap();i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return this;
    }
    fun float[] getPrabablities()
    {
        if (style==0)
            return probabilities[0];
    }
    fun void setStyle(){}           //may be used to change probabilities
}

//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.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 >>>;
    current.getNextChord()@=>current;
    6::second=>now;
}


Added direct chords sound output

Added direct chords sound output

Running "chordProgression" directly outputs the sound. Sounds cool.

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()
    {
        return getNextChord(0);
    }
    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();i++)
        {
            p[i]+=>c;
            if (rand<=c)
                return next[i];
        }
        return this;
    }
    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];
    }
    fun int[] getNotesWithin()
    {
        if (type==0)
        {
            return [root,root+4,root+7];
        }
        if (type==1)
        {
            return [root,root+3,root+7];
        }
        if (type==2)
        {
            return [root,root+3,root+6];
        }
        return null;
    }
}

//runing code starts here
OscSend send;
"localhost" => string hostname;
6449 => int port;
send.setHost(hostname,port);
Chord previous;
Chord current;
Chord I;
Chord ii;
Chord iii;
Chord III;
Chord IV;
Chord V;
Chord V7;
Chord vi;
I.init(0,0,[I,ii,III,IV,V,vi],[[0.1,0.1,0.1,0.3,0.3,0.1],[0.1,0.1,0.1,0.1,0.1,0.5]]);
ii.init(2,1,[I,iii,III,V,vi],[[0.1,0.1,0.3,0.4,0.1],[0.1,0.4,0.3,0.1,0.1]]);
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],[[0.6,0.4],[0.3,0.7]]);
IV.init(5,0,[I,V,III],[[0.3,0.6,0.1],[0.2,0.5,0.3]]);
V.init(7,0,[I,vi,ii,iii],[[0.5,0.2,0.1,0.2],[0.3,0.4,0.1,0.2]]);
vi.init(9,1,[I,ii,iii,IV,V,vi],[[0.1,0.3,0.1,0.3,0.1,0.1],[0.1,0.2,0.2,0.2,0.2,0.1]]);
I @=> current;
Rhodey  instruments[4];
for (0=>int i; i < instruments.cap(); i++)
{
    instruments[i]=>dac;
}
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.getNotesWithin()@=>int notes[];
    for (0=>int j;j<4;j++)
    {
        0.7::second=>now;
        for (0=>int i; i < instruments.cap(); i++)
        {
            Std.mtof(48+key+(notes[i%notes.cap()])%12)=>instruments[i].freq;
            if (j==0)
                0.2=>instruments[i].noteOn;
            else if (Math.random2f(0,1)<0.7)
                0.1=>instruments[i].noteOn;
        }
    }
    current.getNextChord(1)@=>Chord temp;
    while (temp==previous)
    {
        current.getNextChord(1)@=>temp;
    }
    current @=> previous;
    temp @=> current;
}

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;
}


Update common_functions.ck

Update common_functions.ck

// 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[] transpose(int narray[], int semi_tones){}
    fun int[] join_int_arrays(int arr1[], int arr2[]){}
    fun int[] repeat_int_array(int arr[], int num_times){}
    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[] transpose(int narray[], int semi_tones){
    int oarray[0];
    for(0 => int i; i<narray.cap(); i++){
        oarray << (narray[i]+semi_tones);
    }
    return oarray;
}

fun int[] join_int_arrays(int arr1[], int arr2[]){
    [arr1, arr2] @=> int arr[][];
    int new_arr[0];
    for(0 => int j; j<arr.cap(); j++){

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

fun int[] repeat_int_array(int arr[], int num_times){
    int new_arr[0];
    for(0 => int j; j<num_times; j++){
        for(0 => int i; i<arr.cap(); i++){
            new_arr << arr[i];
        }
    }
    return new_arr;
}

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 -5 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[] join_int_arrays(int arr1[], int arr2[]){}
    fun int[] repeat_int_array(int arr[], int num_times){}
    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[]){
    [arr1, arr2] @=> int arr[][];
    int new_arr[0];
    for(0 => int j; j<arr.cap(); j++){

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

fun int[] repeat_int_array(int arr[], int num_times){
    int new_arr[0];
    for(0 => int j; j<num_times; j++){
        for(0 => int i; i<arr.cap(); i++){
            new_arr << arr[i];
        }
    }
    return new_arr;
}

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 -5 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;
}


Manually merged EOH changes, part 2

Manually merged EOH changes, part 2


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
 *
 *   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.
 * 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() >>>;
        <<< "-------------", "-----------" >>>;
    }
}


no more changes to windchime

no more changes to windchime

its ok.

//WindChime.ck

public class WindChime {

    Mix2 mout;
    NRev rvb => mout;
    rvb.mix(0.22);
    mout.gain(0.3);
    dur a;
    dur d;
    dur s;
    float s_level;
    dur r;
    float midint;
    0.02 => float chime_vol; // default

    rvb => DelayA td => rvb;
    td.delay(70::ms);
    td.max(70::ms);
    td.gain(0.33);

    fun void set_chime_vol(float chime_vol){
        chime_vol => this.chime_vol;
    }

    fun void set_adsr(dur a, dur d, dur s, float s_level, dur r){
        a => this.a;
        d => this.d;
        s => this.s;
        s_level => this.s_level;
        r => this.r;
    }

    fun void s_play_note(){
        SinOsc s => ADSR env => rvb;
        SinOsc s2 => env;
        SinOsc s3 => env;
        SinOsc s0 => env;
        SinOsc m => s;

        env => Pan2 p;
        Math.random2f( 0.8, -0.8 ) => p.pan;
        NRev rvs[2];

        p.left => rvs[0] => mout.left;
        p.right => rvs[1] => mout.right;
        for(0 => int i; i<rvs.cap(); i++){
            rvs[i].mix(0.19);
        }

        s.sync(2);
        s.gain(chime_vol);
        midint => Std.mtof => float gfreq => s.freq;
        s2.freq((gfreq*2) + 0.012);
        s2.gain(chime_vol*0.8);
        s3.freq(gfreq*3);
        s3.gain(chime_vol*.22);
        s0.freq(gfreq*4/(midint/17.65));
        s0.gain(chime_vol*.052);
        m.freq(2 * gfreq);
        m.gain(3000);

        // Envelope config
        env.set( a, d, s_level, r );
        env.keyOn();
        (this.a + this.d + this.s) => now;
        env.keyOff();
        this.r => now;
    }

    fun void play_note(float midint){
        midint => this.midint;
        spork ~ s_play_note();
    }

    // this sets a defult, incase i forget to
    set_adsr( 2::ms, 151::ms, 121::ms, .890, 35::ms );  //a, d, s, r

}

WindChime wc;
ADSR sound_sculpt[2];
wc.mout.left => sound_sculpt[0] => dac.left;
wc.mout.right => sound_sculpt[1] => dac.right;
sound_sculpt[0].set( 0::ms, 0::ms, 1.0, 3235::ms );  //a, d, s, r
sound_sculpt[1].set( 0::ms, 0::ms, 1.0, 3235::ms );  //a, d, s, r
wc.set_chime_vol(0.28);
sound_sculpt[0].keyOn();
sound_sculpt[1].keyOn();
120.0 => float start_note;
for(0 => int i; i<28; i++){
    wc.play_note(start_note-(i*0.6));
    Math.random2f(0.12, 0.112)::second =>now;
}
sound_sculpt[0].keyOff();
sound_sculpt[1].keyOff();
// prevent clicks
7::second => now;

//WindChime.ck

public class WindChime {

    Mix2 mout;
    NRev rvb => mout;
    rvb.mix(0.22);
    mout.gain(0.3);
    dur a;
    dur d;
    dur s;
    float s_level;
    dur r;
    float midint;
    0.02 => float chime_vol; // default

    fun void set_chime_vol(float chime_vol){
        chime_vol => this.chime_vol;
    }

    fun void set_adsr(dur a, dur d, dur s, float s_level, dur r){
        a => this.a;
        d => this.d;
        s => this.s;
        s_level => this.s_level;
        r => this.r;
    }

    fun void s_play_note(){
        SinOsc s => ADSR env => rvb;
        SinOsc s2 => env;
        SinOsc m => s;

        env => Pan2 p;
        Math.random2f( 0.8, -0.8 ) => p.pan;
        NRev rvs[2];

        p.left => rvs[0] => mout.left;
        p.right => rvs[1] => mout.right;
        for(0 => int i; i<rvs.cap(); i++){
            rvs[i].mix(0.19);
        }

        s.sync(2);
        s.gain(chime_vol);
        midint => Std.mtof => float gfreq => s.freq;
        s2.freq(gfreq + 0.012);
        s2.gain(chime_vol);
        m.freq(2 * gfreq);
        m.gain(3000);

        // Envelope config
        env.set( a, d, s_level, r );
        env.keyOn();
        (this.a + this.d + this.s) => now;
        env.keyOff();
        this.r => now;
    }

    fun void play_note(float midint){
        midint => this.midint;
        spork ~ s_play_note();
    }

    // this sets a defult, incase i forget to
    set_adsr( 2::ms, 151::ms, 121::ms, .890, 35::ms );  //a, d, s, r

}

WindChime wc;
wc.mout => dac;
wc.set_chime_vol(0.18);

120.0 => float start_note;
for(0 => int i; i<25; i++){
    wc.play_note(start_note-(i*0.6));
    (0.12 )::second =>now;
}

// prevent clicks
2::second => now;


Delete dBFStoGain.ck

Delete dBFStoGain.ck

moved to /utility_functions/

/* Allows inputting a dBFS value like a normal (sound engineer)
person (e.g. -6dB for a "tame" peak value), and getting a
ChucK "gain" number out (e.g. for -6dB, 0.501187).
The results seem to indicate that ChucK's gain, calculated
using the 'Std.dbtorms()' method, conforms to amplitude
(as a ratio) as shown in the chart at the top of
http://en.wikipedia.org/wiki/Decibel.

I'd call it verified:
dBFStoGain( x ) = y
 +3 = ~1.4
  0 = 1      // Unity gain
 -6 = ~0.5
-12 = ~0.25
*/

// Not exactly rocket science >_<
fun float dBFStoGain(float dBFS){
    return Std.dbtorms( dBFS + 100 );
}


updated osc receive sample

updated osc receive sample

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

fun void printOscInt(string oscPath, string leader)
{
    recv.event(oscPath) @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            chout <= leader <= e.getInt() <= IO.newline();
        }
    }
}

fun void printOscFloat(string oscPath, string leader)
{
    recv.event(oscPath) @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            chout <= leader <= e.getFloat() <= IO.newline();
        }
    }
}

fun void pitch()
{
    printOscFloat("/wii/1/accel/pry/0,f", "");
}

fun void roll()
{
    printOscFloat("/wii/1/accel/pry/1,f", "\t");
}

fun void yaw()
{
    printOscFloat("/wii/1/accel/pry/2,f", "\t\t");
}

fun void accel()
{
    printOscFloat("/wii/1/accel/pry/3,f", "\t\t\t");
}

fun void A()
{
    printOscInt("/wii/1/button/A,i", "\t\t\t\t\t");
}

fun void B()
{
    printOscInt("/wii/1/button/B,i", "\t\t\t\t\t\t");
}

spork ~ pitch();
spork ~ roll();
spork ~ yaw();
spork ~ accel();
spork ~ A();
spork ~ B();

while(true)
{
    1::second => now;
}

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


refactoring, hi ho

refactoring, hi ho

OscRecv           wm;
Launchpad         lp;
OscBank oscBank;

false    =>   int prompt;
50::samp =>   dur gainResolution;
0.0016   => float releaseDecay;
0.00001  => float sustainDecay;
0.00001  => float sostenutoDecay;
0.01     => float pressAttack;
0.80     => float maxNoteGain;
0.0      => float rawGain;
0        =>   int currentTone;
false    =>   int sustain;
              int sustainStatus[8][8];
false    =>   int sostenuto;
              int sostenutoStatus[8][8];
0        =>   int lpChannel;

LaunchpadColor.red => int keyOnColor;
LaunchpadColor.lightRed => int keySustainColor;
LaunchpadColor.lightRed => int keySostenutoColor;
LaunchpadColor.red => int toneChoiceColor;

fun void setup()
{
    OscBank.OscBank(8, 8, 1, 5, 82.4068867, 12.0) @=> oscBank;

    if(prompt) {
        intPrompt("Enter Midi Channel for Launchpad input: ") => lpChannel;
        Launchpad.Launchpad(lpChannel) @=> lp;
    } else {
        Launchpad.Launchpad(0) @=> lp;
    }

    me.yield();
    lp.clear();
    lp.setGridLight(8, currentTone, toneChoiceColor);

    spork ~ launchpadListener();
    spork ~ wiiListener();
    spork ~ updateGains();
}

fun void setTone(int toneChoice)
{
    if(toneChoice == currentTone) {
        return;
    } else if(toneChoice == 0) {
        oscBank.setPatch("SinOsc");
    } else if(toneChoice == 1) {
        oscBank.setPatch("SqrOsc");
    } else if(toneChoice == 2) {
        oscBank.setPatch("SawOsc");
    } else if(toneChoice == 3) {
        oscBank.setPatch("TriOsc");
    } else {
        return;
    }

    lp.setGridLight(8, currentTone, 0);
    lp.setGridLight(8, toneChoice, toneChoiceColor);
    toneChoice => currentTone;
}

fun void setSostenuto(int enabled) {
    enabled => sostenuto;
    for(0 => int x; x < 8; x++) {
        for(0 => int y; y < 8; y++) {
            lp.keyDown[x][y] && enabled => sostenutoStatus[x][y];
            if(!enabled && !lp.keyDown[x][y]) {
                lp.setGridLight(x, y, 0);
            }
        }
    }
}

fun void sustainOn()
{
    true => sustain;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            if(lp.keyDown[i][j])
            {
                true => sustainStatus[i][j];
            }
        }
    }
}

fun void sustainOff()
{
    false => sustain;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            false => sustainStatus[i][j];
            if(!lp.keyDown[i][j])
            {
                lp.setGridLight(i, j, 0);
            }
        }
    }
}

fun void release(int column, int row)
{
    Math.max(oscBank.gains[column][row].gain() - releaseDecay, 0.00)
        => oscBank.gains[column][row].gain;
}

fun void updateSustain(int column, int row, float targetGain)
{
    if(sustain && sustainStatus[column][row])
    {
        Math.max(oscBank.gains[column][row].gain() - sustainDecay, 0.00)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        release(column, row);
    }
}

fun void updateSostenuto(int column, int row, float targetGain)
{
    if(sostenuto && sostenutoStatus[column][row])
    {
        Math.max(oscBank.gains[column][row].gain() - sostenutoDecay, 0.00)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        updateSustain(column, row, targetGain);
    }
}

fun void update(int column, int row, float targetGain)
{
    if(lp.keyDown[column][row] && targetGain > oscBank.gains[column][row].gain())
    {
        Math.min(oscBank.gains[column][row].gain() + pressAttack, maxNoteGain)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        updateSostenuto(column, row, targetGain);
    }
}

fun void updateGains()
{
    float targetGain;
    while(true) {
        // Math.max(0.0, (rawGain - 32) / 95.0) => targetGain;
        rawGain => targetGain;

        for(0 => int i; i < 8; i++)
        {
            for(0 => int j; j < 8; j++)
            {
                update(i, j, targetGain);
            }
        }

        gainResolution => now;
    }
}

fun int intPrompt(string msg)
{
    int in;
    ConsoleInput cin;
    StringTokenizer tok;
    cin.prompt(msg) => now;
    while(cin.more())
    {
        tok.set(cin.getLine());
        while(tok.more())
        {
            Std.atoi(tok.next()) => in;
        }
    }
    return in;
}

fun void launchpadListener()
{
    while(true)
    {
        lp.e => now;

        // ignore button presses that are not on the grid
        if(lp.e.column < 0 || lp.e.column > 8) continue;
        if(lp.e.row < 0 || lp.e.row > 7) continue;

        if(lp.e.column == 8)
        {
            if(lp.e.velocity == 127)
            {
                setTone(lp.e.row);
            }
        }
        else if(lp.e.velocity == 127)
        {
            if(sustain)
            {
                true => sustainStatus[lp.e.column][lp.e.row];
            }
            lp.setGridLight(lp.e.column, lp.e.row, keyOnColor);
            1 => oscBank.bank[lp.e.column][lp.e.row].op;
        }
        else if(sostenuto && sostenutoStatus[lp.e.column][lp.e.row])
        {
            lp.setGridLight(lp.e.column, lp.e.row, keySostenutoColor);
        }
        else if(sustain && sustainStatus[lp.e.column][lp.e.row])
        {
            lp.setGridLight(lp.e.column, lp.e.row, keySustainColor);
        }
        else
        {
            lp.setGridLight(lp.e.column, lp.e.row, 0);
        }
    }
}

fun void sustainListener()
{
    wm.event("/wii/1/button/B,i") @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            if(e.getInt() == 0)
            {
                sustainOff();
            }
            else
            {
                sustainOn();
            }
        }
    }
}

fun void sostenutoListener()
{
    wm.event("/wii/1/button/A,i") @=> OscEvent e;
    while(true) {
        e => now;
        while(e.nextMsg() != 0) {
            setSostenuto(e.getInt() != 0);
        }
    }
}

fun void accelListener()
{
    wm.event("/wii/1/accel/pry/3,f") @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            Math.max(0.0, e.getFloat() - 0.22) => rawGain;
            chout <= rawGain <= IO.newline();
        }
    }
}

fun void wiiListener()
{
    6449 => wm.port;
    // 8000 => wm.port;
    wm.listen();
    spork ~ sustainListener();
    spork ~ sostenutoListener();
    spork ~ accelListener();
    while(true)
    {
        1::second => now;
    }
}

setup();

while(true)
{
    100::ms => now;
}

OscRecv           wm;
Launchpad         lp;
OscBank oscBank;

false    =>   int prompt;
50::samp =>   dur gainResolution;
0.0016   => float releaseDecay;
0.00001   => float sustainDecay;
0.00001   => float sostenutoDecay;
0.01     => float pressAttack;
0.80     => float maxNoteGain;
0.0      =>   float rawGain;
0        =>   int currentTone;
false    =>   int sustain;
              int sustainStatus[8][8];
false    =>   int sostenuto;
              int sostenutoStatus[8][8];
0        =>   int lpChannel;

LaunchpadColor.red => int keyOnColor;
LaunchpadColor.lightRed => int keySustainColor;
LaunchpadColor.lightRed => int keySostenutoColor;
LaunchpadColor.red => int toneChoiceColor;
// ToneCalc.grid(8, 8, 1, 5,  82.4068867, 12.0) @=> float toneMap[][];
// ToneCalc.grid(8, 8, 1, 5, 55.0, 12.0) @=> float toneMap[][];

fun void setup()
{
    // OscBank.OscBank(8, 8, 1, 5, 55.0, 12.0) @=> oscBank;
    OscBank.OscBank(8, 8, 1, 5, 82.4068867, 12.0) @=> oscBank;

    if(prompt)
    {
        intPrompt("Enter Midi Channel for Launchpad input: ") => lpChannel;

        Launchpad.Launchpad(lpChannel) @=> lp;
    }
    else
    {
        Launchpad.Launchpad(0) @=> lp;
    }

    me.yield();
    lp.clear();
    lp.setGridLight(8, currentTone, toneChoiceColor);

    spork ~ launchpadListener();
    spork ~ wiiListener();
    spork ~ updateGains();
}

fun void setTone(int toneChoice)
{
    if(toneChoice == currentTone)
    {
        return;
    }

    if(toneChoice == 0)
    {
        oscBank.setPatch("SinOsc");
    }
    else if(toneChoice == 1)
    {
        oscBank.setPatch("SqrOsc");
    }
    else if(toneChoice == 2)
    {
        oscBank.setPatch("SawOsc");
    }
    else if(toneChoice == 3)
    {
        oscBank.setPatch("TriOsc");
    }
    else
    {
        return;
    }

    lp.setGridLight(8, currentTone, 0);
    lp.setGridLight(8, toneChoice, toneChoiceColor);
    toneChoice => currentTone;
}

fun void sostenutoOn()
{
    true => sostenuto;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            if(lp.keyDown[i][j])
            {
                true => sostenutoStatus[i][j];
            }
        }
    }
}

fun void sostenutoOff()
{
    false => sostenuto;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            false => sostenutoStatus[i][j];
            if(!lp.keyDown[i][j])
            {
                lp.setGridLight(i, j, 0);
            }
        }
    }
}

fun void sustainOn()
{
    true => sustain;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            if(lp.keyDown[i][j])
            {
                true => sustainStatus[i][j];
            }
        }
    }
}

fun void sustainOff()
{
    false => sustain;
    for(0 => int i; i < 8; i++)
    {
        for(0 => int j; j < 8; j++)
        {
            false => sustainStatus[i][j];
            if(!lp.keyDown[i][j])
            {
                lp.setGridLight(i, j, 0);
            }
        }
    }
}

fun void release(int column, int row)
{
    Math.max(oscBank.gains[column][row].gain() - releaseDecay, 0.00)
        => oscBank.gains[column][row].gain;
}

fun void updateSustain(int column, int row, float targetGain)
{
    if(sustain && sustainStatus[column][row])
    {
        Math.max(oscBank.gains[column][row].gain() - sustainDecay, 0.00)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        release(column, row);
    }
}

fun void updateSostenuto(int column, int row, float targetGain)
{
    if(sostenuto && sostenutoStatus[column][row])
    {
        Math.max(oscBank.gains[column][row].gain() - sostenutoDecay, 0.00)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        updateSustain(column, row, targetGain);
    }
}

fun void update(int column, int row, float targetGain)
{
    if(lp.keyDown[column][row] && targetGain > oscBank.gains[column][row].gain())
    {
        Math.min(oscBank.gains[column][row].gain() + pressAttack, maxNoteGain)
            => oscBank.gains[column][row].gain;
    }
    else
    {
        updateSostenuto(column, row, targetGain);
    }
}

fun void updateGains()
{
    float targetGain;
    while(true) {
        // Math.max(0.0, (rawGain - 32) / 95.0) => targetGain;
        rawGain => targetGain;

        for(0 => int i; i < 8; i++)
        {
            for(0 => int j; j < 8; j++)
            {
                update(i, j, targetGain);
            }
        }

        gainResolution => now;
    }
}

fun int intPrompt(string msg)
{
    int in;
    ConsoleInput cin;
    StringTokenizer tok;
    cin.prompt(msg) => now;
    while(cin.more())
    {
        tok.set(cin.getLine());
        while(tok.more())
        {
            Std.atoi(tok.next()) => in;
        }
    }
    return in;
}

fun void launchpadListener()
{
    while(true)
    {
        lp.e => now;

        // ignore button presses that are not on the grid
        if(lp.e.column < 0 || lp.e.column > 8) continue;
        if(lp.e.row < 0 || lp.e.row > 7) continue;

        if(lp.e.column == 8)
        {
            if(lp.e.velocity == 127)
            {
                setTone(lp.e.row);
            }
        }
        else if(lp.e.velocity == 127)
        {
            if(sustain)
            {
                true => sustainStatus[lp.e.column][lp.e.row];
            }
            lp.setGridLight(lp.e.column, lp.e.row, keyOnColor);
            1 => oscBank.bank[lp.e.column][lp.e.row].op;
        }
        else if(sostenuto && sostenutoStatus[lp.e.column][lp.e.row])
        {
            lp.setGridLight(lp.e.column, lp.e.row, keySostenutoColor);
        }
        else if(sustain && sustainStatus[lp.e.column][lp.e.row])
        {
            lp.setGridLight(lp.e.column, lp.e.row, keySustainColor);
        }
        else
        {
            lp.setGridLight(lp.e.column, lp.e.row, 0);
        }
    }
}

fun void sustainListener()
{
    wm.event("/wii/1/button/B,i") @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            if(e.getInt() == 0)
            {
                sustainOff();
            }
            else
            {
                sustainOn();
            }
        }
    }
}

fun void sostenutoListener()
{
    wm.event("/wii/1/button/A,i") @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            if(e.getInt() == 0)
            {
                sostenutoOff();
            }
            else
            {
                sostenutoOn();
            }
        }
    }
}

fun void accelListener()
{
    wm.event("/wii/1/accel/pry/3,f") @=> OscEvent e;
    while(true)
    {
        e => now;
        while(e.nextMsg() != 0)
        {
            Math.max(0.0, e.getFloat() - 0.22) => rawGain;
            chout <= rawGain <= IO.newline();
        }
    }
}

fun void wiiListener()
{
    6449 => wm.port;
    // 8000 => wm.port;
    wm.listen();
    spork ~ sustainListener();
    spork ~ sostenutoListener();
    spork ~ accelListener();
    while(true)
    {
        1::second => now;
    }
}

setup();

while(true)
{
    100::ms => now;
}