/*---------------------------------------------------------------------------
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;
}