# [chuck-users] 2 works 1.5 kills chuck

Jordan Orelli jordanorelli at gmail.com
Tue Jul 26 10:58:45 EDT 2011

```Well, there are a number of ways that this code can be improved.  Here's a way of patching the code to make it work, followed by an explanation:

fun void cycle()
{
float targetFreq;
dur targetBeat;
dur targetDelay;
imp => p => dac;
while(true)
{
freq * multiplier => targetFreq;
1.0::second / targetFreq => targetBeat;
targetBeat - (now % targetBeat) => targetDelay;
if(targetDelay < 1::samp)
1::samp => targetDelay;
targetDelay => now;
pan * spread => p.pan;
1.0 => imp.next;
}
}

The problem is that, with certain numbers, the cycle can occur on the exact sample that the click is meant to happen.  The following line is the culprit:

>             targetBeat - (now % targetBeat) => now;

What this does is it looks at a duration called targetBeat and, if we're not on the beat, waits until we are.  Time in ChucK is calculated from when the VM was started.  So if the targetBeat is 10ms, and the VM has been running for 234 ms, we will wait for 6 ms, which would put us on the beat at 240ms.  The arithmetic of time isn't exactly intuitive the first time you encounter it, so let's break that down a little further to see how the math works out and gets us what we're looking for.  Let's take the previous example and say we have a target beat length of 10ms.  Substituting 10ms for targetBeat it would look like this:

10::ms - (now % 10::ms) => now;

The expression "now % 10::ms", or now % any duration for that matter, says "take the current time (now), divide by the following duration, and return the remainder".  This is commonly called the modulo operator.  For example, 6 % 3 would yield 0, because 6 divides by 3 evenly, but 7 % 3 would yield 1, since in integer mathematics divided by 3 would yield 2 with a remainder of 1.  So in this context, the keyword now simply indicates the current time.  I personally always think of it as "an integer representing the number of samples that have passed since I started ChucK".  Let's pretend that we're currently at a time 234::ms after the VM was launched:

10::ms - (234::ms % 10::ms) => now;

Let's simplify the left side.  First we'll reduce the modulo operation in parenthesis.  Since 234 % 10 = 4, we have:

10:: ms - 4::ms => now;

which becomes

6::ms => now;

Chucking any duration to the keyword "now" will cause the shred to wait for that amount of time.  However, there is no protection against chucking zero time to now; which would say "delay by nothing at all".  Effectively when you write 0::ms => now, nothing happens.  The cycle() function that contains this bit of code has it in a logically infinite loop, since it's contained in a while(true) block.  So when this duration is 0, we're looping infinitely without advancing time; we've stopped time.

To prevent this from happening store the amount of time you are to delay in a variable (called targetDelay in my example).  Then, check to make sure that variable represents a duration longer than 1 sample (i.e. a positive amount of time, since a sample is the lower limit on time resolution).  If you try to send a negative number to now you get a rather amusing error indicating that you've attempted to make the VM travel backwards in time.  If your duration is either zero or negative, set it to a minimum of 1 sample.

There's a more mathematical way of determining which values would be "good" or "bad", but I can't honestly figure out why this only happens at certain values.  I verified that 1.5 does indeed break the original code for me, as well, but with the update it works fine.

-Jordan

If we're in this body of code while we are already on the beat.

On Jul 21, 2011, at 3:54 PM, Rustom Mody wrote:

> On Thu, Jul 21, 2011 at 12:36 PM, <tempjayren at gmail.com> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> what did i break now?
> i snipped the code from the message, though when i ran it it said
> something about an undefined variable.
> i wanted to see what was going on.
>
>
> Thanks for looking. The full code is below.
> It works as given ie it starts as a 2 vs 3 polyrhythm.
> You can speed it up by pressing D until the polyrhythm becomes 2 notes
> However if I want to speed up by less than factor of 2 then it breaks.
>
> About 11 lines from the end: the line
> 2 *=> Voice.multiplier;
> if changed to
> 1.5 *=> Voice.multiplier;
>
> Then it dies after a D and cpu shows 100%
> This is debian linux.
>
> There are one or two other enhancements also I would like
> Can I make the clicks sound a little different from each other?
>
> Note the full context is on the other thread: Subject: From 4Hz to 400 Hz
> ---------------------------
> class Voice
> {
>     1.0 => static float multiplier;
>     1.0 => static float spread;
>     float freq;
>     float pan;
>     Impulse imp;
>     Pan2 p;
>
>     fun static Voice Voice(float freq, float pan)
>     {
>         Voice v;
>         freq => v.freq;
>         pan => v.pan;
>         spork ~ v.cycle();
>         return v;
>     }
>
>     fun void cycle()
>     {
>         float targetFreq;
>         dur targetBeat;
>         imp => p => dac;
>         while(true)
>         {
>             freq * multiplier => targetFreq;
>             1::second / targetFreq => targetBeat;
>             targetBeat - (now % targetBeat) => now;
>             pan * spread => p.pan;
>             1.0 => imp.next;
>         }
>     }
> }
>
> fun void keyboardListener()
> {
>     KBHit hi;
>     int c;
>     int tt;
>     while(true)
>     {
>         hi => now;
>         while(hi.more())
>         {
>         hi.getchar() => c;
>             {
>                 if(c == 68) // D
>                     2 *=> Voice.multiplier;
>                 else if(c == 72) // H
>                     2 /=> Voice.multiplier;
>             }
>         }
>     }
> }
>
> Voice.Voice(3.0, -1);
> Voice.Voice(2.0, 1);
> spork ~ keyboardListener();
> while(true) { 100::ms => now; }
>
> _______________________________________________
> chuck-users mailing list
> chuck-users at lists.cs.princeton.edu
> https://lists.cs.princeton.edu/mailman/listinfo/chuck-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cs.princeton.edu/pipermail/chuck-users/attachments/20110726/223cb03a/attachment-0001.html>
```