Skip to content

GUI-Less DAW implemented using ChucK language

Posted on:June 1, 2016 at 12:44 PM

Table Of Contents

Open Table Of Contents

Composition using this project:

GUI-less DAW

A DAW(digital audio workstation) do not have a graphical user interface, yet includes essential features for music production:

  1. a mixer: Master,Bus,Fx Send etc.
  2. basic music modules: Note, Scale, Chord
  3. instruments: drum machine, bass ,guitar etc.
  4. effects : FeedBackDelay etc.
  5. algorithm composition modules
    1. algorithm sequence generator
    2. implemented: Fibonacci, Euclid
    3. TODO: cellular automata, Markov chain etc
  6. spectral composition
    1. risset appregio, resset beat
    2. FibonacciPad
  7. grain synthesis

All these features are implemented using ChucK language, a real-time audio programming language. This project is hosted on github: https://github.com/lmaxwell/chuckComposition

code structure

├── lib
│   ├── basic
│   │   ├── BPM.ck
│   │   ├── Chord.ck
│   │   └── Scale.ck
│   ├── effect
│   │   ├── FbDelay.ck
│   │   └── RtGrain.ck
│   ├── instrument
│   │   ├── FibonacciArp.ck
│   │   ├── LFO.ck
│   │   ├── MandolinBass.ck
│   │   ├── MandoPlayer.ck
│   │   ├── RissetBeat.ck
│   │   ├── RissetChordBeat.ck
│   │   └── RissetNoteBeat.ck
│   ├── mixer
│   │   └── Mixer.ck
│   └── seq
│       ├── EuclidSeq.ck
│       └── FibonacciSeq.ck
├── pop
│   ├── 07.ck
│   └── 27.ck
├── README.md
├── run.ck
├── autogen.sh

How to run

The following command runs pop/27.ck

chuck run.ck:pop/27.ck

run.ck helps to preload all the modules in “lib” directory

Machine.add("lib/basic/BPM.ck");
Machine.add("lib/basic/Chord.ck");
Machine.add("lib/basic/Scale.ck");
Machine.add("lib/effect/FbDelay.ck");
Machine.add("lib/effect/RtGrain.ck");
Machine.add("lib/instrument/FibonacciArp.ck");
Machine.add("lib/instrument/LFO.ck");
Machine.add("lib/instrument/MandoPlayer.ck");
Machine.add("lib/instrument/MandolinBass.ck");
Machine.add("lib/instrument/RissetBeat.ck");
Machine.add("lib/instrument/RissetChordBeat.ck");
Machine.add("lib/instrument/RissetNoteBeat.ck");
Machine.add("lib/mixer/Mixer.ck");
Machine.add("lib/seq/EuclidSeq.ck");
Machine.add("lib/seq/FibonacciSeq.ck");
for(0=>int i;i<me.args();i++)
  Machine.add(me.arg(i)); 

run.ck can be updated by autogen.sh when new modules are added into “lib” directory.

bash autogen.sh

pop/27.ck

pop/27.ck is a song composed with 280 lines of code based this library. This is what it sounds like:

Mixer.master.set();
0.3=>Mixer.master.gain;
Scale scale;
scale.set(70,"aeolian");
Chord chord;
RissetChordBeat rcb  => Mixer.bus[0];
0.6=>Mixer.bus[0].gain;
0.5=>Mixer.bus[0].send[0].gain;
//-0.5=>Mixer.bus[0].pan;
BPM bpm;
bpm.set(120);
FbDelay fbd;
fbd.setTime(bpm.quarterNote*3.0/4.0);
fbd.setFeedBack(0.6);
fbd.setMix(1);
//rcb=>fbd=>Mixer.bus[1];

bpm.quarterNote-now%bpm.quarterNote => now;
//Machine.add("util/rec-auto-stereo.ck");


Impulse i => Moe moe => Mixer.bus[2];
Dinky dk => moe;
0.5=>dk.gain;
i=>Larry larry => Mixer.bus[2];
dk =>larry;
0.8=>Mixer.bus[2].gain;
-0.9=>Mixer.bus[2].pan;
0.9=>Mixer.fxdelay.pan;
0.5=>Mixer.bus[2].send[0].gain;
0.0=>Mixer.bus[2].send[1].gain;
Mixer.fxdelay.fbdelay.setTime(bpm.quarterNote*3.0/4.0);
//Mixer.fxdelay.fbdelay.setFeedBack(0.8);
spork ~moe.run();
spork ~larry.run();


RissetNoteBeat rnb=> Mixer.bus[1];
0.4=>Mixer.bus[1].send[0].gain;
0.7=>Mixer.bus[1].gain;
0.5=>Mixer.bus[1].pan;
RissetNoteBeat rnb_low => Mixer.bus[3];
0.4=>Mixer.bus[3].send[0].gain;
0.8=>Mixer.bus[3].gain;

EuclidSeq impulseseq;
EuclidSeq dkseq;
dkseq.set(16,9,0);

int measure;
LFO lfo_rcb;
120=>lfo_rcb.sync;
//spork ~lfo_rcb.am(rcb,2,8,1::samp,10::samp);

LFO lfo_wave;



while(true)
{
/*
Wave wave => Mixer.bus[4];
0.05=>Mixer.bus[4].gain;
0.6=>Mixer.bus[4].send[0].gain;
1000=>wave.freq;
-0.2=>Mixer.bus[4].pan;
spork ~wave.run(bpm.quarterNote*4*16);
spork ~lfo_wave.am(wave,2,10,10::ms,15::ms);
*/
section1();
section2();
section3();
section4();
section5();
section6();
/*
wave.stop();
*/
}



