//-----------------------------------------------------------------------------// This is a virtual analog model of the Diode Ladder filter.// The VADiodeLadderFilter and VAOnePoleFilter are taken directly from // Will Pirkle's applications notes, and can be found at//// http://www.willpirkle.com/Downloads/AN-6DiodeLadderFilter.pdf//// Ported by Owen Vallis 2015//// This is a Chugin boilerplate, generated by chuginate!//----------------------------------------------------------------------------- // this should align with the correct versions of these ChucK files#include "chuck_dl.h"#include "chuck_def.h" // general includes#include <stdio.h>#include <limits.h> //Pirckle files#include "VADiodeLadderFilter.h" // declaration of chugin constructorCK_DLL_CTOR(wpdiodeladder_ctor);// declaration of chugin desctructorCK_DLL_DTOR(wpdiodeladder_dtor); // Resonance goes between [0...17]CK_DLL_MFUN(wpdiodeladder_setResonance);CK_DLL_MFUN(wpdiodeladder_getResonance); // Cuttoff is in Hz [0..Nyquist)CK_DLL_MFUN(wpdiodeladder_setCutoff);CK_DLL_MFUN(wpdiodeladder_getCutoff); // Saturation is a scalar gain and // can be used to drive the signal// into the non linear saturatorCK_DLL_MFUN(wpdiodeladder_setSaturation);CK_DLL_MFUN(wpdiodeladder_getSaturation); // Enable non linear saturatorCK_DLL_MFUN(wpdiodeladder_setNonLinearProcessing);CK_DLL_MFUN(wpdiodeladder_getNonLinearProcessing); // the 1/tanh(sat) is to normalize the function // so x = [-1..+1] --> y = [-1..+1] Normalized VersionCK_DLL_MFUN(wpdiodeladder_setNonLinearType);CK_DLL_MFUN(wpdiodeladder_getNonLinearType); // for Chugins extending UGen, this is mono synthesis function for 1 sampleCK_DLL_TICK(wpdiodeladder_tick); // this is a special offset reserved for Chugin internal datat_CKINT wpdiodeladder_data_offset = 0; // class definition for internal Chugin data// (note: this isn't strictly necessary, but serves as example// of one recommended approach)class WPDiodeLadder{public: // constructor WPDiodeLadder( t_CKFLOAT fs) { diodeFilter.prepareForPlay(fs); } // for Chugins extending UGen SAMPLE tick( SAMPLE in ) { // default: this passes whatever input is patched into Chugin return diodeFilter.doFilter(in); } float setResonance( t_CKFLOAT p ) { diodeFilter.m_dK = p; diodeFilter.updateFilter(); return p; } float getResonance() { return diodeFilter.m_dK; } float setCutoff( t_CKFLOAT p ) { diodeFilter.m_dFc = p; diodeFilter.updateFilter(); return p; } float getCutoff() { return diodeFilter.m_dFc; } float setSaturation( t_CKFLOAT p ) { diodeFilter.m_dSaturation = p; return p; } float getSaturation() { return diodeFilter.m_dSaturation; } bool setNonLinearProcessing( t_CKBOOL p ) { diodeFilter.m_NonLinearProcessing = p; return p; } bool getNonLinearProcessing() { return diodeFilter.m_NonLinearProcessing; } bool setNonLinearType( t_CKBOOL p ) { diodeFilter.m_uNLPType = p; return p; } bool getNonLinearType() { return diodeFilter.m_uNLPType; } private: // instance data CVADiodeLadderFilter diodeFilter;}; // query function: chuck calls this when loading the Chugin// NOTE: developer will need to modify this function to// add additional functions to this ChuginCK_DLL_QUERY( WPDiodeLadder ){ // hmm, don't change this... QUERY->setname(QUERY, "WPDiodeLadder"); // begin the class definition // can change the second argument to extend a different ChucK class QUERY->begin_class(QUERY, "WPDiodeLadder", "UGen"); QUERY->doc_class(QUERY, "Virtual analog low pass filter based on Will Pirkle's Diode Ladder application notes"); QUERY->add_ex(QUERY, "filter/WPDiodeLadder.ck"); // register the constructor (probably no need to change) QUERY->add_ctor(QUERY, wpdiodeladder_ctor); // register the destructor (probably no need to change) QUERY->add_dtor(QUERY, wpdiodeladder_dtor); // for UGen's only: add tick function QUERY->add_ugen_func(QUERY, wpdiodeladder_tick, NULL, 1, 1); // NOTE: if this is to be a UGen with more than 1 channel, // e.g., a multichannel UGen -- will need to use add_ugen_funcf() // and declare a tickf function using CK_DLL_TICKF QUERY->add_mfun(QUERY, wpdiodeladder_setResonance, "float", "resonance"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->doc_func(QUERY, "Resonance goes between [0...17]. "); QUERY->add_mfun(QUERY, wpdiodeladder_getResonance, "float", "resonance"); QUERY->doc_func(QUERY, "Get resonance [0 - 17]."); QUERY->add_mfun(QUERY, wpdiodeladder_setCutoff, "float", "cutoff"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->doc_func(QUERY, "Cuttoff is in Hz [0..Nyquist). "); QUERY->add_mfun(QUERY, wpdiodeladder_getCutoff, "float", "cutoff"); QUERY->doc_func(QUERY, "Get cuttoff frequency in Hz [0..Nyquist)."); QUERY->add_mfun(QUERY, wpdiodeladder_setSaturation, "float", "saturation"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->doc_func(QUERY, "Saturation is a scalar gain, and can be used to drive the non-linearity. "); QUERY->add_mfun(QUERY, wpdiodeladder_getSaturation, "float", "saturation"); QUERY->doc_func(QUERY, "Get saturation. Saturation is a scalar gain, and can be used to drive the non-linearity."); QUERY->add_mfun(QUERY, wpdiodeladder_setNonLinearProcessing, "int", "nonlinear"); QUERY->add_arg(QUERY, "int", "arg"); QUERY->doc_func(QUERY, "Enable non linear saturator. "); QUERY->add_mfun(QUERY, wpdiodeladder_getNonLinearProcessing, "int", "nonlinear"); QUERY->doc_func(QUERY, "Get non-linear saturator setting. 1 is enabled."); QUERY->add_mfun(QUERY, wpdiodeladder_setNonLinearType, "int", "nlp_type"); QUERY->add_arg(QUERY, "int", "arg"); QUERY->doc_func(QUERY, "Set to 1 to normalize non-linear output. "); QUERY->add_mfun(QUERY, wpdiodeladder_getNonLinearType, "int", "nlp_type"); QUERY->doc_func(QUERY, "Get non-linear output setting. 1 is normalized."); // this reserves a variable in the ChucK internal class to store // referene to the c++ class we defined above wpdiodeladder_data_offset = QUERY->add_mvar(QUERY, "int", "@wpdl_data", false); // end the class definition // IMPORTANT: this MUST be called! QUERY->end_class(QUERY); // wasn't that a breeze? return TRUE;} // implementation for the constructorCK_DLL_CTOR(wpdiodeladder_ctor){ // get the offset where we'll store our internal c++ class pointer OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = 0; // instantiate our internal c++ class representation WPDiodeLadder * bcdata = new WPDiodeLadder(API->vm->get_srate(API, SHRED)); // store the pointer in the ChucK object member OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = (t_CKINT) bcdata;} // implementation for the destructorCK_DLL_DTOR(wpdiodeladder_dtor){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // check it if( bcdata ) { // clean up delete bcdata; OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = 0; bcdata = NULL; }} // implementation for tick functionCK_DLL_TICK(wpdiodeladder_tick){ // get our c++ class pointer WPDiodeLadder * c = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // invoke our tick function; store in the magical out variable if(c) *out = c->tick(in); // yes return TRUE;} // example implementation for setterCK_DLL_MFUN(wpdiodeladder_setResonance){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->setResonance(GET_NEXT_FLOAT(ARGS));} // example implementation for getterCK_DLL_MFUN(wpdiodeladder_getResonance){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->getResonance();} // example implementation for setterCK_DLL_MFUN(wpdiodeladder_setCutoff){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->setCutoff(GET_NEXT_FLOAT(ARGS));} // example implementation for getterCK_DLL_MFUN(wpdiodeladder_getCutoff){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->getCutoff();} // example implementation for setterCK_DLL_MFUN(wpdiodeladder_setSaturation){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->setSaturation(GET_NEXT_FLOAT(ARGS));} // example implementation for getterCK_DLL_MFUN(wpdiodeladder_getSaturation){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->getSaturation();} // example implementation for setterCK_DLL_MFUN(wpdiodeladder_setNonLinearProcessing){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->setNonLinearProcessing(GET_NEXT_FLOAT(ARGS));} // example implementation for getterCK_DLL_MFUN(wpdiodeladder_getNonLinearProcessing){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->getNonLinearProcessing();} // example implementation for setterCK_DLL_MFUN(wpdiodeladder_setNonLinearType){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->setNonLinearType(GET_NEXT_FLOAT(ARGS));} // example implementation for getterCK_DLL_MFUN(wpdiodeladder_getNonLinearType){ // get our c++ class pointer WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset); // set the return value RETURN->v_float = bcdata->getNonLinearType();}
//-----------------------------------------------------------------------------
// This is a virtual analog model of the Diode Ladder filter.
// The VADiodeLadderFilter and VAOnePoleFilter are taken directly from
// Will Pirkle's applications notes, and can be found at
//
// http://www.willpirkle.com/Downloads/AN-6DiodeLadderFilter.pdf
//
// Ported by Owen Vallis 2015
//
// This is a Chugin boilerplate, generated by chuginate!
//-----------------------------------------------------------------------------
// this should align with the correct versions of these ChucK files
#include "chuck_dl.h"
#include "chuck_def.h"
// general includes
#include <stdio.h>
#include <limits.h>
//Pirckle files
#include "VADiodeLadderFilter.h"
// declaration of chugin constructor
CK_DLL_CTOR(wpdiodeladder_ctor);
// declaration of chugin desctructor
CK_DLL_DTOR(wpdiodeladder_dtor);
// Resonance goes between [0...17]
CK_DLL_MFUN(wpdiodeladder_setResonance);
CK_DLL_MFUN(wpdiodeladder_getResonance);
// Cuttoff is in Hz [0..Nyquist)
CK_DLL_MFUN(wpdiodeladder_setCutoff);
CK_DLL_MFUN(wpdiodeladder_getCutoff);
// Saturation is a scalar gain and
// can be used to drive the signal
// into the non linear saturator
CK_DLL_MFUN(wpdiodeladder_setSaturation);
CK_DLL_MFUN(wpdiodeladder_getSaturation);
// Enable non linear saturator
CK_DLL_MFUN(wpdiodeladder_setNonLinearProcessing);
CK_DLL_MFUN(wpdiodeladder_getNonLinearProcessing);
// the 1/tanh(sat) is to normalize the function
// so x = [-1..+1] --> y = [-1..+1] Normalized Version
CK_DLL_MFUN(wpdiodeladder_setNonLinearType);
CK_DLL_MFUN(wpdiodeladder_getNonLinearType);
// for Chugins extending UGen, this is mono synthesis function for 1 sample
CK_DLL_TICK(wpdiodeladder_tick);
// this is a special offset reserved for Chugin internal data
t_CKINT wpdiodeladder_data_offset = 0;
// class definition for internal Chugin data
// (note: this isn't strictly necessary, but serves as example
// of one recommended approach)
class WPDiodeLadder
{
public:
// constructor
WPDiodeLadder( t_CKFLOAT fs)
{
diodeFilter.prepareForPlay(fs);
}
// for Chugins extending UGen
SAMPLE tick( SAMPLE in )
{
// default: this passes whatever input is patched into Chugin
return diodeFilter.doFilter(in);
}
float setResonance( t_CKFLOAT p )
{
diodeFilter.m_dK = p;
diodeFilter.updateFilter();
return p;
}
float getResonance() { return diodeFilter.m_dK; }
float setCutoff( t_CKFLOAT p )
{
diodeFilter.m_dFc = p;
diodeFilter.updateFilter();
return p;
}
float getCutoff() { return diodeFilter.m_dFc; }
float setSaturation( t_CKFLOAT p )
{
diodeFilter.m_dSaturation = p;
return p;
}
float getSaturation() { return diodeFilter.m_dSaturation; }
bool setNonLinearProcessing( t_CKBOOL p )
{
diodeFilter.m_NonLinearProcessing = p;
return p;
}
bool getNonLinearProcessing() { return diodeFilter.m_NonLinearProcessing; }
bool setNonLinearType( t_CKBOOL p )
{
diodeFilter.m_uNLPType = p;
return p;
}
bool getNonLinearType() { return diodeFilter.m_uNLPType; }
private:
// instance data
CVADiodeLadderFilter diodeFilter;
};
// query function: chuck calls this when loading the Chugin
// NOTE: developer will need to modify this function to
// add additional functions to this Chugin
CK_DLL_QUERY( WPDiodeLadder )
{
// hmm, don't change this...
QUERY->setname(QUERY, "WPDiodeLadder");
// begin the class definition
// can change the second argument to extend a different ChucK class
QUERY->begin_class(QUERY, "WPDiodeLadder", "UGen");
QUERY->doc_class(QUERY, "Virtual analog low pass filter based on Will Pirkle's Diode Ladder application notes");
QUERY->add_ex(QUERY, "filter/WPDiodeLadder.ck");
// register the constructor (probably no need to change)
QUERY->add_ctor(QUERY, wpdiodeladder_ctor);
// register the destructor (probably no need to change)
QUERY->add_dtor(QUERY, wpdiodeladder_dtor);
// for UGen's only: add tick function
QUERY->add_ugen_func(QUERY, wpdiodeladder_tick, NULL, 1, 1);
// NOTE: if this is to be a UGen with more than 1 channel,
// e.g., a multichannel UGen -- will need to use add_ugen_funcf()
// and declare a tickf function using CK_DLL_TICKF
QUERY->add_mfun(QUERY, wpdiodeladder_setResonance, "float", "resonance");
QUERY->add_arg(QUERY, "float", "arg");
QUERY->doc_func(QUERY, "Resonance goes between [0...17]. ");
QUERY->add_mfun(QUERY, wpdiodeladder_getResonance, "float", "resonance");
QUERY->doc_func(QUERY, "Get resonance [0 - 17].");
QUERY->add_mfun(QUERY, wpdiodeladder_setCutoff, "float", "cutoff");
QUERY->add_arg(QUERY, "float", "arg");
QUERY->doc_func(QUERY, "Cuttoff is in Hz [0..Nyquist). ");
QUERY->add_mfun(QUERY, wpdiodeladder_getCutoff, "float", "cutoff");
QUERY->doc_func(QUERY, "Get cuttoff frequency in Hz [0..Nyquist).");
QUERY->add_mfun(QUERY, wpdiodeladder_setSaturation, "float", "saturation");
QUERY->add_arg(QUERY, "float", "arg");
QUERY->doc_func(QUERY, "Saturation is a scalar gain, and can be used to drive the non-linearity. ");
QUERY->add_mfun(QUERY, wpdiodeladder_getSaturation, "float", "saturation");
QUERY->doc_func(QUERY, "Get saturation. Saturation is a scalar gain, and can be used to drive the non-linearity.");
QUERY->add_mfun(QUERY, wpdiodeladder_setNonLinearProcessing, "int", "nonlinear");
QUERY->add_arg(QUERY, "int", "arg");
QUERY->doc_func(QUERY, "Enable non linear saturator. ");
QUERY->add_mfun(QUERY, wpdiodeladder_getNonLinearProcessing, "int", "nonlinear");
QUERY->doc_func(QUERY, "Get non-linear saturator setting. 1 is enabled.");
QUERY->add_mfun(QUERY, wpdiodeladder_setNonLinearType, "int", "nlp_type");
QUERY->add_arg(QUERY, "int", "arg");
QUERY->doc_func(QUERY, "Set to 1 to normalize non-linear output. ");
QUERY->add_mfun(QUERY, wpdiodeladder_getNonLinearType, "int", "nlp_type");
QUERY->doc_func(QUERY, "Get non-linear output setting. 1 is normalized.");
// this reserves a variable in the ChucK internal class to store
// referene to the c++ class we defined above
wpdiodeladder_data_offset = QUERY->add_mvar(QUERY, "int", "@wpdl_data", false);
// end the class definition
// IMPORTANT: this MUST be called!
QUERY->end_class(QUERY);
// wasn't that a breeze?
return TRUE;
}
// implementation for the constructor
CK_DLL_CTOR(wpdiodeladder_ctor)
{
// get the offset where we'll store our internal c++ class pointer
OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = 0;
// instantiate our internal c++ class representation
WPDiodeLadder * bcdata = new WPDiodeLadder(API->vm->get_srate(API, SHRED));
// store the pointer in the ChucK object member
OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = (t_CKINT) bcdata;
}
// implementation for the destructor
CK_DLL_DTOR(wpdiodeladder_dtor)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// check it
if( bcdata )
{
// clean up
delete bcdata;
OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset) = 0;
bcdata = NULL;
}
}
// implementation for tick function
CK_DLL_TICK(wpdiodeladder_tick)
{
// get our c++ class pointer
WPDiodeLadder * c = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// invoke our tick function; store in the magical out variable
if(c) *out = c->tick(in);
// yes
return TRUE;
}
// example implementation for setter
CK_DLL_MFUN(wpdiodeladder_setResonance)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->setResonance(GET_NEXT_FLOAT(ARGS));
}
// example implementation for getter
CK_DLL_MFUN(wpdiodeladder_getResonance)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->getResonance();
}
// example implementation for setter
CK_DLL_MFUN(wpdiodeladder_setCutoff)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->setCutoff(GET_NEXT_FLOAT(ARGS));
}
// example implementation for getter
CK_DLL_MFUN(wpdiodeladder_getCutoff)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->getCutoff();
}
// example implementation for setter
CK_DLL_MFUN(wpdiodeladder_setSaturation)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->setSaturation(GET_NEXT_FLOAT(ARGS));
}
// example implementation for getter
CK_DLL_MFUN(wpdiodeladder_getSaturation)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->getSaturation();
}
// example implementation for setter
CK_DLL_MFUN(wpdiodeladder_setNonLinearProcessing)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->setNonLinearProcessing(GET_NEXT_FLOAT(ARGS));
}
// example implementation for getter
CK_DLL_MFUN(wpdiodeladder_getNonLinearProcessing)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->getNonLinearProcessing();
}
// example implementation for setter
CK_DLL_MFUN(wpdiodeladder_setNonLinearType)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->setNonLinearType(GET_NEXT_FLOAT(ARGS));
}
// example implementation for getter
CK_DLL_MFUN(wpdiodeladder_getNonLinearType)
{
// get our c++ class pointer
WPDiodeLadder * bcdata = (WPDiodeLadder *) OBJ_MEMBER_INT(SELF, wpdiodeladder_data_offset);
// set the return value
RETURN->v_float = bcdata->getNonLinearType();
}