chuckles
Joined: Apr 02, 2007 Posts: 72 Location: San Diego, California
|
Posted: Thu May 03, 2007 10:30 am Post subject:
My take on the ctrl_sequencer example |
|
|
[24 May 2007 -- added a download link for the program -- it shows up at the bottom]
Sort of quiet in this forum lately...what I've been doing is tweaking the example in the ctrl directory called ctrl_sequencer.ck. It wasn't too extensively commented so it was a good exercise in trying to figure out what it was doing.
It was a program that created a mandolin and clarinet "player" and a simple algorithm to play a little two-part "sonata". I finished adding a third voice which had been started, wrote a bunch of comments and experimented with some various code variants.
My thanks to whoever philipd is who I guess wrote the original thing. It's fun to listen to -- for a while!
All comments, changes, improvements, criticism is welcome...
I'm going to add it inline even though it's sort of long; since I personally would rather read the code in a forum than have to download a file. Hope it's not too inconvenient...
chuckles!
Code: | // 05 ctrl_sequencer.ck
// Trio Sonata for Mandolin, Flute and Clarinet
// um, by philipd
// (what is it?)
// based on ctrl_sequencer.ck distributed in the examples\ctrl directory
// This started out as a very cool ChucK program to play an algorithmic
// quasi-Baroque Trio. It's amazingly simple for the good results it gives.
// I took it and added comments, formatting, and fiddled with the code a
// little here and there.
// Runs as one shred
//
// Originally only mandolin and clarinet voices were active; I added some
// code to play the flute voice as well.
//
// NOTE: Beginner zone: this is one of the first things I ever did with
// ChucK. Be kind.
//
// 20070423 tps
// 20070418 tps
// 20070426 tps
// 20070502 tps
// 20070503 tps
// --------------------------------------------------------------------------
//
// Classes used:
// Player.connect, .noteOn, .noteOff
// Note.set, .playOn, .playOnAlt
// Player -> MandPlayer.noteOn
// Player -> FlutePlayer.noteOn, .noteOff
// Player -> ClarPlayer.noteOn, .noteOff
//
// Functions defined:
// newsequence
// swap
class Player
{
UGen @ base; // thus base is a null reference of type UGen
fun void connect( UGen target )
{
base => target; // connect one UGen to another?
}
fun void noteOn ( float note, float vel ) {}
fun void noteOff ( float vel ) {}
}
class MandPlayer extends Player
{
Mandolin m @=> base;
fun void noteOn ( float note, float vel )
{
Std.mtof ( note ) => m.freq;
vel => m.pluck;
}
}
class ClarPlayer extends Player
{
Clarinet c @=> base;
fun void noteOn ( float note, float vel )
{
Std.mtof ( note ) => c.freq;
vel => c.startBlowing;
}
// ClarPlayer is monophonic, so .stopBlowing refers to a the note.
// For a polyphonic Player, you'd need to identify the note to stop.
fun void noteOff ( float vel )
{
vel => c.stopBlowing;
}
}
// 'pears that FlutePlayer hasn't yet been turned on...an exercise
// for the new user...going to make it have some of the same
// characteristics as Clarinet...
// (might be interesting to try the Flute UGen too)
class FlutePlayer extends Player
{
PercFlut f @=> base;
fun void noteOn ( float note, float vel )
{
Std.mtof ( note ) => f.freq;
vel => f.noteOn;
}
fun void noteOff ( float vel )
{
vel => f.noteOff;
}
}
// Note has three methods: .set, .playOn and .playOnAlt
class Note
{
float note;
float vel;
dur length;
fun void set ( float nt, float vl, dur ln )
{
nt => note;
vl => vel;
ln => length;
}
fun void playOn ( Player p )
{
if ( note > 0 )
{
p.noteOn( note , vel );
}
}
fun void playOnAlt( Player p, float noff, float vmul )
// like playOn, but add noff to the note and multiply
// the velocity by a factor vmul
{
p.noteOn( note+noff, vel*vmul );
}
}
// --------------------------------------------------------------------------
// set up some parameters, scale, note and order arrays...
// sequence is an array of Note objects; 12 of them in this case...
12 => int seqn;
Note sequence[seqn];
// order will be an array of ints which will give us the order in
// which to play the sequence
int order[seqn];
// ok.. a simple two octave pentatonic scale. in C it would map to notes
// C D E G A
[0, 2, 4, 7, 9, 12, 14, 16, 19, 21] @=> int scale[];
// 10 => int nscale; // I think scale.cap() is supposed to be able to do this
scale.cap() => int nscale;
// TODO: make this more flexible re tempo...right now notes can only be
// 1/4, 1/8 or 3/8 sec long
// [0.25::second, 0.125::second, 0.125::second, 0.375::second] @=> dur times[];
// 4 => int ntimes;
// or: let's try it thisaway
// [ (1./4.)::second, (1./8.)::second, (1./.8)::second, (3./8.)::second] @=> dur times[];
// made a typo in the third value (1./.8 rather than 1./8.; thus
// 1.25 sec rather than .125 sec -- made an interesting change
[ (1./4.)::second, (1./8.)::second, (1./8.)::second, (3./8.)::second] @=> dur times[];
times.cap() => int ntimes; // seems to work
//fun initialize ( Note sequence, int n ) { // leftover from something?
// --------------------------------------------------------------------------
// the clever thing is he managed to do this with just a couple of functions
// newsequence and swap
fun void newsequence()
{
for ( 0 => int i; i <seqn> order[i];
55 + scale[Std.rand2(0, nscale - 1)] => int note;
times[Std.rand2(0, ntimes - 1)] => dur mydur;
Std.rand2f( 0.75, 0.9 ) => float vel;
sequence[i].set( note, vel, mydur );
}
}
// swap is intended to do limited permutations but exchanging
// a couple entries in the order array (maybe rewrite this as
// a function of type int[]?) A minor gyration is gone through
// to make sure a <b> int a;
( a + Std.rand2(1, seqn-1) ) % seqn => int b;
<<< "swapping ", a, " and ", b >>> ;
order[a] => int tmp;
order[b] => order[a];
tmp => order[a];
}
// --------------------------------------------------------------------------
Gain g => JCRev j => Echo e => dac;
0.95 => j.gain;
0.2 => j.mix;
1.15::second => e.max;
1.0::second => e.delay;
0.3 => e.mix;
// Instantiate some Players...
MandPlayer mand;
ClarPlayer clar;
FlutePlayer flutey;
// Hook em all up to the Gain object...
mand.connect(g);
clar.connect(g);
flutey.connect(g); // and our new player too
// 0.6 => g.gain; this seemed to give slightly too low
// a level when I saved this to a file
0.8 => g.gain;
newsequence();
1 => int loop_count;
while ( true )
{
<<< "loop #", loop_count++ >>>;
for ( 0 => int j ; j <seqn> Note note;
// we can use "note" here again since it's in a different
// scope than the temporary "note" used in the Note class
// definition
// play a mandolin note...
note.playOn ( mand );
// and a clarinet note...
note.playOnAlt ( clar, 12 , 0.7 );
// that's cool, now let's add the new flute note:
note.playOnAlt ( flutey, 5 , 0.7 );
note.length * 2.0 => now;
// play a note 7 semitones higher, 0.33 velocity
note.playOnAlt( mand, 7, 0.33 );
note.length => now;
}
// do the swap function between 1 and 2 times.
for ( Std.rand2(0, 2) => int j ; j > 0 ; j-- ) {
swap();
}
Std.rand2(0, 10) => int newseq;
if ( newseq > 8 ) {
<<< "generating a new sequence at time", now >>>;
newsequence();
}
} |
Description: |
My variation on the ctrl_sequencer.ck example program which came with 1.2.0.8 |
|
Download |
Filename: |
05 ctrl_sequencer.ck |
Filesize: |
6.83 KB |
Downloaded: |
516 Time(s) |
|
|