/*--------------------------------------------------------------------------- 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: follower.ck // desc: simple (but effective) envelope follower // // Perry's comments: /* Hi all. I keep meaning to post to this list about the under-exploited feature that all unit generators have, in that you can cause their inputs to multiply rather than add. As an example, here's a simple power envelope follower that doesn't require sample-level chuck intervention. A gain UG is used to square the incoming A/D signal (try it on your built-in mic), then a OnePole UG is used as a "leaky integrator" to keep a running estimate of the signal power. The main loop wakes up each 100 ms and checks the power, and prints out a message if it's over a certain level. You might need to change the threshold, but you get the idea. */ // // author: Perry Cook // commented by: Rebecca Fiebrink and Ge Wang // // to run (in command line chuck): // %> chuck follower.ck // // to run (in miniAudicle): // (make sure VM is started, add the thing) //----------------------------------------------------------------------------- // patch adc => Gain g => OnePole p => blackhole; // square the input, by chucking adc to g a second time adc => g; // set g to multiply its inputs 3 => g.op; // threshold .05 => float threshold; // set pole position, influences how closely the envelope follows the input // : pole = 0 -> output == input; // : as pole position approaches 1, follower will respond more slowly to input 0.999 => p.pole; // duration between successive polling 20::ms => dur pollDur; // duration to pause when onset detected 300::ms => dur pauseDur; // time before which to not check for threshold time notBefore; // infinite time loop while( true ) { // print <<< "current envelope value:", p.last() >>>; // detect onset if( now > notBefore && p.last() > threshold ) { // do something <<< "BANG!!" >>>; // compute time to resume checking now + pauseDur => notBefore; } // determines poll rate pollDur => now; }