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