rendered paste body/*-----------------------------------------------------------------------------
© 2002, Jeff M Soft und Hardware GmbH, All Rights Reserved
-----------------------------------------------------------------------------*/
#include "Module.h"
#include "SEMod_struct.h"
#include "SEPin.h"
#include <assert.h>
#include <math.h>
// define some constants to make referencing in/outs clearer
#define PN_INPUT1 0
#define PN_INPUT2 1
#define PN_INPUT3 2
#define PN_INPUT4 3
#define PN_INPUT5 4
#define PN_OUTPUT1 5
#define PN_OUTPUT2 6
#define COEF1 0.45 // 0.15 - 0.25
#define COEF2 1.16 // 1.16
#define MAXR 2.5
#define COEF3 0.3673
// #define COEFR 0.5
// The most important part, processing the audio
void Module::sub_MONO(long buffer_offset, long sampleFrames )
{
// assign some pointers to your in/output buffers. usually blocks (array) of 96 samples
float *in1 = buffer_offset + input1_buffer; // AUDIO-L
// float *in2 = buffer_offset + input2_buffer; // AUTIO-R
float *in3 = buffer_offset + input3_buffer; // Freq
float *in4 = buffer_offset + input4_buffer; // Reso
float *in5 = buffer_offset + input5_buffer; // <spare>
float *out1 = buffer_offset + output1_buffer;
float *out2 = buffer_offset + output2_buffer;
float *o3 = buffer_offset + o3_buffer;
float *o4 = buffer_offset + o4_buffer;
float *in6 = buffer_offset + input6_buffer; // <spare>
while(--sampleFrames >= 0) // sampleFrames = how many samples to process (can vary). repeat (loop) that many times
{
FREQ = (*in3 * 20000) * NI; // F / SR
if( FREQ >= 1 ) { FREQ = 1; }
else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; }
// original 1.16
F = FREQ * COEF2;
RES = *in4 * 2.5;
if( RES >= MAXR ) { RES = MAXR; }
FB = RES * (1.0 - COEF1 * F * F); // RES * (1.0 - 0.15 * F * F) // COEF1
LIM = *in5;
// ------------------------------------------- //
x0 = *in1 - (y4 * FB); // y4/OUT << (feedback)
// CX = 1 - (cy4 * FB);
CR = 0.54 - (RES * 0.0959999);
COEFR = CR + (FREQ * 0.25);
x0 *= COEFR * (F * F) * (F * F); // COEFR
// original 0.35013, good looking 0.5 // COEFR
// ; ------------------------------------------------------------------- Pole 1
y1 = x0 + COEF3 * x1 + (1 - F) * y1;
x1 = x0;
// ; ------------------------------------------------------------------- Pole 2
y2 = y1 + COEF3 * x2 + (1 - F) * y2;
x2 = y1;
// ; ------------------------------------------------------------------- Pole 3
y3 = y2 + COEF3 * x3 + (1 - F) * y3;
x3 = y2;
// ; ------------------------------------------------------------------- Pole 4
y4 = y3 + COEF3 * x4 + (1 - F) * y4;
x4 = y3;
// COEFX = 1.57 - 1.53 - (((RES - 1.47) * -0.358) + (RES - 3.975) * (((RES * -1) + 2.32) * 0.2225));
// COEFX = 0.633 + (RES * 0.8668);
COEFX = 0.404 + (RES * 0.8764001);
switch (MODE)
{
case 1:
OUT = y4 * 1; // LP
break;
case 2:
OUT = (*in1 - (y4 * COEFX)); // HP (pri res 1.4V e ok)
break;
case 3:
OUT = ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX));
break;
case 4:
OUT = *in1 + ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX));
break;
case 5:
F = 2.f * sin(M_PI * FREQ); //[approximately]
Q = *in4;
QS = Q;
SVFL = SVFL + F * SVFB;
SVFH = QS * *in1 - SVFL - Q * SVFB;
SVFB = F * SVFH + SVFB;
SVFN = SVFH + SVFL;
OUT = SVFL;
break;
default:
return;
};
// if (OUT > LIM) { OUT = LIM; }
// else if (OUT < (LIM * -1)) { OUT = (LIM * -1); }
*out1 = OUT; // OUTPUT
*out2 = OUT; // MONO
*o3 = RES * 0.1;
*o4 = FREQ * 0.1;
// increment the pointers (move to next sample in buffers)
in1++;
// in2++;
in3++;
in4++;
in5++;
in6++;
out1++;
out2++;
o3++;
o4++;
}
}
void Module::sub_STEREO(long buffer_offset, long sampleFrames )
{
// assign some pointers to your in/output buffers. usually blocks (array) of 96 samples
float *in1 = buffer_offset + input1_buffer; // AUDIO-L
float *in2 = buffer_offset + input2_buffer; // AUTIO-R
float *in3 = buffer_offset + input3_buffer; // Freq
float *in4 = buffer_offset + input4_buffer; // Reso
float *in5 = buffer_offset + input5_buffer; // <spare>
float *in6 = buffer_offset + input6_buffer;
float *out1 = buffer_offset + output1_buffer;
float *out2 = buffer_offset + output2_buffer;
while(--sampleFrames >= 0) // sampleFrames = how many samples to process (can vary). repeat (loop) that many times
{
FREQ = (*in3 * 20000) * NI;
if( FREQ >= 1 ) { FREQ = 1; }
else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; }
// original 1.16
F = FREQ * COEF2;
RES = *in4 * 2.5;
if( RES >= MAXR ) { RES = MAXR; }
FB = RES * (1.0 - COEF1 * F * F); // RES * (1.0 - 0.15 * F * F) // COEF1
LIM = *in5;
// ------------------------------------------- //
x0 = *in1 - (y4 * FB); // y4/OUT << (feedback)
v0 = *in2 - (z4 * FB); // y4/OUT << (feedback)
x0 *= COEFR * (F * F) * (F * F);
v0 *= COEFR * (F * F) * (F * F);
// original 0.35013, good looking 0.5 // COEFR
// ; ------------------------------------------------------------------- Pole 1
y1 = x0 + COEF3 * x1 + (1 - F) * y1;
z1 = v0 + COEF3 * v1 + (1 - F) * z1;
x1 = x0;
v1 = v0;
// ; ------------------------------------------------------------------- Pole 2
y2 = y1 + COEF3 * x2 + (1 - F) * y2;
z2 = z1 + COEF3 * v2 + (1 - F) * z2;
x2 = y1;
v2 = z1;
// ; ------------------------------------------------------------------- Pole 3
y3 = y2 + COEF3 * x3 + (1 - F) * y3;
z3 = z2 + COEF3 * v3 + (1 - F) * z3;
x3 = y2;
v3 = z2;
// ; ------------------------------------------------------------------- Pole 4
y4 = y3 + COEF3 * x4 + (1 - F) * y4;
z4 = z3 + COEF3 * v4 + (1 - F) * z4;
x4 = y3;
v4 = z3;
COEFX = 0.633 + (RES * 0.8668);
switch (MODE)
{
case 1:
OUTL = (y4 * COEFX); // LP
OUTR = (z4 * COEFX); // LP
break;
case 2:
OUTL = (*in1 - (y4 * COEFX)); // HP (pri res 1.4V e ok)
OUTR = (*in2 - (z4 * COEFX)); // HP (pri res 1.4V e ok)
break;
case 3:
OUTL = ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX));
OUTR = ((z1 * COEFX) + (z2 * COEFX) + (z3 * COEFX) + ((z4 * -1) * COEFX));
break;
case 4:
OUTL = *in1 + ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX));
OUTR = *in2 + ((z1 * COEFX) + (z2 * COEFX) + (z3 * COEFX) + ((z4 * -1) * COEFX));
break;
case 5:
y5 = y4 + COEF3 * x5 + (1 - F) * y5;
z5 = z4 + COEF3 * v5 + (1 - F) * z5;
x5 = y4;
v5 = z4;
y6 = y5 + COEF3 * x6 + (1 - F) * y6;
z6 = z5 + COEF3 * v6 + (1 - F) * z6;
x6 = y5;
v6 = z5;
OUTL = (y6 * 0.2);
OUTR = (z6 * 0.2);
break;
default:
return;
};
//OUTL = y4;
//OUTR = z4;
//if (OUTL > LIM) { OUTL = LIM; }
//else if (OUTL < (LIM * -1)) { OUTL = (LIM * -1); }
//if (OUTR > LIM) { OUTR = LIM; }
//else if (OUTR < (LIM * -1)) { OUTR = (LIM * -1); }
*out1 = OUTL; // OUTPUT
*out2 = OUTR; // OUTPUT
// increment the pointers (move to next sample in buffers)
in1++;
in2++;
in3++;
in4++;
in5++;
out1++;
out2++;
}
}
// every module has an output buffer of approx 100 samples.
// before deactivating module, need to fill that buffer with silence.
// "static_count" is counting out those 100 samples.
void Module::sub_process_static(long buffer_offset, long sampleFrames )
{
sub_MONO(buffer_offset, sampleFrames);
static_count = static_count - sampleFrames;
if( static_count <= 0 )
{
// CallHost(seaudioMasterSleepMode);
}
}
Module::Module(seaudioMasterCallback2 seaudioMaster, void *p_resvd1) : SEModule_base(seaudioMaster, p_resvd1)
{
}
void Module::open()
{
// SET SAMPLE RATE
SR = getSampleRate();
NI = SR / 2;
NI = 1 / NI;
// call the base class
SEModule_base::open();
// choose which function is used to process audio
SET_PROCESS_FUNC(Module::sub_MONO);
// How to prevent other people using your custom module.
// query the current registered user's name
char host_registered_to[100];
CallHost( seaudioMasterGetRegisteredName, 0,0, host_registered_to );
bool registered_to_me = strcmp(host_registered_to, "Jeff McClintock") == 0;
if( !registered_to_me )
{
// do something appropriate here if you don't want other people using your module
}
}
Module::~Module()
{
// This is where you free any memory/resources your module has created
}
// describe your module
bool Module::getModuleProperties (SEModuleProperties* properties)
{
// describe the plugin, this is the name the end-user will see.
properties->name = "AS_F24S"; // !!TODO!!
// return a unique string 32 characters max
// if posible include manufacturer and plugin identity
// this is used internally by SE to identify the plug.
// No two plugs may have the same id.
properties->id = "AS_F24S_v0.98"; // !!TODO!!
// Info, may include Author, Web page whatever
properties->about = "by Anton Savov [antto]"; // !!TODO!!
return true;
}
// describe the pins (plugs and parameters)
bool Module::getPinProperties (long index, SEPinProperties* properties)
{
switch( index ) // !!TODO!! list your in / out plugs
{
// typical input plug (inputs are listed first)
case 0:
properties->name = "LEFT";
properties->variable_address = &input1_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "0";
break;
case 1:
properties->name = "RIGHT";
properties->variable_address = &input2_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "0";
break;
case 2:
properties->name = "Freq(KHz)";
properties->variable_address = &input3_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "0.440";
break;
// typical output plug
case 3:
properties->name = "Res";
properties->variable_address = &input4_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "0";
break;
case 4:
properties->name = "Limit";
properties->variable_address = &input5_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "5";
break;
case 5:
properties->name = "LEFT";
properties->variable_address = &output1_buffer;
properties->direction = DR_OUT;
properties->datatype = DT_FSAMPLE;
break;
case 6:
properties->name = "RIGHT";
properties->variable_address = &output2_buffer;
properties->direction = DR_OUT;
properties->datatype = DT_FSAMPLE;
break;
case 7:
properties->name = "MONO/STEREO";
properties->variable_address = &MNST;
properties->datatype_extra = "MONO=1,STEREO=2";
properties->default_value = "1";
properties->direction = DR_IN;
properties->datatype = DT_ENUM;
break;
case 8:
properties->name = "MODE";
properties->variable_address = &MODE;
properties->datatype_extra = "LP24=1,HP24=2,BP24=3,BR24=4,SVF LP12=5";
properties->default_value = "1";
properties->direction = DR_IN;
properties->datatype = DT_ENUM;
break;
case 9:
properties->name = "F";
properties->variable_address = &o3_buffer;
properties->direction = DR_OUT;
properties->datatype = DT_FSAMPLE;
break;
case 10:
properties->name = "FB";
properties->variable_address = &o4_buffer;
properties->direction = DR_OUT;
properties->datatype = DT_FSAMPLE;
break;
case 11:
properties->name = "zzz";
properties->variable_address = &input6_buffer;
properties->direction = DR_IN;
properties->datatype = DT_FSAMPLE;
properties->default_value = "5";
break;
default:
return false; // host will ask for plugs 0,1,2,3 etc. return false to signal when done
};
return true;
}
// An input plug has changed value
void Module::OnPlugStateChange(SEPin *pin)
{
/*
if ( pin->getPinID() == 1 ) // Freq has changed!
{
float *in2;
FREQ = (*in2 * 20000) * NI;
if( FREQ >= 1 ) { FREQ = 1; }
else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; }
// original 1.16
F = FREQ * 1.16;
FB = RES * (1.0 - 0.15 * F * F);
}
if ( pin->getPinID() == 2 ) // Res has changed!
{
float *in3;
RES = *in3 * 2.5;
if( RES >= 2.5 ) { RES = 2.5; }
}
*/
// float test = getPin(PN_INPUT2)->getValue();
// int test2 = SampleClock();
if ( pin->getPinID() == 7 ) // MONO/STEREO has changed!
{
if (MNST == 1) { SET_PROCESS_FUNC(Module::sub_MONO); }
else if (MNST == 2) { SET_PROCESS_FUNC(Module::sub_STEREO); }
}
if ( pin->getPinID() == 11 ) // RESET has changed!
{
if (RSTx <= 0 && getPin(11)->getValue() > 0)
{
x0 = x1 = x2 = x3 = x4 = 0;
v0 = v1 = v2 = v3 = v4 = 0;
y1 = y2 = y3 = y4 = 0;
z1 = z2 = z3 = z4 = 0;
}
RSTx = getPin(11)->getValue();
}
// query the 'state of the input plugs...
// ST_RUN = Normal Streaming Audio (e.g. from an oscillator)
// ST_STATIC = Fixed, unchanging input value (e.g. a slider at rest)
state_type in_stat1 = getPin(PN_INPUT1)->getStatus();
state_type in_stat2 = getPin(PN_INPUT2)->getStatus();
// we need to pass on the state of this module's output signal
// it depends on the inputs...
state_type out_stat = in_stat1;
if( in_stat2 > out_stat)
out_stat = in_stat2;
// if user has set either input to zero, we can tell downstream modules that the audio has stopped
/*
if( in_stat1 < ST_RUN && getPin(PN_INPUT1)->getValue() == 0.f )
{
out_stat = ST_STATIC;
}
if( in_stat2 < ST_RUN && getPin(PN_INPUT2)->getValue() == 0.f )
{
out_stat = ST_STATIC;
}
*/
// 'transmit' this modules new output status to next module 'downstream'
getPin(PN_OUTPUT1)->TransmitStatusChange( SampleClock(), ST_RUN);
getPin(PN_OUTPUT2)->TransmitStatusChange( SampleClock(), ST_RUN);
getPin(9)->TransmitStatusChange( SampleClock(), ST_RUN);
getPin(10)->TransmitStatusChange( SampleClock(), ST_RUN);
// setup up 'sleep mode' or not
/* if( out_stat < ST_RUN )
{
static_count = getBlockSize();
SET_PROCESS_FUNC(Module::sub_process_static);
}
else
{
SET_PROCESS_FUNC(Module::sub_MONO);
}
*/
}