[chuck-users] Longish example with 2 problems...

Mike McGonagle mjmogo at gmail.com
Thu Mar 2 16:15:17 EST 2006


/*
	This discusses two different problems. As the goal is to work with
granular synthesis, the time scale is something of concern.
	
		1. Time is NOT necessarily infinitly controllable. a time of
(sample-rate * .5) seems to be a comfortable limit for the
"synchronization" of shreds when using flags to control execution.
(having only tested this with one sample rate [default], on one
platform [10.3.9, using 1.2.0.4], I am not quite certain about this
assertion...)
		2. 'spork' appears to have some trouble when used within a function
(I get the same results when trying to use within an Object function
as well).
	
	I want to use two shreds to control two different layers of a
composition. the bottom layer (MaskComposition.perform) controls the
ranges for each synthesis parameter, while the top layer
(MaskComposition.execute) is a means of selecting a value for each of
the synthesis parameters.
	
	In building this piece/program, I discovered that, while trying to
use a flag to control a "main" (while(inPerformance) from
MaskComposition.execute) loop, there appears to be an oddity in how
ChucK handles time. I had first discovered that to get the main loop
to generate any data, it had to be delayed a small amount of time to
ensure that the control flag was set. Later, as I tried to extend the
main loop for additional iterations, I found that the main loop may or
may not execute with each iteration.
	
	With some additional experimentation, I found that the interval of
time that the main loop is delayed will effect weather or not the main
loop gets executed. I found that values below half the sample rate for
the delay may or may not allow the loop to execute. Once this delay is
set to half the sample rate, it successfully executed the main loop
without dropping any iterations.
	
	The point at which this "error" shows up is when the inner loop
(while(inPerformance)) does NOT execute because the child shred has
NOT set 'inPerformance' to true yet.
	
	what issues are there that concern "control" flags (i.e.
'inPerformance')? is there a better mechanism that would produce
reliable results with times less than half the sample rate? what is
the smallest unit of time that ChucK can reliably execute? is this a
scheduling issue of each of the child and parent shreds?
*/
fun float at() { return now / 1::ms; }
fun float dur_ms(dur d) { return d / 1::ms; }

class MaskComposition {
	1::samp / 2 => dur tolerance;
	false => int inPerformance;
	
	/* represents the bottom layer for controlling a set of parameters. */
	fun void perform(float d[][], int iteration) {
		<<< at(),"perform", d.cap(), inPerformance, iteration >>>;
		if (inPerformance) {
			<<< at(), "returning from perform", iteration >>>;
			return;
		}
		true => inPerformance;
		for(0 => int i; i < d.cap(); i++) { now + d[i][0]::ms => now; }
		<<< at(),"finished doing something:", iteration >>>;
		false => inPerformance;
	}
	
	/* used to generate a "score" for perform. a score is a time ordered
table (array of arrays) of floating point. the first element in each
of the arrays is considered to be a "delta-time", or the time until
the next item in the table should be triggered. the tables can be
explicitly defined, or generated programmatically, or anywhere
inbetween. */
	fun float[][] compose() {
		<<< at(),"compose", "" >>>;
		return [ [ 250.0, 0.0 ] ];
	}
	
	fun void execute(float tol, int times) {
		0 => int iter;
		1::samp / tol => tolerance;
		<<< at(), "tolerance:", dur_ms(tolerance) >>>;
		while(iter < times) {
			<<< at(), "trying to do something.", "" >>>;
			spork ~ perform(compose(), iter);
			now + tolerance => now;
			while(inPerformance) {
				(0.01, 3.0) => std.rand2f => float onset;
				<<< at(), iter, onset >>>;
				now + onset::ms => now;
			}
			1 +=> iter;
		}
	}
}

MaskComposition mine;

/*
	this function encapsulates the stuff just past the end of this
commented block. as far as I can tell, it does the same thing as
below, except that when it gets executed, it generates an error of

	[chuck](VM): NullPointerException: shred[id=285:spork~exp], PC=[3]

	the only sense I can make of this is that 'spork' can't produce
another shred, but is this error because this 'spork' is inside a
function?
*/
fun void ex(MaskComposition mc, float tol, int t) {
	0 => int iter;
	1::samp / tol => mc.tolerance;
	<<< at(), "tolerance:", dur_ms(mc.tolerance) >>>;
	while(iter < t) {
		<<< at(), "trying to do something.", "" >>>;
		spork ~ mc.perform(mc.compose(), iter);
		now + mc.tolerance => now;
		while(mc.inPerformance) {
			(0.01, 3.0) => std.rand2f => float onset;
			<<< at(), iter, onset >>>;
			now + onset::ms => now;
		}
		1 +=> iter;
	}
}

/*
// the following three segments are intended to operate separately.

// seg 1 - this code generates an error
ex(mine, 3, 100);
ex(mine, 2.1, 100);
ex(mine, 2, 100);
*/

/*
// seg 2 - as well as this. I tested this to see if 'ex' being sporked
would make a difference. it doesn't.
spork ~ ex(mine, 3, 100);
now + 30::second => now;
*/

/*
// seg 3 - this also produces the same error.
mine.execute(3, 100);
mine.execute(2.1, 100);
mine.execute(2, 100);
*/

//* seg 4 - the "explicit" version, and the only one that works...
0 => int iteration;
100 => int times;

1::samp / 3 => mine.tolerance;
<<< at(), "tolerance:", dur_ms(mine.tolerance) >>>;
while(iteration < times) {
	<<< at(), "try to do something.", "" >>>;
	spork ~ mine.perform(mine.compose(), iteration);
	now + mine.tolerance => now;
	while(mine.inPerformance) {
		(0.01, 3.0) => std.rand2f => float onset;
		<<< at(), iteration, onset >>>;
		now + onset::ms => now;
	}
	1 +=> iteration;
}

0 => iteration;
1::samp / 2.1 => mine.tolerance;
<<< at(), "tolerance:", dur_ms(mine.tolerance) >>>;
while(iteration < times) {
	<<< at(), "try to do something.", "" >>>;
	spork ~ mine.perform(mine.compose(), iteration);
	now + mine.tolerance => now;
	while(mine.inPerformance) {
		(0.01, 3.0) => std.rand2f => float onset;
		<<< at(), iteration, onset >>>;
		now + onset::ms => now;
	}
	1 +=> iteration;
}

0 => iteration;
1::samp / 2.0 => mine.tolerance;
<<< at(), "tolerance:", dur_ms(mine.tolerance) >>>;
while(iteration < times) {
	<<< at(), "try to do something.", "" >>>;
	spork ~ mine.perform(mine.compose(), iteration);
	now + mine.tolerance => now;
	while(mine.inPerformance) {
		(0.01, 3.0) => std.rand2f => float onset;
		<<< at(), iteration, onset >>>;
		now + onset::ms => now;
	}
	1 +=> iteration;
}
//*/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test2.ck
Type: application/octet-stream
Size: 6445 bytes
Desc: not available
Url : http://lists.cs.princeton.edu/pipermail/chuck-users/attachments/20060302/e55f3c1e/test2.obj


More information about the chuck-users mailing list