/*---------------------------------------------------------------------------- ChucK Simple Decaying Exponential Envelope Unit Generator Simple single time constant exponential decay, applied to any signal passed through it. Obeys: value, T60, radius, and keyOn Especially useful for Modal synthesis. One of these for each mode: SinOsc s => ExpEnv e => dac; Also useful for noise excitation pulse, using it like: Noise n => ExpEnv e => dac; Copyright (c) 2015 Perry R. Cook. All rights reserved. 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. -----------------------------------------------------------------------------*/ #include "chuck_dl.h" #include "chuck_def.h" #include #include #include CK_DLL_CTOR(expenv_ctor); CK_DLL_DTOR(expenv_dtor); CK_DLL_TICK(expenv_tick); CK_DLL_MFUN(expenv_setValue); CK_DLL_MFUN(expenv_getValue); CK_DLL_MFUN(expenv_setRadius); CK_DLL_MFUN(expenv_getRadius); CK_DLL_MFUN(expenv_setT60); CK_DLL_MFUN(expenv_getT60); CK_DLL_MFUN(expenv_keyOn); t_CKINT expenv_data_offset = 0; class ExpEnv { public: ExpEnv(float sr) { srate = sr; radius = 0.999; } SAMPLE tick() { value *= radius; return value; } t_CKFLOAT setValue(t_CKFLOAT f) { value = f; return value; } t_CKFLOAT getValue() { return value; } t_CKFLOAT setRadius(t_CKFLOAT f) { radius = f; if (radius < 1.0) { T60 = (t_CKDUR) -3.0/log10(radius)/srate; // check this someday } else T60 = 0.0; return radius; } t_CKFLOAT getRadius() { return radius; } t_CKDUR setT60(t_CKDUR samps) { T60 = samps; if (samps > 0) { radius = pow(10.0,-3.0/samps); } else radius = 1.0; return T60; } t_CKDUR getT60() { return T60; } t_CKINT keyOn() { value = 1.0; return 1; } private: t_CKFLOAT srate; t_CKFLOAT value; t_CKFLOAT radius; t_CKDUR T60; }; CK_DLL_QUERY(ExpEnv) { QUERY->setname(QUERY, "ExpEnv"); QUERY->begin_class(QUERY, "ExpEnv", "UGen"); QUERY->add_ctor(QUERY, expenv_ctor); QUERY->add_dtor(QUERY, expenv_dtor); QUERY->doc_class(QUERY, "ChucK Simple Decaying Exponential Envelope UGen\n\n" "Simple single time constant exponential decay, applied to any " "signal passed through it. Obeys: value, T60, radius, and keyOn " "Especially useful for Modal synthesis. One of these for each mode:\n" "SinOsc s => ExpEnv e => dac;\n\n" "Also useful for noise excitation pulse, using it like:\n" "Noise n => ExpEnv e => dac;"); QUERY->add_ex(QUERY, "effects/ExpEnv.ck"); QUERY->add_ex(QUERY, "effects/ExpEnv-modes.ck"); QUERY->add_ugen_func(QUERY, expenv_tick, NULL, 1, 1); QUERY->add_mfun(QUERY, expenv_setValue, "float", "value"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->add_mfun(QUERY, expenv_getValue, "float", "value"); QUERY->add_mfun(QUERY, expenv_setRadius, "float", "radius"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->add_mfun(QUERY, expenv_getRadius, "float", "radius"); QUERY->add_mfun(QUERY, expenv_setT60, "dur", "T60"); QUERY->add_arg(QUERY, "dur", "arg"); QUERY->doc_func(QUERY, "Set T60 delay time (time for sounds to decay by 60dB"); QUERY->add_mfun(QUERY, expenv_getT60, "dur", "T60"); QUERY->doc_func(QUERY, "Get T60 delay time (time for sounds to decay by 60dB"); QUERY->add_mfun(QUERY, expenv_keyOn, "int", "keyOn"); QUERY->add_arg(QUERY, "int", "arg"); expenv_data_offset = QUERY->add_mvar(QUERY, "int", "@expenv_data", false); QUERY->end_class(QUERY); return TRUE; } CK_DLL_CTOR(expenv_ctor) { OBJ_MEMBER_INT(SELF, expenv_data_offset) = 0; ExpEnv * c = new ExpEnv(API->vm->get_srate(API, SHRED)); OBJ_MEMBER_INT(SELF, expenv_data_offset) = (t_CKINT) c; } CK_DLL_DTOR(expenv_dtor) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); if(c) { delete c; OBJ_MEMBER_INT(SELF, expenv_data_offset) = 0; c = NULL; } } CK_DLL_TICK(expenv_tick) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); // if(c) // if it ain’t, why are we even here? *out = in * c->tick(); return TRUE; } CK_DLL_MFUN(expenv_setValue) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); // TODO: sanity check RETURN->v_float = c->setValue(GET_NEXT_FLOAT(ARGS)); } CK_DLL_MFUN(expenv_getValue) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); RETURN->v_float = c->getValue(); } CK_DLL_MFUN(expenv_setRadius) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); // TODO: sanity check RETURN->v_float = c->setRadius(GET_NEXT_FLOAT(ARGS)); } CK_DLL_MFUN(expenv_getRadius) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); RETURN->v_float = c->getRadius(); } CK_DLL_MFUN(expenv_setT60) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); // TODO: sanity check RETURN->v_float = c->setT60(GET_NEXT_FLOAT(ARGS)); } CK_DLL_MFUN(expenv_getT60) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); RETURN->v_float = c->getT60(); } CK_DLL_MFUN(expenv_keyOn) { ExpEnv * c = (ExpEnv *) OBJ_MEMBER_INT(SELF, expenv_data_offset); RETURN->v_int = c->keyOn(); }