ChucK is a music programming language (and compiler/synthesizer) written by a professor (Perry Cook) and his students at Princeton University. I'm learning how to use it; I thought that writing about how to use it would help...

Tuesday, January 25, 2005

Multiple DAC's For Multiple Voices

I've been noticing that the example files all seem to be single-voiced, so I've been wondering about doing chords...

So I looked at the definition of the dac in the programming guide and it didn't seem to prohibit there from being more than one reference.

[ugen] dac
* digital/analog converter
* abstraction for underlying audio output device


So I decided to try it out. It works! (Or seems to — running multiple versions of the multi-voice program does seem to cause some interference.)
chuck bpmulti2.ck bpmulti2.ck bpmulti2.ck rec2.ck
seems to cause some interference...

I've reworked the bluespenta.ck file to use multiple dac's (and JCRev's and Echo's to give interest to the secondary voices). You can download it here (right-click and Save, or click to view in a new window). Here's the code:




// bpmulti2.ck
// Bluesy R&R* C Eb F G Bb C -

// try out multiple dac's for multiple voices
// and for more interesting voices, multiple effects too

// scale exercise using TubeBell STK
// added scale run-up run-down to display scale

// modified from examples/wurley.ck by Gary Williams
// even more music for replicants Wurley changed to TubeBell

TubeBell voc=> JCRev r => Echo a => Echo b => Echo c => dac;

// wonder if this will work (it does)
TubeBell voc1=> JCRev r1 => Echo a1 => Echo b1 => Echo c1 => dac;
TubeBell voc2=> JCRev r2 => Echo a2 => Echo b2 => Echo c2 => dac;

// was 220.0
880.0 => voc.freq => voc1.freq => voc2.freq;
0.95 => voc.gain => voc1.gain => voc2.gain;
.8 => r.gain => r1.gain => r2.gain;
.2 => r.mix => r1.mix => r2.mix;

1000::ms => a.max => b.max => c.max;
750::ms => a.delay => b.delay => c.delay;
.50 => a.mix => b.mix => c.mix;

1000::ms => a1.max => b1.max => c1.max;
750::ms => a1.delay => b1.delay => c1.delay;
.50 => a1.mix => b1.mix => c1.mix;

1000::ms => a2.max => b2.max => c2.max;
750::ms => a2.delay => b2.delay => c2.delay;
.50 => a2.mix => b2.mix => c2.mix;

// shred to modulate the mix
fun void vecho_shred( )
{
0.0 => float decider;
0.0 => float mix;
0.0 => float old;
0.0 => float inc;
0 => int n;

// time loop
while( true )
{
std.rand2f(0.0,1.0) => decider;
if( decider < .3 ) 0.0 => mix;
else if( decider < .6 ) .08 => mix;
else if( decider < .8 ) .5 => mix;
else .15 => mix;

// find the increment
(mix-old)/1000.0 => inc;
1000 => n;
while( n-- )
{
old + inc => old;
old => a.mix => b.mix => c.mix;
old => a1.mix => b1.mix => c1.mix;
old => a2.mix => b2.mix => c2.mix;
1::ms => now;
}
mix => old;
std.rand2(2,6)::second => now;
}
}

// let echo shred go
spork ~ vecho_shred();

// function to set tone duration
function int setnotedur() {
std.rand2f( 0.6, 0.8 ) => voc.noteOn;
std.rand2f( 0.6, 0.8 ) => voc1.noteOn;
std.rand2f( 0.6, 0.8 ) => voc2.noteOn;

// duration
if( std.randf() > 0.7 )
{ 1000::ms => now; }
else if( std.randf() > .7 )
{ 500::ms => now; }
else if( std.randf() > -0.8 )
{ .250::second => now; }
else
{
0 => int i;
2 * std.rand2( 1, 3 ) => int pick;
0 => int pick_dir;
0.0 => float pluck;

for( ; i < pick; i++ )
{
std.rand2f(.4,.6) + (float)i*.035 => pluck;
pluck + 0.03 * (float)(i * pick_dir) => voc.noteOn;
std.rand2f(.4,.6) + (float)i*.035 => pluck;
pluck + 0.03 * (float)(i * pick_dir) => voc1.noteOn;
std.rand2f(.4,.6) + (float)i*.035 => pluck;
pluck + 0.03 * (float)(i * pick_dir) => voc2.noteOn;
!pick_dir => pick_dir;
250::ms => now;
}
}

// report
// machine.status();
return( 1 );
}

