/*---------------------------------------------------------------------------- S.M.E.L.T. : Small Musically Expressive Laptop Toolkit Copyright (c) 2007 Rebecca Fiebrink and Ge Wang. All rights reserved. http://smelt.cs.princeton.edu/ http://soundlab.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // name: motion-sing.ck // desc: this program attempts to use the Sudden Motion Sensor (SMS) to sing // // authors: Rebecca Fiebrink and Ge Wang // // requires: SMS-enabled powerbook or macbook running OS X (10.4.8 or higher) // // to run (in command line chuck): // %> chuck motion-sing.ck // // to run (in miniAudicle): // (make sure VM is started, add the thing) //----------------------------------------------------------------------------- // sub patch SndBuf buffy => TwoZero t => TwoZero t2 => OnePole p; // formant filters p => TwoPole f1 => Gain g; p => TwoPole f2 => g; p => TwoPole f3 => g; // the rest g => JCRev r => dac; // set first two zero filter 1.0 => t.b0; 0.0 => t.b1; -1.0 => t.b2; // set second two zero filter 1.0 => t2.b0; 0.0 => t2.b1; 1.0 => t2.b2; // set effects parameters 0.05 => r.mix; // see formant filter parameters 0.997 => f1.radius; 0.997 => f2.radius; 0.997 => f3.radius; .4 => float factor; factor * 1.0 => f1.gain; factor * 0.8 => f2.gain; factor * 0.6 => f3.gain; // set one pole parameters 0.99 => p.pole; .5 => p.gain; // the four-mants [ [ 703.0, 1475.0, 2984.0 ], // ah [ 530.0, 1864.0, 2637.0 ], // e [ 400.0, 800.0, 3250.0 ], // oo [ 431.0, 2434.0, 2913.0 ] // i ] @=> float formants3[][]; // current coordinate 0 => float curr_x; 0 => float curr_y; // more globals 400.0 => float f1freq; 1000.0 => float f2freq; 2800.0 => float f3freq; 400.0 => float target_f1freq; 1000.0 => float target_f2freq; 2800.0 => float target_f3freq; // read "special:glot_pop" => buffy.read; // helper function fun float distance( float x1, float y1, float x2, float y2 ) { return Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); } // the almighty bew! (TODO: comment this more) fun void bew() { // guess what distance( curr_x, curr_y, -1, 1 ) => float A; distance( curr_x, curr_y, 1, 1 ) => float B; distance( curr_x, curr_y, -1, -1 ) => float C; distance( curr_x, curr_y, 1, -1 ) => float D; // weights 1 / (A + .001) => float wA; 1 / (B + .001) => float wB; 1 / (C + .001) => float wC; 1 / (D + .001) => float wD; // normalize 1 / (wA + wB + wC + wD) => float norm; // formant table formants3 @=> float forms[][]; // target formant freqs ( wA * forms[0][0] + wB * forms[1][0] + wC * forms[2][0] + wD * forms[3][0] ) * norm => target_f1freq; ( wA * forms[0][1] + wB * forms[1][1] + wC * forms[2][1] + wD * forms[3][1] ) * norm => target_f2freq; ( wA * forms[0][2] + wB * forms[1][2] + wC * forms[2][2] + wD * forms[3][2] ) * norm => target_f3freq; } // instantiate a HidIn object HidIn hi; HidMsg msg; // open tilt sensor if( !hi.openTiltSensor() ) { <<< "tilt sensor unavailable", "" >>>; me.exit(); } // "hey" <<< "tilt and sing", "" >>>; // spork spork ~ do_impulse(); spork ~ ramp_stuff(); // infinite event loop while( true ) { // poll the tilt sensor, expect to get back 3 element array of ints hi.read( 9, 0, msg ); // mapping first two axes to 2D vowel space msg.x / 100.0 => curr_x; msg.y / 100.0 => curr_y; if( curr_x > 1.0 ) 1.0 => curr_x; else if( curr_x < -1.0 ) -1.0 => curr_x; if( curr_y > 1.0 ) 1.0 => curr_y; else if( curr_y < -1.0 ) 1.0 => curr_y; // important bew bew(); // advance time 20::ms => now; } // source generation fun void do_impulse() { // infinite time loop while( true ) { // fire! 0 => buffy.pos; // wait 100::ms => now; } } // interpolation fun void ramp_stuff() { // mysterious 'slew' 0.025 => float slew; // infinite time loop while( true ) { (target_f1freq - f1freq) * slew + f1freq => f1freq => f1.freq; (target_f2freq - f2freq) * slew + f2freq => f2freq => f2.freq; (target_f3freq - f3freq) * slew + f3freq => f3freq => f3.freq; 0.0025::second => now; } }