fun void section6()
{
    //section 3
    0=> measure;


    while(measure<16)
    {
        Math.random2(10,30)=>int num;
        <<<num>>>;
        rnb.set(num);
        Math.random2(4,10)=> num;
        rnb_low.set(num);
        <<<num>>>;
        Math.random2(10,30)=>num;
        rcb.set(num);
        <<<num>>>;
        chord.set(scale.get(1),"minor7");
            spork ~dinky(chord,8*BPM.quarterNote,-1,2);
        spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
        spork ~rnb.play(Std.mtof(chord.sample()+24),bpm.quarterNote*3);
        rcb.play(chord,8*BPM.quarterNote);
        chord.set(scale.get(7)-12,"dom7");
            spork ~dinky(chord,8*BPM.quarterNote,-2,2);
        spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
        spork ~rnb.play(Std.mtof(chord.sample()+24),bpm.quarterNote*3);
        rcb.play(chord,8*BPM.quarterNote);
        measure+4=>measure;
    }

}


fun void section5()
{
//section 3
0=> measure;
while(measure<16)
{
    Math.random2(10,30)=>int num;
    <<<num>>>;
    rnb.set(num);
    Math.random2(4,10)=> num;
    rnb_low.set(num);
    <<<num>>>;
    Math.random2(10,30)=>num;
    rcb.set(num);
    <<<num>>>;
    chord.set(scale.get(1),"minor7");
        spork ~dinky(chord,8*BPM.quarterNote,-1,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
    spork ~rnb.play(Std.mtof(chord.sample()+24),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    chord.set(scale.get(7)-12,"dom7");
        spork ~dinky(chord,8*BPM.quarterNote,-2,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
    spork ~rnb.play(Std.mtof(chord.sample()+24),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    measure+4=>measure;
}
}
fun void section4()
{
//section 3
0=> measure;
while(measure<16)
{
    Math.random2(10,30)=>int num;
    <<<num>>>;
    rnb.set(num);
    Math.random2(4,10)=> num;
    rnb_low.set(num);
    <<<num>>>;
    Math.random2(10,30)=>num;
    rcb.set(num);
    <<<num>>>;
    chord.set(scale.get(1),"minor7");
        spork ~dinky(chord,8*BPM.quarterNote,-1,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    chord.set(scale.get(7)-12,"dom7");
        spork ~dinky(chord,8*BPM.quarterNote,-2,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-24),bpm.quarterNote*6);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    measure+4=>measure;
}
}

fun void section3()
{
//section 3
impulseseq.setRotation(2);
0=> measure;
while(measure<16)
{
    Math.random2(10,30)=>int num;
    <<<num>>>;
    rnb.set(num);
    Math.random2(4,10)=> num;
    rnb_low.set(num);
    <<<num>>>;
    Math.random2(10,30)=>num;
    rcb.set(num);
    <<<num>>>;
    chord.set(scale.get(1),"minor7");
        spork ~dinky(chord,8*BPM.quarterNote,-1,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-12),bpm.quarterNote*3);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    chord.set(scale.get(7)-12,"dom7");
        spork ~dinky(chord,8*BPM.quarterNote,-2,2);
    spork ~rnb_low.play(Std.mtof(chord.sample()-12),bpm.quarterNote*3);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    measure+4=>measure;
}
}

fun void section2()
{
impulseseq.setRotation(1);
//section 2
0=> measure;
while(measure<16)
{
    Math.random2(10,30)=>int num;
    <<<num>>>;
    rnb.set(num);
    <<<num>>>;
    Math.random2(10,30)=>num;
    rcb.set(num);
    <<<num>>>;
    chord.set(scale.get(1),"minor7");
        spork ~dinky(chord,8*BPM.quarterNote,-1,0);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    chord.set(scale.get(7)-12,"dom7");
        spork ~dinky(chord,8*BPM.quarterNote,-1,1);
    spork ~rnb.play(Std.mtof(chord.sample()+12),bpm.quarterNote*3);
    rcb.play(chord,8*BPM.quarterNote);
    measure+4=>measure;
}
}

fun void section1()
{
//section 1
0=> measure;
while(measure<32)
{
    if (measure == 4)
        spork ~impulse();
    if (measure ==8)
        1.0=>Mixer.bus[2].send[1].gain;
    Math.random2(5,15)=>int num;
    rcb.set(num);
    <<<num>>>;
    chord.set(scale.get(1),"minor7");
    if (measure >16)
        spork ~dinky(chord,8*BPM.quarterNote,-1,0);
    rcb.play(chord,8*BPM.quarterNote);
    chord.set(scale.get(7)-12,"dom7");
    if (measure >16)
        spork ~dinky(chord,8*BPM.quarterNote,-1,0);
    rcb.play(chord,8*BPM.quarterNote);
    measure+4=>measure;
}
}


fun void dinky(Chord chord ,dur _dur, int low,int high)
{
    now + _dur=>time mark;
    dkseq.setRotation(Math.random2(0,16));
    while(now<mark)
    {
        if (dkseq.genNext())
        dk.play(Std.mtof(chord.sample()+Math.random2(low,high)*12),bpm.sixteenthNote);
        else 
            bpm.sixteenthNote=>now;
    }
}
fun void impulse()
{
    impulseseq.set(16,11,1);
    while(true)
    {
        if(impulseseq.genNext())
        {
            1.0=>i.next;
            0.5=>i.gain;
        }
        bpm.sixteenthNote=>now;

    }
}