// Bluesy R&R* C Eb E F G A Bb C
// Blues Pentatonic C Eb F G Bb C
// octave
// MIDI 60 63 64 65 67 69 70 72 0
// 72 75 76 77 79 81 82 84 1
// 84 87 88 89 91 93 94 96 2
// 96 99 100 101 103 105 106 107 3
// NOTE # 0 1 2 3 4 5 6 7

// map notes 2 and 5 to 0 and 7
fun float note_to_midi( int note, int octave ) {
if( note == 0 || note == 2 ){
if( octave == 0 ) { return(60.0); }
else if( octave == 1 ) { return( 72.0 ); }
else if( octave == 2 ) { return( 84.0 ); }
else return( 96.0 );
}
else if( note == 1 ){
if( octave == 0 ) { return(63.0); }
else if( octave == 1 ) { return( 75.0 ); }
else if( octave == 2 ) { return( 87.0 ); }
else return( 99.0 );
}
////////// else if( note == 2 ){
////////// if( octave == 0 ) { return(64.0); }
////////// else if( octave == 1 ) { return( 75.0 ); }
////////// else if( octave == 2 ) { return( 88.0 ); }
////////// else return( 100.0 );
////////// }
else if( note == 3 ){
if( octave == 0 ) { return(65.0); }
else if( octave == 1 ) { return( 77.0 ); }
else if( octave == 2 ) { return( 89.0 ); }
else return( 101.0 );
}
else if( note == 4 ){
if( octave == 0 ) { return(67.0); }
else if( octave == 1 ) { return( 79.0 ); }
else if( octave == 2 ) { return( 91.0 ); }
else return( 103.0 );
}
////////// else if( note == 5 ){
////////// if( octave == 0 ) { return(69.0); }
////////// else if( octave == 1 ) { return( 81.0 ); }
////////// else if( octave == 2 ) { return( 93.0 ); }
////////// else return( 105.0 );
////////// }
else if( note == 6 ){
if( octave == 0 ) { return(70.0); }
else if( octave == 1 ) { return( 82.0 ); }
else if( octave == 2 ) { return( 93.0 ); }
else return( 106.0 );
}
else if( note == 7 || note == 5 ){
if( octave == 0 ) { return(72.0); }
else if( octave == 1 ) { return( 84.0 ); }
else if( octave == 2 ) { return( 96.0 ); }
else return( 107.0 );
}
return( 120.0 ); // error code
}

// vars
0 => int i;
0 => int oct;
0.0 => float freq;
0.0 => float f;

// run up and down scale first, to display scale being featured
"Blues Pentatonic Scale: up" => stdout;
for( 0 => oct; oct < 4; ++oct ) {
for( 0 => i; i < 8; ++i ) {
std.mtof( note_to_midi( i++, oct) ) => f;
f => voc.freq;
chout => "i, freq: " => i => ", " => f => endl;

std.mtof( note_to_midi( i++, oct) ) => f;
f => voc1.freq;
chout => "i, freq: " => i => ", " => f => endl;

std.mtof( note_to_midi( i++, oct) ) => f;
f => voc2.freq;

chout => "i, freq: " => i => ", " => f => endl;
setnotedur();
}
}

"Blues Pentatonic Scale: down" => stdout;
for( 4 => oct; oct > -1; --oct ) {
for( 7 => i; i > -1; --i ) {
std.mtof( note_to_midi( i--, oct) ) => f;
f => voc.freq;
chout => "i, freq: " => i => ", " => f => endl;

std.mtof( note_to_midi( i--, oct) ) => f;
f => voc1.freq;
chout => "i, freq: " => i => ", " => f => endl;

std.mtof( note_to_midi( i--, oct) ) => f;
f => voc2.freq;
chout => "i, freq: " => i => ", " => f => endl;
setnotedur();
}
}

"Change To Random Notes" => stdout;

// our main loop
while( true )
{
std.rand2(0, 7) => i;
std.rand2(0, 3) => int octave;
std.mtof( note_to_midi( i, octave) ) => float freq;
freq => voc.freq;
chout => "i,i1,i2: " => i; // => ", " => freq; // => endl;

std.rand2(0, 7) => i;
std.rand2(0, 3) => octave;
std.mtof( note_to_midi( i, octave) ) => freq;
freq => voc1.freq;
chout => " " => i; // => ", " => freq; // => endl;

std.rand2(0, 7) => i;
std.rand2(0, 3) => octave;
std.mtof( note_to_midi( i, octave) ) => freq;
freq => voc2.freq;
chout => " " => i => endl; // => ", " => freq => endl;

setnotedur();
}




I did some MP3's, they sound really pleasant, but my server is full right now so I can't upload it right now. (I'm pursuing some more space, but I'm waiting for the admins to tell me they've upped by disk space...) Look for bpmulti...mp3 in the recording links for the mp3.