Recent Posts ¶

OSC-based audience participation

Ronald MacDonald <ronald@rmacd.com> v1.0, Thu Apr 19 19:51:32 EDT 2012

This is a very rough prototype, written in a couple of hours, which solves the idea of an audience member being able to pull up a web address on their mobile phone and ‘join in’ a performance, based on OSC and Pd.

In my particular case, I wanted the following to happen:

  1. User accesses address
  2. Browser is assigned a unique session
  3. Session ID (ID) is assigned to a team: ‘red’ or ‘blue’
  4. ID is assigned a random ‘strategy’ within a list of options
  5. User interacts with strategy via interface
  6. Interface ‘translates’ input to OSC, transmits to Pd
  7. User may be given a score/rank
Initialise the MySQL database
CREATE TABLE `scores` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(11) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE `state` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `x` tinyint(11) DEFAULT NULL,
  `y` tinyint(11) DEFAULT NULL,
  `z` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `sid` varchar(32) DEFAULT NULL,
  `lasttime` int(11) DEFAULT NULL,
  `team` varchar(4) DEFAULT NULL,
  `model` int(11) DEFAULT NULL,
  `delta` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
In index.php
<?php

// Use Andy W. Schmeder's library <andy@a2hd.com>
require ('osc.php');

session_start();

$db = mysql_connect("127.0.0.1", "255", "j8qT9qrO") or die(mysql_error());
mysql_select_db("255", $db) or die(mysql_error());

function pointmod($uid, $team, $value) {
        // Ouick routine for updating scores, we'll need to redefine DB resource.

        $dba = mysql_connect("127.0.0.1", "255", "j8qT9qrO") or die(mysql_error());
        mysql_select_db("255", $dba) or die(mysql_error());

        // Give users less points than their team as a whole.
        // Rounding with intval() will mess up scores if changes are less than division factor below.
        $uvalue = intval($value / 3);
        mysql_query(sprintf("UPDATE scores SET score=score+'%s' WHERE name='%s'", $value, $team), $dba);
        mysql_query(sprintf("UPDATE users SET delta=delta+'%s' WHERE sid='%s'", $uvalue, $uid), $dba);
}

// TODO: Purge users from DB older than 5 minutes
$time = time();

$id = session_id();

