Tutorial 3: Listening to ChucK

Home ~ Tutorial 1: Getting Started ~ Tutorial 2: Communicating with Chuck ~ Tutorial 3: Listening to Chuck

In this tutorial we will learn how to listen to Chuck Events and other variables.

1. Listening to ChucK Events

An Event is a class that encapsulates a very useful mode of communication within ChucK. Effectively, an Event represents just that: an event - something did or will happen. A global Event let’s the WebChucK backend know that an Event instance needs to be added to an Event registry so that we can keep an eye on it in javascript.

In the ChucK code below (interaction-4.ck), a simple note is played every 300 milliseconds. Simultaneously, we fire off an event via an Event class’s broadcast() method on an Event instance called "step".

global Event step; SinOsc osc => ADSR env => dac; 0.5 => dac.gain; 220 => osc.freq; env.set(3::ms, 250::ms, 0.0, 0::ms); while (true) { env.keyOn(); step.broadcast(); 300::ms => now; }

Now, let’s do something with this in Event ("step") in javascript. For example, let’s change the background color of a simple webpage every time a note is played (or event broadcasted).

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <link rel="stylesheet" href="../css/editor.css">
</head>
<body>
<script type="text/javascript" src="./js/webchuck_host.js"></script>

<h1>Interfacing With WebChucK</h1>
<h2>Listening to a ChucK Event</h2>

<input id="startButton" type="button" value="Start ChucK" />

<script>
    var serverFilesToPreload = [
            {
                serverFilename: './interaction-4.ck',
                virtualFilename: 'interaction-4.ck'
            }
        ];
    var startButton = document.getElementById( "startButton" );
    startButton.addEventListener( "click", async function() {
        await preloadFilenames( serverFilesToPreload );
        await startChuck();
        await theChuckReady;
        await theChuck.runFile( "interaction-4.ck" );
        theChuck.startListeningForEvent("step", stepCallback);

        startButton.disabled = true;
    });

    function randomizeBackgroundColor() {
        var r = Math.random() * 256, g = Math.random() * 256, b = Math.random() * 256;
        var color = "rgb(" + r.toString() + "," + g.toString() + "," + b.toString()+")";
        document.body.style.backgroundColor  = color;
    }

    function stepCallback() {
        randomizeBackgroundColor();
    }
    
</script>
</body>
</html>

Check the working site out here.

1. Listening to (/retrieving) ChucK variables

What if we want to know the value of a ChucK variable for use in our webpage?

The ChucK code below updates global float named scale to control an oscillator, modulating its frequency between 200 and 800 Hz. The value of scale itself is normalized to be between 0.0 and 1.0.

global float scale; SinOsc car => dac; SinOsc mod => blackhole; Math.PI / 4.0 => mod.phase; 0.25 => mod.freq; 0.5 => dac.gain; while (true) { (mod.last() + 1.0) * 0.5 => scale; scale * 800 + 200 => car.freq; 1::samp => now; }

In our webpage, we can tell our ChucK instance (theChuck) that we want to know the value of the global float named scale by passing “scale” in to a function called getFloat(). getFloat("variable") returns a [Promise][https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise], which effectively serves as a placeholder for a value that hasn’t been retrieved yet. The cool thing is that you can associate a handler (a function) with a Promise, which will be called when the Promise task is completed (in our case, retrieving a value from the WebChucK thread).

Below is a demonstration of how you can chain a getFloat("variable") call to a function using .then(). See updateBackgroundColor(), which is called at an interval of 50ms.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <link rel="stylesheet" href="../css/editor.css">
</head>
<body>
<script type="text/javascript" src="./js/webchuck_host.js"></script>

<h1>Interfacing With WebChucK</h1>
<h2>Listening to a ChucK Variable</h2>

<input id="startButton" type="button" value="Start ChucK" />

<script>
    var serverFilesToPreload = [
            {
                serverFilename: './interaction-5.ck',
                virtualFilename: 'interaction-5.ck'
            }
        ];
    var startButton = document.getElementById( "startButton" );
    startButton.addEventListener( "click", async function() {
        await preloadFilenames( serverFilesToPreload );
        await startChuck();
        await theChuckReady;
        await theChuck.runFile( "interaction-5.ck" );
        setInterval(updateBackgroundColor, 50);
        startButton.disabled = true;
    });


    function updateBackgroundColor() {
        theChuck.getFloat("scale").then( function(val) {
            var r = val * 256, g = 100, b = 100;
            var color = "rgb(" + r.toString() + "," + g.toString() + "," + b.toString()+")";
            document.body.style.backgroundColor  = color;
        });
    }

</script>
</body>
</html>

This is a non-intuitive syntax, but ends up being quite easy to work with in context.

Check the working site out here.

Home ~ Tutorial 1: Getting Started ~ Tutorial 2: Communicating with Chuck ~ Tutorial 3: Listening to Chuck