// Check if session already exists (i.e. we've seen the user before)
if ((mysql_num_rows(mysql_query(sprintf("SELECT * FROM users where sid='%s'", $id), $db))) == 0) {

        // Assign team to new user, even ID is blue, odd ID is red.
        if ((mysql_num_rows(mysql_query("SELECT * FROM users", $db))) == 0) {
                $team = "red";
        }
        elseif ((mysql_num_rows(mysql_query("SELECT * FROM users", $db))) % 2 == 0) {
                $team = "blue";
        }
        else {
                $team = "red";
        }

        // Assign 'model' which corresponds to profile in Pd project
        // OSC path is /public/$model $buttonNumber, e.g. "/public/4 2"
        // Todo: Distribute users evenly, rather than completely at random
        $model = rand(1, 7);

        // Write all we want to store about the user to DB
        mysql_query(sprintf("INSERT INTO users(sid,lasttime,team,model)
                VALUES ('%s','%s','%s','%s')", $id, $time, $team, $model), $db);

} else {
        // Grab data (if user's already been seen) from DB
        $result = mysql_query("SELECT lasttime,team,model FROM users WHERE sid='$id'", $db);
        while($row = mysql_fetch_array($result)) {
                $lasttime = $row['lasttime'];
                $team = $row['team'];
                $model = $row['model'];
        }
}

if ($_POST) {
        // Construct OSC packet for delivery to sound controller
        $c = new OSCClient();
        $c->set_destination("127.0.0.1", 3890);
        $c->send(new OSCMessage("/public/$model", array($_POST['button'])));

        // Each strategy flips beween 'on' and 'off'.
        // Let's find out the status of the selected ($POST) strategy
        // TODO: Bug in SQL statement, if NULL, cannot compare to '0'.
        if (mysql_result(mysql_query(sprintf("SELECT z FROM state WHERE x='%s'
                AND y='%s'", $_POST['model'], $_POST['button']), $db), 0) == '1') {
                mysql_query(sprintf("UPDATE state SET z='0' WHERE x='%s' AND y='%s'",
                        $_POST['model'], $_POST['button']), $db);
        } else {
                mysql_query(sprintf("UPDATE state SET z='1' WHERE x='%s' AND y='%s'",
                        $_POST['model'], $_POST['button']), $db);
        }

        $result = mysql_query("SELECT x, y, z FROM state", $db);
        while($states = mysql_fetch_array($result)) {
                $state[$states['x']][$states['y']] = $states['z'];
        }

        // Matrix comparison.
        // There's probably a better way of defining these 'rules'
        switch ($state[$_POST['model']][$_POST['button']]) {
                case $state['1']['1']:
                pointmod($id, $team, '-10');
                break;

                // And so on ...
        }
}

?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>255</title>
<style type="text/css">
body {
        background-color:#AAA;
        font-family:verdana;
}
#form .button {
        padding: 15px;
        margin: 5px;
}
</style>
</head>
<body>

<div style="padding:20px;margin:3px;width:80px;background-color:#<?php
        if ($team == "blue") {echo ("0000FF"); } else { echo ("FF0000"); } ?>">
<form id="form" name="form" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
  <input type="submit" name="button" id="1" value="1" tabindex="1" class="button" />
  <input type="submit" name="button" id="2" value="2" tabindex="2" class="button" />
  <input type="hidden" name="model" value="<?php echo $model; ?>">
</form>
</div>
<div style="padding:10px;margin:3px;width:80px;font-weight:800;color:#ddd;background-color:#660099;">
        <?php
                // Get team score
                $score = mysql_query(sprintf("SELECT score FROM scores WHERE name='%s'", $team), $db);
                $row = mysql_fetch_row($score) or die(mysql_error());
                echo $row[0];
        ?>
</div>
<div style="padding:10px;margin:3px;width:80px;font-weight:800;color:#ddd;background-color:#990066;">
        <?php
                // Get user (session) score
                $score = mysql_query(sprintf("SELECT delta FROM users WHERE sid='%s'", $id), $db);
                $row = mysql_fetch_row($score) or die(mysql_error());
                echo $row[0];
        ?>
</div>
<div style="padding:10px;margin:3px;width:80px;font-weight:800;color:#ddd;background-color:#669900;">
        <?php
                // Cough up a short session ID (last 5 characters of $id)
                echo substr($id, -5);
        ?>
</div>
</body>
</html>

As for the OSC Pd patch:

#N canvas 640 110 745 657 10;
#X declare -lib mrpeach;
#X declare -lib rradical -lib creb;
#X obj 20 17 udpreceive 3890;
#X obj 421 17 import mrpeach;
#X obj 118 17 unpackOSC;
#X obj 204 40 print;
#X obj 179 17 routeOSC /public;
#X obj 20 40 routeOSC /1 /2 /3 /4 /5 /6 /7;
#X obj 119 169 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1;
#X obj 152 165 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1;
#X obj 119 146 php-sub;
#X obj 43 165 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 43 142 php-sub;
#X obj 288 17 import rradical creb;
#X msg 119 213 linear 32 100 105;
#X msg 119 190 linear 8 1 5;
#X obj 164 421 ezdac~;
#X obj 119 379 fdn~ 64 40000;
#X obj 43 207 noise~;
#X obj 43 186 tgl 15 0 empty empty empty 0 -6 0 8 -24198 -1 -1 1 1
;
#X obj 42 274 +~;
#X obj 43 230 lop~ 1000;
#X obj 65 165 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 328 182 readsf~;
#X obj 353 142 bng 15 250 50 0 empty empty empty 0 -6 0 8 -24198 -1
-1;
#X obj 402 186 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X msg 328 159 0;
#X obj 328 138 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
-1;
#X floatatom 77 274 5 0 0 0 - - -;
#X obj 70 251 random 800;
#X obj 194 297 osc~;
#X floatatom 147 274 5 0 0 0 - - -;
#X obj 220 318 *~;
#X obj 194 349 +~;
#X obj 68 71 php-sub;
#X obj 68 94 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 147 251 random 800;
#X msg 245 153 1;
#X obj 245 243 line~;
#X obj 245 199 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1;
#X obj 245 176 delay 20;
#X msg 245 220 0 3000;
#X msg 361 159 open ./255/dog.wav \, 1;
#X obj 142 67 php-sub;
#X obj 142 90 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 199 71 php-sub;
#X obj 328 115 readsf~;
#X obj 351 71 bng 15 250 50 0 empty empty empty 0 -6 0 8 -24198 -1
-1;
#X obj 400 115 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X msg 328 92 0;
#X obj 328 71 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
-1;
#X msg 359 93 open ./255/wackybird.wav \, 1;
#X obj 175 93 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 230 93 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 332 331 readsf~;
#X obj 357 284 bng 15 250 50 0 empty empty empty 0 -6 0 8 -24198 -1
-1;
#X obj 406 328 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X msg 332 308 0;
#X obj 332 287 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
-1;
#X obj 332 264 readsf~;
#X obj 355 220 bng 15 250 50 0 empty empty empty 0 -6 0 8 -24198 -1
-1;
#X obj 404 256 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X msg 332 241 0;
#X obj 332 220 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
-1;
#X obj 248 40 php-sub;
#X obj 248 63 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 278 67 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X msg 365 305 open ./255/train.wav \, 1;
#X msg 363 230 open ./255/glass.wav \, 1;
#X obj 98 93 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 249 397 lop~;
#X floatatom 302 397 5 0 0 0 - - -;
#X msg 337 368 100;
#X msg 368 368 18000;
#X obj 20 63 php-sub;
#X obj 20 86 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 47 93 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#N canvas 376 391 450 300 test-sigs 0;
#X obj 100 454 line~;
#X obj 100 379 f;
#X obj 100 534 outlet~;
#X msg 100 433 0 \, \$1 \$2;
#X obj 100 407 pack 0 0;
#X obj 200 354 /;
#X obj 259 335 * 0.001;
#X obj 100 507 hip~ 5;
#X obj 45 256 loadbang;
#X msg 100 332 1;
#X obj 100 354 metro 1000;
#X obj 201 312 t b b f;
#X obj 127 280 t b f;
#X obj 100 479 tabread4~ \$0-sample;
#X text 31 38 test signal: looped sample playback;
#X obj 61 169 hip~ 5;
#X obj 61 145 adc~ 1;
#X obj 123 169 s insamprate;
#X obj 50 109 inlet;
#X obj 123 145 samplerate~;
#X obj 126 256 r \$0-samplength;
#X obj 201 286 r \$0-insamprate;
#X obj 50 192 tabwrite~ \$0-sample;
#X obj 408 447 line~;
#X obj 408 372 f;
#X obj 408 527 outlet~;
#X msg 408 426 0 \, \$1 \$2;
#X obj 408 400 pack 0 0;
#X obj 508 347 /;
#X obj 567 328 * 0.001;
#X obj 408 500 hip~ 5;
#X obj 353 249 loadbang;
#X msg 408 325 1;
#X obj 408 347 metro 1000;
#X obj 509 305 t b b f;
#X obj 435 273 t b f;
#X obj 370 162 hip~ 5;
#X obj 370 138 adc~ 1;
#X obj 358 101 inlet;
#X obj 432 138 samplerate~;
#X obj 432 162 s insamprate2;
#X obj 358 185 tabwrite~ \$0-sample2;
#X obj 434 249 r \$0-samplength2;
#X obj 509 279 r \$0-insamprate2;
#X obj 408 472 tabread4~ \$0-sample2;
#X connect 0 0 13 0;
#X connect 1 0 4 0;
#X connect 3 0 0 0;
#X connect 4 0 3 0;
#X connect 5 0 4 1;
#X connect 5 0 10 1;
#X connect 6 0 5 1;
#X connect 7 0 2 0;
#X connect 8 0 9 0;
#X connect 9 0 10 0;
#X connect 10 0 1 0;
#X connect 11 0 9 0;
#X connect 11 1 5 0;
#X connect 11 2 6 0;
#X connect 12 0 9 0;
#X connect 12 1 5 0;
#X connect 12 1 1 1;
#X connect 13 0 7 0;
#X connect 15 0 22 0;
#X connect 16 0 15 0;
#X connect 18 0 19 0;
#X connect 18 0 22 0;
#X connect 19 0 17 0;
#X connect 20 0 12 0;
#X connect 21 0 11 0;
#X connect 23 0 44 0;
#X connect 24 0 27 0;
#X connect 26 0 23 0;
#X connect 27 0 26 0;
#X connect 28 0 27 1;
#X connect 28 0 33 1;
#X connect 29 0 28 1;
#X connect 30 0 25 0;
#X connect 31 0 32 0;
#X connect 32 0 33 0;
#X connect 33 0 24 0;
#X connect 34 0 32 0;
#X connect 34 1 28 0;
#X connect 34 2 29 0;
#X connect 35 0 32 0;
#X connect 35 1 28 0;
#X connect 35 1 24 1;
#X connect 36 0 41 0;
#X connect 37 0 36 0;
#X connect 38 0 39 0;
#X connect 38 0 41 0;
#X connect 39 0 40 0;
#X connect 42 0 35 0;
#X connect 43 0 34 0;
#X connect 44 0 30 0;
#X restore 372 410 pd test-sigs;
#N canvas 0 22 570 372 insample1 0;
#N canvas 0 22 450 300 (subpatch) 0;
#X array \$0-sample 151471 float 0;
#X coords 0 1 151470 -1 400 150 1;
#X restore 269 34 graph;
#X obj 29 84 unpack s f;
#X obj 29 194 soundfiler;
#X text 366 260 read a sample;
#X obj 286 259 loadbang;
#X obj 29 110 t s b;
#X obj 85 109 symbol \$0-sample;
#X obj 29 145 pack s s;
#X msg 29 170 read -resize \$1 \$2;
#X obj 84 56 44100;
#X obj 29 57 t a b;
#X obj 39 218 s \$0-samplength;
#X obj 126 84 s \$0-insamprate;
#X obj 29 257 /;
#X obj 29 281 * 1000;
#X obj 29 304 s \$0-samp-msec;
#X obj 67 257 r \$0-insamprate;
#X obj 29 33 r read-sound1;
#X msg 286 283 \; read-sound1 ~/255/noise.aif;
#X connect 1 0 5 0;
#X connect 1 1 12 0;
#X connect 2 0 11 0;
#X connect 2 0 13 0;
#X connect 4 0 18 0;
#X connect 5 0 7 0;
#X connect 5 1 6 0;
#X connect 6 0 7 1;
#X connect 7 0 8 0;
#X connect 8 0 2 0;
#X connect 9 0 12 0;
#X connect 10 0 1 0;
#X connect 10 1 9 0;
#X connect 13 0 14 0;
#X connect 14 0 15 0;
#X connect 16 0 13 1;
#X connect 17 0 10 0;
#X restore 554 230 pd insample1;
#N canvas 0 22 546 371 insample2 0;
#N canvas 0 22 450 300 (subpatch) 0;
#X array \$0-sample2 151471 float 0;
#X coords 0 1 151470 -1 400 150 1;
#X restore 308 34 graph;
#X obj 29 84 unpack s f;
#X obj 29 194 soundfiler;
#X text 366 260 read a sample;
#X obj 286 259 loadbang;
#X obj 29 110 t s b;
#X obj 29 145 pack s s;
#X msg 29 170 read -resize \$1 \$2;
#X obj 84 56 44100;
#X obj 29 57 t a b;
#X obj 29 257 /;
#X obj 29 281 * 1000;
#X obj 29 33 r read-sound2;
#X obj 126 84 s \$0-insamprate2;
#X obj 85 109 symbol \$0-sample2;
#X obj 39 218 s \$0-samplength2;
#X obj 67 257 r \$0-insamprate2;
#X obj 29 304 s \$0-samp2-msec;
#X msg 286 283 \; read-sound2 ./255/train.wav;
#X connect 1 0 5 0;
#X connect 1 1 13 0;
#X connect 2 0 10 0;
#X connect 2 0 15 0;
#X connect 4 0 18 0;
#X connect 5 0 6 0;
#X connect 5 1 14 0;
#X connect 6 0 7 0;
#X connect 7 0 2 0;
#X connect 8 0 13 0;
#X connect 9 0 1 0;
#X connect 9 1 8 0;
#X connect 10 0 11 0;
#X connect 11 0 17 0;
#X connect 12 0 9 0;
#X connect 14 0 6 1;
#X connect 16 0 10 1;
#X restore 554 253 pd insample2;
#N canvas 0 22 803 693 fftanalysis 0;
#X obj 104 521 *~;
#X obj 65 521 *~;
#X obj 423 366 *~;
#X obj 382 366 *~;
#X obj 382 389 +~;
#X obj 64 193 *~;
#X obj 64 168 inlet~;
#X obj 64 216 rfft~;
#X obj 64 570 *~;
#X obj 151 255 *~;
#X obj 382 343 rfft~;
#X obj 64 545 rifft~;
#X obj 64 593 outlet~;
#X obj 117 255 *~;
#X obj 117 278 +~;
#X text 468 418 modulus;
#X obj 117 430 *~;
#X obj 610 23 block~ 1024 4;
#X obj 117 408 clip~;
#X obj 97 194 tabreceive~ \$0-hann;
#X obj 609 63 loadbang;
#X obj 158 356 r squelch;
#X obj 157 379 expr 0.01*$f1*$f1;
#X obj 117 304 +~ 1e-20;
#X obj 118 490 *~ 0.00065;
#X obj 97 570 tabreceive~ \$0-hann;
#X obj 383 317 *~;
#X obj 383 292 inlet~;
#X obj 416 318 tabreceive~ \$0-hann;
#X obj 117 331 q8_rsqrt~;
#X obj 382 412 q8_sqrt~;
#X text 468 435 of control;
#X text 466 452 amplitude;
#X text 206 258 reciprocal;
#X text 209 277 modulus of;
#X text 205 297 filter input;
#X text 206 316 amplitude;
#X msg 609 86 \; pd dsp 1 \; window-size 1024 \; squelch 30 \; squelch-set
set 30;
#X text 125 169 filter input;
#X text 448 292 control source;
#X text 444 342 Fourier transform;
#X text 38 27 Internal workings of the timbre stamping algorithm. First
the "filter input" is treated as in the compressor patch \, multiplying
each channel amplitude by one over its modulus (but limited by the
"squelch" parameter.) It is then multiplied by the modulus of the channel
amplitude for the control source (which is Fourier analyzed in parallel
with the filter input.);
#X text 155 432 multiply the two amplitude;
#X text 153 449 factors (for compression;
#X text 155 465 and to apply new timbre);
#X connect 0 0 11 1;
#X connect 1 0 11 0;
#X connect 2 0 4 1;
#X connect 3 0 4 0;
#X connect 4 0 30 0;
#X connect 5 0 7 0;
#X connect 6 0 5 0;
#X connect 7 0 13 0;
#X connect 7 0 13 1;
#X connect 7 0 1 0;
#X connect 7 1 9 0;
#X connect 7 1 9 1;
#X connect 7 1 0 0;
#X connect 8 0 12 0;
#X connect 9 0 14 1;
#X connect 10 0 3 0;
#X connect 10 0 3 1;
#X connect 10 1 2 0;
#X connect 10 1 2 1;
#X connect 11 0 8 0;
#X connect 13 0 14 0;
#X connect 14 0 23 0;
#X connect 16 0 24 0;
#X connect 18 0 16 0;
#X connect 19 0 5 1;
#X connect 20 0 37 0;
#X connect 21 0 22 0;
#X connect 22 0 18 2;
#X connect 23 0 29 0;
#X connect 24 0 0 1;
#X connect 24 0 1 1;
#X connect 25 0 8 1;
#X connect 26 0 10 0;
#X connect 27 0 26 0;
#X connect 28 0 26 1;
#X connect 29 0 18 0;
#X connect 30 0 16 1;
#X restore 372 433 pd fftanalysis;
#N canvas 0 22 450 300 hann-window 0;
#N canvas 0 22 450 300 (subpatch) 0;
#X array \$0-hann 1024 float 0;
#X coords 0 1 1023 0 300 100 1;
#X restore 92 321 graph;
#X obj 388 175 osc~;
#X obj 388 200 *~ -0.5;
#X obj 388 224 +~ 0.5;
#X obj 341 257 tabwrite~ \$0-hann;
#X obj 47 98 r window-size;
#X obj 48 183 /;
#X obj 137 152 samplerate~;
#X obj 48 261 s window-sec;
#X obj 187 214 swap;
#X obj 187 238 /;
#X obj 187 262 s window-hz;
#X obj 59 211 * 1000;
#X obj 59 238 s window-msec;
#X obj 48 125 t f b f;
#X msg 183 102 resize \$1;
#X obj 183 126 s \$0-hann;
#X obj 340 115 r window-hz;
#X msg 392 140 0;
#X obj 340 141 t f b;
#X text 25 18 calculate Hann window table (variable window size) and
constants window-hz (fundamental frequency of analysis) \, window-sec
and window-msec (analysis window size in seconds and msec).;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 4 0;
#X connect 5 0 14 0;
#X connect 6 0 8 0;
#X connect 6 0 12 0;
#X connect 7 0 6 1;
#X connect 7 0 9 1;
#X connect 9 0 10 0;
#X connect 9 1 10 1;
#X connect 10 0 11 0;
#X connect 12 0 13 0;
#X connect 14 0 6 0;
#X connect 14 0 9 0;
#X connect 14 1 7 0;
#X connect 14 2 15 0;
#X connect 15 0 16 0;
#X connect 17 0 19 0;
#X connect 18 0 1 1;
#X connect 19 0 1 0;
#X connect 19 1 4 0;
#X connect 19 1 18 0;
#X restore 554 276 pd hann-window;
#X floatatom 85 434 0 0 500 0 - squelch-set -;
#X obj 85 457 s squelch;
#X obj 554 90 s read-sound1;
#X obj 554 195 s read-sound2;
#X obj 199 94 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X msg 554 21 ~/255/balloon.wav;
#X msg 554 44 ~/255/whoosh.wav;
#X msg 554 126 ~/255/balloon.wav;
#X msg 554 149 ~/255/whoosh.wav;
#X msg 554 172 ~/255/noise.aif;
#X msg 554 67 ~/255/noise.aif;
#X msg 3 210 0.15;
#X obj 23 251 *~;
#X obj 9 344 select 0;
#X obj 16 385 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X msg 21 410 0;
#X obj 308 40 php-sub;
#X obj 363 44 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X obj 388 44 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X connect 0 0 2 0;
#X connect 2 0 4 0;
#X connect 4 0 3 0;
#X connect 4 0 5 0;
#X connect 5 0 72 0;
#X connect 5 1 10 0;
#X connect 5 2 32 0;
#X connect 5 3 96 0;
#X connect 5 4 3 0;
#X connect 5 4 8 0;
#X connect 5 5 41 0;
#X connect 5 6 43 0;
#X connect 5 7 62 0;
#X connect 6 0 13 0;
#X connect 7 0 12 0;
#X connect 8 0 6 0;
#X connect 8 1 7 0;
#X connect 9 0 17 0;
#X connect 10 0 9 0;
#X connect 10 1 20 0;
#X connect 12 0 15 0;
#X connect 13 0 15 0;
#X connect 15 0 14 0;
#X connect 15 1 68 0;
#X connect 16 0 19 0;
#X connect 17 0 91 0;
#X connect 17 0 93 0;
#X connect 18 0 15 0;
#X connect 19 0 92 0;
#X connect 20 0 27 0;
#X connect 20 0 35 0;
#X connect 20 0 38 0;
#X connect 21 0 15 0;
#X connect 21 0 68 0;
#X connect 21 1 23 0;
#X connect 22 0 40 0;
#X connect 23 0 40 0;
#X connect 24 0 21 0;
#X connect 25 0 24 0;
#X connect 26 0 28 0;
#X connect 27 0 26 0;
#X connect 28 0 30 0;
#X connect 29 0 31 0;
#X connect 30 0 31 1;
#X connect 31 0 14 0;
#X connect 31 0 15 0;
#X connect 32 0 33 0;
#X connect 32 1 67 0;
#X connect 33 0 34 0;
#X connect 33 0 35 0;
#X connect 33 0 38 0;
#X connect 34 0 29 0;
#X connect 35 0 36 0;
#X connect 36 0 30 1;
#X connect 37 0 39 0;
#X connect 38 0 37 0;
#X connect 39 0 36 0;
#X connect 40 0 21 0;
#X connect 41 0 42 0;
#X connect 41 1 50 0;
#X connect 42 0 27 0;
#X connect 42 0 35 0;
#X connect 42 0 89 0;
#X connect 43 0 84 0;
#X connect 43 1 51 0;
#X connect 44 0 15 0;
#X connect 44 0 68 0;
#X connect 44 1 46 0;
#X connect 45 0 49 0;
#X connect 46 0 49 0;
#X connect 47 0 44 0;
#X connect 48 0 47 0;
#X connect 49 0 44 0;
#X connect 50 0 25 0;
#X connect 50 0 45 0;
#X connect 51 0 22 0;
#X connect 51 0 48 0;
#X connect 52 0 15 0;
#X connect 52 0 14 0;
#X connect 52 1 54 0;
#X connect 53 0 65 0;
#X connect 54 0 65 0;
#X connect 55 0 52 0;
#X connect 56 0 55 0;
#X connect 57 0 14 0;
#X connect 57 0 15 0;
#X connect 57 1 59 0;
#X connect 58 0 66 0;
#X connect 59 0 66 0;
#X connect 60 0 57 0;
#X connect 61 0 60 0;
#X connect 62 0 63 0;
#X connect 62 1 64 0;
#X connect 63 0 61 0;
#X connect 63 0 53 0;
#X connect 63 0 90 0;
#X connect 64 0 87 0;
#X connect 64 0 90 0;
#X connect 65 0 52 0;
#X connect 66 0 57 0;
#X connect 67 0 58 0;
#X connect 67 0 56 0;
#X connect 68 0 14 1;
#X connect 69 0 68 1;
#X connect 70 0 69 0;
#X connect 71 0 69 0;
#X connect 72 0 73 0;
#X connect 72 1 74 0;
#X connect 73 0 70 0;
#X connect 73 0 20 0;
#X connect 73 0 86 0;
#X connect 74 0 25 0;
#X connect 74 0 48 0;
#X connect 74 0 61 0;
#X connect 74 0 56 0;
#X connect 75 0 78 0;
#X connect 75 1 78 1;
#X connect 78 0 14 1;
#X connect 78 0 14 0;
#X connect 80 0 81 0;
#X connect 84 0 71 0;
#X connect 84 0 85 0;
#X connect 85 0 82 0;
#X connect 86 0 82 0;
#X connect 87 0 83 0;
#X connect 88 0 83 0;
#X connect 89 0 83 0;
#X connect 90 0 82 0;
#X connect 91 0 92 1;
#X connect 92 0 18 0;
#X connect 93 0 94 0;
#X connect 94 0 95 0;
#X connect 95 0 92 1;
#X connect 96 0 97 0;
#X connect 96 1 98 0;
#X connect 97 0 88 0;
#X connect 97 0 90 0;
#X connect 97 0 94 0;
#X connect 98 0 56 0;
#X connect 98 0 25 0;
#X connect 98 0 45 0;
#X connect 98 0 27 0;