mame/src/emu/sound/disc_flt.c

1424 lines
42 KiB
C

/************************************************************************
*
* MAME - Discrete sound system emulation library
*
* Written by Keith Wilkins (mame@esplexo.co.uk)
*
* (c) K.Wilkins 2000
*
***********************************************************************
*
* DST_CRFILTER - Simple CR filter & also highpass filter
* DST_FILTER1 - Generic 1st order filter
* DST_FILTER2 - Generic 2nd order filter
* DST_OP_AMP_FILT - Op Amp filter circuits
* DST_RCDISC - Simple discharging RC
* DST_RCDISC2 - Simple charge R1/C, discharge R0/C
* DST_RCDISC3 - Simple charge R1/c, discharge R0*R1/(R0+R1)/C
* DST_RCDISC4 - Various charge/discharge circuits
* DST_RCDISC5 - Diode in series with R//C
* DST_RCDISC_MOD - RC triggered by logic and modulated
* DST_RCFILTER - Simple RC filter & also lowpass filter
* DST_RCFILTER_SW - Usage of node_description values for switchable RC filter
* DST_RCINTEGRATE - Two diode inputs, transistor and a R/C charge
* discharge network
* DST_SALLEN_KEY - Sallen-Key filter circuit
*
************************************************************************/
struct dss_filter1_context
{
double x1; /* x[k-1], previous input value */
double y1; /* y[k-1], previous output value */
double a1; /* digital filter coefficients, denominator */
double b0, b1; /* digital filter coefficients, numerator */
};
struct dss_filter2_context
{
double x1, x2; /* x[k-1], x[k-2], previous 2 input values */
double y1, y2; /* y[k-1], y[k-2], previous 2 output values */
double a1, a2; /* digital filter coefficients, denominator */
double b0, b1, b2; /* digital filter coefficients, numerator */
};
struct dst_op_amp_filt_context
{
int type; /* What kind of filter */
int is_norton; /* 1 = Norton op-amps */
double vRef;
double vP;
double vN;
double rTotal; /* All input resistance in parallel. */
double iFixed; /* Current supplied by r3 & r4 if used. */
double exponentC1;
double exponentC2;
double exponentC3;
double rRatio; /* divide ratio of resistance network */
double vC1; /* Charge on C1 */
double vC1b; /* Charge on C1, part of C1 charge if needed */
double vC2; /* Charge on C2 */
double vC3; /* Charge on C2 */
double gain; /* Gain of the filter */
double x1, x2; /* x[k-1], x[k-2], previous 2 input values */
double y1, y2; /* y[k-1], y[k-2], previous 2 output values */
double a1,a2; /* digital filter coefficients, denominator */
double b0,b1,b2; /* digital filter coefficients, numerator */
};
struct dst_rcdisc_context
{
int state;
double t; /* time */
double exponent0;
double exponent1;
};
struct dst_rcdisc_mod_context
{
double v_cap;
double exp_low[2];
double exp_high[4];
double gain[2];
double vd_gain[4];
};
struct dst_rcdisc4_context
{
int type;
double max_out;
double vC1;
double v[2];
double exp[2];
};
struct dst_rcfilter_context
{
double exponent;
double vCap;
};
struct dst_rcfilter_sw_context
{
double vCap[4];
double exp[4];
double exp0; /* fast case bit 0 */
double exp1; /* fast case bit 1 */
double factor; /* fast case */
};
struct dst_rcintegrate_context
{
int type;
double gain_r1_r2;
double f; /* r2,r3 gain */
double vCap;
double vCE;
double exponent0;
double exponent1;
double exp_exponent0;
double exp_exponent1;
double c_exp0;
double c_exp1;
};
/************************************************************************
*
* DST_CRFILTER - Usage of node_description values for CR filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
* input[4] - Voltage reference. Usually 0V.
*
************************************************************************/
#define DST_CRFILTER__ENABLE (*(node->input[0]))
#define DST_CRFILTER__IN (*(node->input[1]))
#define DST_CRFILTER__R (*(node->input[2]))
#define DST_CRFILTER__C (*(node->input[3]))
#define DST_CRFILTER__VREF (*(node->input[4]))
static DISCRETE_STEP(dst_crfilter)
{
struct dst_rcfilter_context *context = node->context;
if(DST_CRFILTER__ENABLE)
{
node->output[0] = DST_CRFILTER__IN - context->vCap;
context->vCap += ((DST_CRFILTER__IN - DST_CRFILTER__VREF) - context->vCap) * context->exponent;
}
else
{
node->output[0] = 0;
}
}
static DISCRETE_RESET(dst_crfilter)
{
struct dst_rcfilter_context *context = node->context;
context->exponent = RC_CHARGE_EXP(DST_CRFILTER__R * DST_CRFILTER__C);
context->vCap = 0;
node->output[0] = DST_CRFILTER__IN;
}
/************************************************************************
*
* DST_FILTER1 - Generic 1st order filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Frequency value (initialization only)
* input[3] - Filter type (initialization only)
*
************************************************************************/
#define DST_FILTER1__ENABLE (*(node->input[0]))
#define DST_FILTER1__IN (*(node->input[1]))
#define DST_FILTER1__FREQ (*(node->input[2]))
#define DST_FILTER1__TYPE (*(node->input[3]))
static void calculate_filter1_coefficients(double fc, double type,
double *a1, double *b0, double *b1)
{
double den, w, two_over_T;
/* calculate digital filter coefficents */
/*w = 2.0*M_PI*fc; no pre-warping */
w = discrete_current_context->sample_rate*2.0*tan(M_PI*fc/discrete_current_context->sample_rate); /* pre-warping */
two_over_T = 2.0*discrete_current_context->sample_rate;
den = w + two_over_T;
*a1 = (w - two_over_T)/den;
if (type == DISC_FILTER_LOWPASS)
{
*b0 = *b1 = w/den;
}
else if (type == DISC_FILTER_HIGHPASS)
{
*b0 = two_over_T/den;
*b1 = -(*b0);
}
else
{
discrete_log("calculate_filter1_coefficients() - Invalid filter type for 1st order filter.");
}
}
static DISCRETE_STEP(dst_filter1)
{
struct dss_filter1_context *context = node->context;
double gain = 1.0;
if (DST_FILTER1__ENABLE == 0.0)
{
gain = 0.0;
}
node->output[0] = -context->a1*context->y1 + context->b0*gain*DST_FILTER1__IN + context->b1*context->x1;
context->x1 = gain*DST_FILTER1__IN;
context->y1 = node->output[0];
}
static DISCRETE_RESET(dst_filter1)
{
struct dss_filter1_context *context = node->context;
calculate_filter1_coefficients(DST_FILTER1__FREQ, DST_FILTER1__TYPE, &context->a1, &context->b0, &context->b1);
node->output[0] = 0;
}
/************************************************************************
*
* DST_FILTER2 - Generic 2nd order filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Frequency value (initialization only)
* input[3] - Damping value (initialization only)
* input[4] - Filter type (initialization only)
*
************************************************************************/
#define DST_FILTER2__ENABLE (*(node->input[0]))
#define DST_FILTER2__IN (*(node->input[1]))
#define DST_FILTER2__FREQ (*(node->input[2]))
#define DST_FILTER2__DAMP (*(node->input[3]))
#define DST_FILTER2__TYPE (*(node->input[4]))
static void calculate_filter2_coefficients(double fc, double d, double type,
double *a1, double *a2,
double *b0, double *b1, double *b2)
{
double w; /* cutoff freq, in radians/sec */
double w_squared;
double den; /* temp variable */
double two_over_T = 2*discrete_current_context->sample_rate;
double two_over_T_squared = two_over_T * two_over_T;
/* calculate digital filter coefficents */
/*w = 2.0*M_PI*fc; no pre-warping */
w = discrete_current_context->sample_rate * 2.0 * tan(M_PI * fc / discrete_current_context->sample_rate); /* pre-warping */
w_squared = w * w;
den = two_over_T_squared + d*w*two_over_T + w_squared;
*a1 = 2.0 * (-two_over_T_squared + w_squared) / den;
*a2 = (two_over_T_squared - d * w * two_over_T + w_squared) / den;
if (type == DISC_FILTER_LOWPASS)
{
*b0 = *b2 = w_squared/den;
*b1 = 2.0 * (*b0);
}
else if (type == DISC_FILTER_BANDPASS)
{
*b0 = d * w * two_over_T / den;
*b1 = 0.0;
*b2 = -(*b0);
}
else if (type == DISC_FILTER_HIGHPASS)
{
*b0 = *b2 = two_over_T_squared / den;
*b1 = -2.0 * (*b0);
}
else
{
discrete_log("calculate_filter2_coefficients() - Invalid filter type for 2nd order filter.");
}
}
static DISCRETE_STEP(dst_filter2)
{
struct dss_filter2_context *context = node->context;
double gain = 1.0;
if (DST_FILTER2__ENABLE == 0.0)
{
gain = 0.0;
}
node->output[0] = -context->a1 * context->y1 - context->a2 * context->y2 +
context->b0 * gain * DST_FILTER2__IN + context->b1 * context->x1 + context->b2 * context->x2;
context->x2 = context->x1;
context->x1 = gain * DST_FILTER2__IN;
context->y2 = context->y1;
context->y1 = node->output[0];
}
static DISCRETE_RESET(dst_filter2)
{
struct dss_filter2_context *context = node->context;
calculate_filter2_coefficients(DST_FILTER2__FREQ, DST_FILTER2__DAMP, DST_FILTER2__TYPE,
&context->a1, &context->a2,
&context->b0, &context->b1, &context->b2);
node->output[0] = 0;
}
/************************************************************************
*
* DST_OP_AMP_FILT - Op Amp filter circuit RC filter
*
* input[0] - Enable input value
* input[1] - IN0 node
* input[2] - IN1 node
* input[3] - Filter Type
*
* also passed discrete_op_amp_filt_info structure
*
* Mar 2004, D Renaud.
************************************************************************/
#define DST_OP_AMP_FILT__ENABLE (*(node->input[0]))
#define DST_OP_AMP_FILT__INP1 (*(node->input[1]))
#define DST_OP_AMP_FILT__INP2 (*(node->input[2]))
#define DST_OP_AMP_FILT__TYPE (*(node->input[3]))
static DISCRETE_STEP(dst_op_amp_filt)
{
const discrete_op_amp_filt_info *info = node->custom;
struct dst_op_amp_filt_context *context = node->context;
double i, v = 0;
if (DST_OP_AMP_FILT__ENABLE)
{
if (context->is_norton)
{
v = DST_OP_AMP_FILT__INP1 - OP_AMP_NORTON_VBE;
if (v < 0) v = 0;
}
else
{
/* Millman the input voltages. */
i = context->iFixed;
i += (DST_OP_AMP_FILT__INP1 - context->vRef) / info->r1;
if (info->r2 != 0)
i += (DST_OP_AMP_FILT__INP2 - context->vRef) / info->r2;
v = i * context->rTotal;
}
switch (context->type)
{
case DISC_OP_AMP_FILTER_IS_LOW_PASS_1:
context->vC1 += (v - context->vC1) * context->exponentC1;
node->output[0] = context->vC1 * context->gain + info->vRef;
break;
case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1:
node->output[0] = (v - context->vC1) * context->gain + info->vRef;
context->vC1 += (v - context->vC1) * context->exponentC1;
break;
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1:
node->output[0] = (v - context->vC2);
context->vC2 += (v - context->vC2) * context->exponentC2;
context->vC1 += (node->output[0] - context->vC1) * context->exponentC1;
node->output[0] = context->vC1 * context->gain + info->vRef;
break;
case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON:
context->vC1 += (v - context->vC1) * context->exponentC1;
context->vC2 += (context->vC1 - context->vC2) * context->exponentC2;
v = context->vC2;
node->output[0] = v - context->vC3;
context->vC3 += (v - context->vC3) * context->exponentC3;
i = node->output[0] / context->rTotal;
node->output[0] = (context->iFixed - i) * info->rF;
break;
case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON:
node->output[0] = v - context->vC1;
context->vC1 += (v - context->vC1) * context->exponentC1;
i = node->output[0] / context->rTotal;
node->output[0] = (context->iFixed - i) * info->rF;
break;
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M:
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON:
node->output[0] = -context->a1 * context->y1 - context->a2 * context->y2 +
context->b0 * v + context->b1 * context->x1 + context->b2 * context->x2 +
context->vRef;
context->x2 = context->x1;
context->x1 = v;
context->y2 = context->y1;
break;
}
/* Clip the output to the voltage rails.
* This way we get the original distortion in all it's glory.
*/
if (node->output[0] > context->vP) node->output[0] = context->vP;
if (node->output[0] < context->vN) node->output[0] = context->vN;
context->y1 = node->output[0] - context->vRef;
}
else
node->output[0] = 0;
}
static DISCRETE_RESET(dst_op_amp_filt)
{
const discrete_op_amp_filt_info *info = node->custom;
struct dst_op_amp_filt_context *context = node->context;
/* Convert the passed filter type into an int for easy use. */
context->type = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_FILTER_TYPE_MASK;
context->is_norton = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_IS_NORTON;
if (context->is_norton)
{
context->vRef = 0;
context->rTotal = info->r1;
if (context->type == (DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON))
context->rTotal += info->r2 + info->r3;
/* Setup the current to the + input. */
context->iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r4;
/* Set the output max. */
context->vP = info->vP - OP_AMP_NORTON_VBE;
context->vN = info->vN;
}
else
{
context->vRef = info->vRef;
/* Set the output max. */
context->vP = info->vP - OP_AMP_VP_RAIL_OFFSET;
context->vN = info->vN;
/* Work out the input resistance. It is all input and bias resistors in parallel. */
context->rTotal = 1.0 / info->r1; /* There has to be an R1. Otherwise the table is wrong. */
if (info->r2 != 0) context->rTotal += 1.0 / info->r2;
if (info->r3 != 0) context->rTotal += 1.0 / info->r3;
context->rTotal = 1.0 / context->rTotal;
context->iFixed = 0;
context->rRatio = info->rF / (context->rTotal + info->rF);
context->gain = -info->rF / context->rTotal;
}
switch (context->type)
{
case DISC_OP_AMP_FILTER_IS_LOW_PASS_1:
context->exponentC1 = RC_CHARGE_EXP(info->rF * info->c1);
context->exponentC2 = 0;
break;
case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1:
context->exponentC1 = RC_CHARGE_EXP(context->rTotal * info->c1);
context->exponentC2 = 0;
break;
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1:
context->exponentC1 = RC_CHARGE_EXP(info->rF * info->c1);
context->exponentC2 = RC_CHARGE_EXP(context->rTotal * info->c2);
break;
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON:
context->rTotal = 1.0 / (1.0 / info->r1 + 1.0 / info->r2);
case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M:
{
double fc = 1.0 / (2 * M_PI * sqrt(context->rTotal * info->rF * info->c1 * info->c2));
double d = (info->c1 + info->c2) / sqrt(info->rF / context->rTotal * info->c1 * info->c2);
double gain = -info->rF / context->rTotal * info->c2 / (info->c1 + info->c2);
calculate_filter2_coefficients(fc, d, DISC_FILTER_BANDPASS,
&context->a1, &context->a2,
&context->b0, &context->b1, &context->b2);
context->b0 *= gain;
context->b1 *= gain;
context->b2 *= gain;
if (context->is_norton)
context->vRef = (info->vP - OP_AMP_NORTON_VBE) / info->r3 * info->rF;
else
context->vRef = info->vRef;
break;
}
case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON:
context->exponentC1 = RC_CHARGE_EXP(RES_2_PARALLEL(info->r1, info->r2 + info->r3 + info->r4) * info->c1);
context->exponentC2 = RC_CHARGE_EXP(RES_2_PARALLEL(info->r1 + info->r2, info->r3 + info->r4) * info->c2);
context->exponentC3 = RC_CHARGE_EXP((info->r1 + info->r2 + info->r3 + info->r4) * info->c3);
break;
case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON:
context->exponentC1 = RC_CHARGE_EXP(info->r1 * info->c1);
break;
}
/* At startup there is no charge on the caps and output is 0V in relation to vRef. */
context->vC1 = 0;
context->vC1b = 0;
context->vC2 = 0;
context->vC3 = 0;
node->output[0] = info->vRef;
}
/************************************************************************
*
* DST_RCDISC - Usage of node_description values for RC discharge
* (inverse slope of DST_RCFILTER)
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISC__ENABLE (*(node->input[0]))
#define DST_RCDISC__IN (*(node->input[1]))
#define DST_RCDISC__R (*(node->input[2]))
#define DST_RCDISC__C (*(node->input[3]))
static DISCRETE_STEP(dst_rcdisc)
{
struct dst_rcdisc_context *context = node->context;
switch (context->state)
{
case 0: /* waiting for trigger */
if(DST_RCDISC__ENABLE)
{
context->state = 1;
context->t = 0;
}
node->output[0] = 0;
break;
case 1:
if (DST_RCDISC__ENABLE)
{
node->output[0] = DST_RCDISC__IN * exp(context->t / context->exponent0);
context->t += discrete_current_context->sample_time;
} else
{
context->state = 0;
}
}
}
static DISCRETE_RESET(dst_rcdisc)
{
struct dst_rcdisc_context *context = node->context;
node->output[0] = 0;
context->state = 0;
context->t = 0;
context->exponent0=-1.0 * DST_RCDISC__R * DST_RCDISC__C;
}
/************************************************************************
*
* DST_RCDISC2 - Usage of node_description values for RC discharge
* Has switchable charge resistor/input
*
* input[0] - Switch input value
* input[1] - input[0] value
* input[2] - Resistor0 value (initialization only)
* input[3] - input[1] value
* input[4] - Resistor1 value (initialization only)
* input[5] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISC2__ENABLE (*(node->input[0]))
#define DST_RCDISC2__IN0 (*(node->input[1]))
#define DST_RCDISC2__R0 (*(node->input[2]))
#define DST_RCDISC2__IN1 (*(node->input[3]))
#define DST_RCDISC2__R1 (*(node->input[4]))
#define DST_RCDISC2__C (*(node->input[5]))
static DISCRETE_STEP(dst_rcdisc2)
{
struct dst_rcdisc_context *context = node->context;
double diff;
/* Works differently to other as we are always on, no enable */
/* exponential based in difference between input/output */
diff = ((DST_RCDISC2__ENABLE == 0) ? DST_RCDISC2__IN0 : DST_RCDISC2__IN1) - node->output[0];
diff = diff - (diff * ((DST_RCDISC2__ENABLE == 0) ? context->exponent0 : context->exponent1));
node->output[0] += diff;
}
static DISCRETE_RESET(dst_rcdisc2)
{
struct dst_rcdisc_context *context = node->context;
node->output[0] = 0;
context->state = 0;
context->t = 0;
context->exponent0 = RC_DISCHARGE_EXP(DST_RCDISC2__R0 * DST_RCDISC2__C);
context->exponent1 = RC_DISCHARGE_EXP(DST_RCDISC2__R1 * DST_RCDISC2__C);
}
/************************************************************************
*
* DST_RCDISC3 - Usage of node_description values for RC discharge
*
*
* input[0] - Enable
* input[1] - input value
* input[2] - Resistor0 value (initialization only)
* input[4] - Resistor1 value (initialization only)
* input[5] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISC3__ENABLE (*(node->input[0]))
#define DST_RCDISC3__IN (*(node->input[1]))
#define DST_RCDISC3__R1 (*(node->input[2]))
#define DST_RCDISC3__R2 (*(node->input[3]))
#define DST_RCDISC3__C (*(node->input[4]))
static DISCRETE_STEP(dst_rcdisc3)
{
struct dst_rcdisc_context *context = node->context;
double diff;
/* Exponential based in difference between input/output */
if(DST_RCDISC3__ENABLE)
{
diff = DST_RCDISC3__IN - node->output[0];
if( diff > 0 )
{
diff = diff - (diff * context->exponent0);
} else if( diff < 0)
{
if(diff < -0.5)
diff = diff - (diff * context->exponent1);
else
diff = diff - (diff * context->exponent0);
}
node->output[0] += diff;
}
else
{
node->output[0] = 0;
}
}
static DISCRETE_RESET(dst_rcdisc3)
{
struct dst_rcdisc_context *context = node->context;
node->output[0] = 0;
context->state = 0;
context->t = 0;
context->exponent0 = RC_CHARGE_EXP(DST_RCDISC3__R1 * DST_RCDISC3__C);
context->exponent1 = RC_CHARGE_EXP(RES_2_PARALLEL(DST_RCDISC3__R1, DST_RCDISC3__R2) * DST_RCDISC3__C);
}
/************************************************************************
*
* DST_RCDISC4 - Various charge/discharge circuits
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - R1 Resistor value (initialization only)
* input[2] - R2 Resistor value (initialization only)
* input[4] - C1 Capacitor Value (initialization only)
* input[4] - vP power source (initialization only)
* input[4] - circuit type (initialization only)
*
************************************************************************/
#define DST_RCDISC4__ENABLE (*(node->input[0]))
#define DST_RCDISC4__IN (*(node->input[1]))
#define DST_RCDISC4__R1 (*(node->input[2]))
#define DST_RCDISC4__R2 (*(node->input[3]))
#define DST_RCDISC4__R3 (*(node->input[4]))
#define DST_RCDISC4__C1 (*(node->input[5]))
#define DST_RCDISC4__VP (*(node->input[6]))
#define DST_RCDISC4__TYPE (*(node->input[7]))
static DISCRETE_STEP(dst_rcdisc4)
{
struct dst_rcdisc4_context *context = node->context;
int inp1 = (DST_RCDISC4__IN == 0) ? 0 : 1;
if (DST_RCDISC4__ENABLE == 0)
{
node->output[0] = 0;
return;
}
switch (context->type)
{
case 1:
case 3:
context->vC1 += ((context->v[inp1] - context->vC1) * context->exp[inp1]);
node->output[0] = context->vC1;
break;
}
/* clip output */
if (node->output[0] > context->max_out) node->output[0] = context->max_out;
if (node->output[0] < 0) node->output[0] = 0;
}
static DISCRETE_RESET( dst_rcdisc4)
{
struct dst_rcdisc4_context *context = node->context;
double v, i, r, rT;
context->type = 0;
/* some error checking. */
if (DST_RCDISC4__R1 <= 0 || DST_RCDISC4__R2 <= 0 || DST_RCDISC4__C1 <= 0 || (DST_RCDISC4__R3 <= 0 && context->type == 1))
{
discrete_log("Invalid component values in NODE_%d.\n", node->node - NODE_00);
return;
}
if (DST_RCDISC4__VP < 3)
{
discrete_log("vP must be >= 3V in NODE_%d.\n", node->node - NODE_00);
return;
}
if (DST_RCDISC4__TYPE < 1 || DST_RCDISC4__TYPE > 3)
{
discrete_log("Invalid circuit type in NODE_%d.\n", node->node - NODE_00);
return;
}
context->vC1 = 0;
/* store type as integer */
context->type = (int)DST_RCDISC4__TYPE;
/* setup the maximum op-amp output. */
context->max_out = DST_RCDISC4__VP - OP_AMP_VP_RAIL_OFFSET;
switch (context->type)
{
case 1:
/* We will simulate this as a voltage divider with 2 states depending
* on the input. But we have to take the diodes into account.
*/
v = DST_RCDISC4__VP - .5; /* diode drop */
/* When the input is 1, both R1 & R3 are basically in parallel. */
r = RES_2_PARALLEL(DST_RCDISC4__R1, DST_RCDISC4__R3);
rT = DST_RCDISC4__R2 + r;
i = v / rT;
context->v[1] = i * r + .5;
rT = RES_2_PARALLEL(DST_RCDISC4__R2, r);
context->exp[1] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1);
/* When the input is 0, R1 is out of circuit. */
rT = DST_RCDISC4__R2 + DST_RCDISC4__R3;
i = v / rT;
context->v[0] = i * DST_RCDISC4__R3 + .5;
rT = RES_2_PARALLEL(DST_RCDISC4__R2, DST_RCDISC4__R3);
context->exp[0] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1);
break;
case 3:
/* We will simulate this as a voltage divider with 2 states depending
* on the input. The 1k pullup is in parallel with the internal TTL
* resistance, so we will just use .5k in series with R1.
*/
r = 500.0 + DST_RCDISC4__R1;
context->v[1] = RES_VOLTAGE_DIVIDER(r, DST_RCDISC4__R2) * (5.0 - 0.5);
rT = RES_2_PARALLEL(r, DST_RCDISC4__R2);
context->exp[1] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1);
/* When the input is 0, R1 is out of circuit. */
context->v[0] = 0;
context->exp[0] = RC_CHARGE_EXP(DST_RCDISC4__R2 * DST_RCDISC4__C1);
break;
}
}
/************************************************************************
*
* DST_RCDISC5 - Diode in series with R//C
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISC5__ENABLE (*(node->input[0]))
#define DST_RCDISC5__IN (*(node->input[1]))
#define DST_RCDISC5__R (*(node->input[2]))
#define DST_RCDISC5__C (*(node->input[3]))
static DISCRETE_STEP( dst_rcdisc5)
{
struct dst_rcdisc_context *context = node->context;
double diff,u;
/* Exponential based in difference between input/output */
if(DST_RCDISC5__ENABLE)
{
u = DST_RCDISC5__IN - 0.7; /* Diode drop */
if( u < 0)
u = 0;
diff = u - node->output[0];
if(diff < 0)
//diff = diff - (diff * exp(discrete_current_context->sample_time / context->exponent0));
diff = -node->output[0] + (node->output[0] * context->exponent0);
node->output[0] += diff;
}
else
{
node->output[0] = 0;
}
}
static DISCRETE_RESET( dst_rcdisc5)
{
struct dst_rcdisc_context *context = node->context;
node->output[0] = 0;
context->state = 0;
context->t = 0;
context->exponent0 = RC_CHARGE_EXP(DST_RCDISC5__R * DST_RCDISC5__C);
}
/************************************************************************
*
* DST_RCDISC_MOD - RC triggered by logic and modulated
*
* input[0] - Enable input value
* input[1] - input value 1
* input[2] - input value 2
* input[3] - Resistor 1 value (initialization only)
* input[4] - Resistor 2 value (initialization only)
* input[5] - Resistor 3 value (initialization only)
* input[6] - Resistor 4 value (initialization only)
* input[7] - Capacitor Value (initialization only)
* input[8] - Voltage Value (initialization only)
*
************************************************************************/
#define DST_RCDISC_MOD__IN1 (*(node->input[0]))
#define DST_RCDISC_MOD__IN2 (*(node->input[1]))
#define DST_RCDISC_MOD__R1 (*(node->input[2]))
#define DST_RCDISC_MOD__R2 (*(node->input[3]))
#define DST_RCDISC_MOD__R3 (*(node->input[4]))
#define DST_RCDISC_MOD__R4 (*(node->input[5]))
#define DST_RCDISC_MOD__C (*(node->input[6]))
#define DST_RCDISC_MOD__VP (*(node->input[7]))
static DISCRETE_STEP(dst_rcdisc_mod)
{
struct dst_rcdisc_mod_context *context = node->context;
double diff, v_cap, u, vD;
int mod_state, mod1_state, mod2_state;
/* Exponential based in difference between input/output */
v_cap = context->v_cap;
mod1_state = DST_RCDISC_MOD__IN1 > 0.5;
mod2_state = DST_RCDISC_MOD__IN2 > 0.6;
mod_state = (mod2_state << 1) + mod1_state;
u = mod1_state ? 0 : DST_RCDISC_MOD__VP;
/* Clamp */
diff = u - v_cap;
vD = diff * context->vd_gain[mod_state];
if (vD < -0.6)
{
diff = u + 0.6 - v_cap;
diff -= diff * context->exp_low[mod1_state];
v_cap += diff;
node->output[0] = mod2_state ? 0 : -0.6;
}
else
{
diff -= diff * context->exp_high[mod_state];
v_cap += diff;
/* neglecting current through R3 drawn by next8 node */
node->output[0] = mod2_state ? 0: (u - v_cap) * context->gain[mod1_state];
}
context->v_cap = v_cap;
}
static DISCRETE_RESET(dst_rcdisc_mod)
{
struct dst_rcdisc_mod_context *context = node->context;
double rc[2], rc2[2];
/* pre-calculate fixed values */
/* DST_RCDISC_MOD__IN1 <= 0.5 */
rc[0] = DST_RCDISC_MOD__R1 + DST_RCDISC_MOD__R2;
if (rc[0] < 1) rc[0] = 1;
context->exp_low[0] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * rc[0]);
context->gain[0] = RES_VOLTAGE_DIVIDER(rc[0], DST_RCDISC_MOD__R4);
/* DST_RCDISC_MOD__IN1 > 0.5 */
rc[1] = DST_RCDISC_MOD__R2;
if (rc[1] < 1) rc[1] = 1;
context->exp_low[1] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * rc[1]);
context->gain[1] = RES_VOLTAGE_DIVIDER(rc[1], DST_RCDISC_MOD__R4);
/* DST_RCDISC_MOD__IN2 <= 0.6 */
rc2[0] = DST_RCDISC_MOD__R4;
/* DST_RCDISC_MOD__IN2 > 0.6 */
rc2[1] = RES_2_PARALLEL(DST_RCDISC_MOD__R3, DST_RCDISC_MOD__R4);
/* DST_RCDISC_MOD__IN1 <= 0.5 && DST_RCDISC_MOD__IN2 <= 0.6 */
context->exp_high[0] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[0] + rc2[0]));
context->vd_gain[0] = RES_VOLTAGE_DIVIDER(rc[0], rc2[0]);
/* DST_RCDISC_MOD__IN1 > 0.5 && DST_RCDISC_MOD__IN2 <= 0.6 */
context->exp_high[1] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[1] + rc2[0]));
context->vd_gain[1] = RES_VOLTAGE_DIVIDER(rc[1], rc2[0]);
/* DST_RCDISC_MOD__IN1 <= 0.5 && DST_RCDISC_MOD__IN2 > 0.6 */
context->exp_high[2] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[0] + rc2[1]));
context->vd_gain[2] = RES_VOLTAGE_DIVIDER(rc[0], rc2[1]);
/* DST_RCDISC_MOD__IN1 > 0.5 && DST_RCDISC_MOD__IN2 > 0.6 */
context->exp_high[3] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[1] + rc2[1]));
context->vd_gain[3] = RES_VOLTAGE_DIVIDER(rc[1], rc2[1]);
context->v_cap = 0;
node->output[0] = 0;
}
/************************************************************************
*
* DST_RCFILTER - Usage of node_description values for RC filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
* input[4] - Voltage reference. Usually 0V.
*
************************************************************************/
#define DST_RCFILTER__ENABLE (*(node->input[0]))
#define DST_RCFILTER__VIN (*(node->input[1]))
#define DST_RCFILTER__R (*(node->input[2]))
#define DST_RCFILTER__C (*(node->input[3]))
#define DST_RCFILTER__VREF (*(node->input[4]))
static DISCRETE_STEP(dst_rcfilter)
{
struct dst_rcfilter_context *context = node->context;
/************************************************************************/
/* Next Value = PREV + (INPUT_VALUE - PREV)*(1-(EXP(-TIMEDELTA/RC))) */
/************************************************************************/
if(DST_RCFILTER__ENABLE)
{
context->vCap += ((DST_RCFILTER__VIN - DST_RCFILTER__VREF - context->vCap) * context->exponent);
node->output[0] = context->vCap + DST_RCFILTER__VREF;
}
else
{
node->output[0] = 0;
}
}
static DISCRETE_RESET(dst_rcfilter)
{
struct dst_rcfilter_context *context = node->context;
context->exponent = RC_CHARGE_EXP(DST_RCFILTER__R * DST_RCFILTER__C);
context->vCap = 0;
node->output[0] = 0;
}
/************************************************************************
*
* DST_RCFILTER_SW - Usage of node_description values for switchable RC filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
* input[4] - Voltage reference. Usually 0V.
*
************************************************************************/
#define DST_RCFILTER_SW__ENABLE (*(node->input[0]))
#define DST_RCFILTER_SW__VIN (*(node->input[1]))
#define DST_RCFILTER_SW__SWITCH (*(node->input[2]))
#define DST_RCFILTER_SW__R (*(node->input[3]))
#define DST_RCFILTER_SW__C(x) (*(node->input[4+x]))
#define CD4066_ON_RES 270
#define DST_RCFILTER_SW_ITERATIONS (10)
// FIXME: This needs optimization !
static DISCRETE_STEP(dst_rcfilter_sw)
{
struct dst_rcfilter_sw_context *context = node->context;
int i,j ;
int bits = (int)DST_RCFILTER_SW__SWITCH;
double us = 0, rs = 0;
if (DST_RCFILTER_SW__ENABLE)
{
switch (bits)
{
case 0:
node->output[0] = DST_RCFILTER_SW__VIN;
break;
case 1:
context->vCap[0] += (DST_RCFILTER_SW__VIN - context->vCap[0]) * context->exp0;
node->output[0] = context->vCap[0] + (DST_RCFILTER_SW__VIN - context->vCap[0]) * context->factor;
break;
case 2:
context->vCap[1] += (DST_RCFILTER_SW__VIN - context->vCap[1]) * context->exp1;
node->output[0] = context->vCap[1] + (DST_RCFILTER_SW__VIN - context->vCap[1]) * context->factor;
break;
default:
for (j = 0; j < DST_RCFILTER_SW_ITERATIONS; j++)
{
for (i = 0; i < 4; i++)
{
if (( bits & (1 << i)) != 0)
{
us += context->vCap[i];
rs += DST_RCFILTER_SW__R;
}
}
node->output[0] = RES_VOLTAGE_DIVIDER(rs, CD4066_ON_RES) * DST_RCFILTER_SW__VIN + DST_RCFILTER_SW__R / (CD4066_ON_RES + rs) * us;
for (i = 0; i < 4; i++)
{
if (( bits & (1 << i)) != 0)
{
context->vCap[i] += (node->output[0] - context->vCap[i]) * context->exp[i];
}
}
}
}
}
else
{
node->output[0] = 0;
}
}
static DISCRETE_RESET(dst_rcfilter_sw)
{
struct dst_rcfilter_sw_context *context = node->context;
int i;
for (i = 0; i < 4; i++)
{
context->vCap[i] = 0;
context->exp[i] = RC_CHARGE_EXP(((double) DST_RCFILTER_SW_ITERATIONS) * CD4066_ON_RES * DST_RCFILTER_SW__C(i));
}
/* fast cases */
context->exp0 = RC_CHARGE_EXP((CD4066_ON_RES + DST_RCFILTER_SW__R) * DST_RCFILTER_SW__C(0));
context->exp1 = RC_CHARGE_EXP((CD4066_ON_RES + DST_RCFILTER_SW__R) * DST_RCFILTER_SW__C(1));
context->factor = RES_VOLTAGE_DIVIDER(DST_RCFILTER_SW__R, CD4066_ON_RES);
node->output[0] = 0;
}
/************************************************************************
*
* DST_RCINTEGRATE - Two diode inputs, transistor and a R/C charge
* discharge network
*
* input[0] - Enable input value
* input[1] - input value 1
* input[2] - input value 2
* input[3] - Resistor 1 value (initialization only)
* input[4] - Resistor 2 value (initialization only)
* input[5] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCINTEGRATE__IN1 (*(node->input[0]))
#define DST_RCINTEGRATE__R1 (*(node->input[1]))
#define DST_RCINTEGRATE__R2 (*(node->input[2]))
#define DST_RCINTEGRATE__R3 (*(node->input[3]))
#define DST_RCINTEGRATE__C (*(node->input[4]))
#define DST_RCINTEGRATE__VP (*(node->input[5]))
#define DST_RCINTEGRATE__TYPE (*(node->input[6]))
/* Ebers-Moll large signal model
* Couriersud:
* The implementation avoids all iterative approaches in order not to burn cycles
* We will calculate Ic from vBE and use this as an indication where to go.
* The implementation may oscillate if you change the weighting factors at the
* end.
*
* This implementation is not perfect, but does it's job in dkong'
*/
/* reverse saturation current */
#define IES 7e-15
#define ALPHAT 0.99
#define KT 0.026
#define EM_IC(x) (ALPHAT * IES * exp( (x) / KT - 1.0 ))
static DISCRETE_STEP( dst_rcintegrate)
{
struct dst_rcintegrate_context *context = node->context;
double diff, u, iQ, iQc, iC, RG, vE;
double vP;
u = DST_RCINTEGRATE__IN1;
vP = DST_RCINTEGRATE__VP;
if ( u - 0.7 < context->vCap * context->gain_r1_r2)
{
/* discharge .... */
diff = 0.0 - context->vCap;
iC = context->c_exp1 * diff; /* iC */
diff -= diff * context->exp_exponent1;
context->vCap += diff;
iQ = 0;
vE = context->vCap * context->gain_r1_r2;
RG = vE / iC;
}
else
{
/* charging */
diff = (vP - context->vCE) * context->f - context->vCap;
iC = 0.0 - context->c_exp0 * diff; /* iC */
diff -= diff * context->exp_exponent0;
context->vCap += diff;
iQ = iC + (iC * DST_RCINTEGRATE__R1 + context->vCap) / DST_RCINTEGRATE__R2;
RG = (vP - context->vCE) / iQ;
vE = (RG - DST_RCINTEGRATE__R3) / RG * (vP - context->vCE);
}
u = DST_RCINTEGRATE__IN1;
if (u > 0.7 + vE)
vE = u - 0.7;
iQc = EM_IC(u - vE);
context->vCE = MIN(vP - 0.1, vP - RG * iQc);
/* Avoid oscillations
* The method tends to largely overshoot - no wonder without
* iterative solution approximation
*/
context->vCE = MAX(context->vCE, 0.1 );
context->vCE = 0.1 * context->vCE + 0.9 * (vP - vE - iQ * DST_RCINTEGRATE__R3);
switch (context->type)
{
case DISC_RC_INTEGRATE_TYPE1:
node->output[0] = context->vCap;
break;
case DISC_RC_INTEGRATE_TYPE2:
node->output[0] = vE;
break;
case DISC_RC_INTEGRATE_TYPE3:
node->output[0] = MAX(0, vP - iQ * DST_RCINTEGRATE__R3);
break;
}
}
static DISCRETE_RESET(dst_rcintegrate)
{
struct dst_rcintegrate_context *context = node->context;
double r;
double dt = discrete_current_context->sample_time;
context->type = DST_RCINTEGRATE__TYPE;
context->vCap = 0;
context->vCE = 0;
/* pre-calculate fixed values */
context->gain_r1_r2 = RES_VOLTAGE_DIVIDER(DST_RCINTEGRATE__R1, DST_RCINTEGRATE__R2);
r = DST_RCINTEGRATE__R1 / DST_RCINTEGRATE__R2 * DST_RCINTEGRATE__R3 + DST_RCINTEGRATE__R1 + DST_RCINTEGRATE__R3;
context->f = RES_VOLTAGE_DIVIDER(DST_RCINTEGRATE__R3, DST_RCINTEGRATE__R2);
context->exponent0 = -1.0 * r * context->f * DST_RCINTEGRATE__C;
context->exponent1 = -1.0 * (DST_RCINTEGRATE__R1 + DST_RCINTEGRATE__R2) * DST_RCINTEGRATE__C;
context->exp_exponent0 = exp(dt / context->exponent0);
context->exp_exponent1 = exp(dt / context->exponent1);
context->c_exp0 = DST_RCINTEGRATE__C / context->exponent0 * context->exp_exponent0;
context->c_exp1 = DST_RCINTEGRATE__C / context->exponent1 * context->exp_exponent1;
node->output[0] = 0;
}
/************************************************************************
*
* DST_SALLEN_KEY - Sallen-Key filter circuit
*
* input[0] - Enable input value
* input[1] - IN0 node
* input[3] - Filter Type
*
* also passed discrete_op_amp_filt_info structure
*
* 2008, couriersud
************************************************************************/
#define DST_SALLEN_KEY__ENABLE (*(node->input[0]))
#define DST_SALLEN_KEY__INP0 (*(node->input[1]))
#define DST_SALLEN_KEY__TYPE (*(node->input[2]))
static DISCRETE_STEP(dst_sallen_key)
{
struct dss_filter2_context *context = node->context;
double gain = 1.0;
if (DST_SALLEN_KEY__ENABLE == 0.0)
{
gain = 0.0;
}
node->output[0] = -context->a1 * context->y1 - context->a2 * context->y2 +
context->b0 * gain * DST_SALLEN_KEY__INP0 + context->b1 * context->x1 + context->b2 * context->x2;
context->x2 = context->x1;
context->x1 = gain * DST_SALLEN_KEY__INP0;
context->y2 = context->y1;
context->y1 = node->output[0];
}
static DISCRETE_RESET(dst_sallen_key)
{
struct dss_filter2_context *context = node->context;
const discrete_op_amp_filt_info *info = node->custom;
double freq, q;
switch ((int) DST_SALLEN_KEY__TYPE)
{
case DISC_SALLEN_KEY_LOW_PASS:
freq = 1.0 / ( 2.0 * M_PI * sqrt(info->c1 * info->c2 * info->r1 * info->r2));
q = sqrt(info->c1 * info->c2 * info->r1 * info->r2) / (info->c2 * (info->r1 + info->r2));
break;
default:
fatalerror("Unknown sallen key filter type");
}
calculate_filter2_coefficients(freq, 1.0 / q, DISC_FILTER_LOWPASS,
&context->a1, &context->a2,
&context->b0, &context->b1, &context->b2);
node->output[0] = 0;
}
/* !!!!!!!!!!! NEW FILTERS for testing !!!!!!!!!!!!!!!!!!!!! */
/************************************************************************
*
* DST_RCFILTERN - Usage of node_description values for RC filter
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCFILTERN__ENABLE (*(node->input[0]))
#define DST_RCFILTERN__IN (*(node->input[1]))
#define DST_RCFILTERN__R (*(node->input[2]))
#define DST_RCFILTERN__C (*(node->input[3]))
static DISCRETE_RESET(dst_rcfilterN)
{
#if 0
double f=1.0/(2*M_PI* DST_RCFILTERN__R * DST_RCFILTERN__C);
/* !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!! */
/* Put this stuff in a context */
node->input[2] = f;
node->input[3] = DISC_FILTER_LOWPASS;
/* Use first order filter */
dst_filter1_reset(node);
#endif
}
/************************************************************************
*
* DST_RCDISCN - Usage of node_description values for RC discharge
* (inverse slope of DST_RCFILTER)
*
* input[0] - Enable input value
* input[1] - input value
* input[2] - Resistor value (initialization only)
* input[3] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISCN__ENABLE (*(node->input[0]))
#define DST_RCDISCN__IN (*(node->input[1]))
#define DST_RCDISCN__R (*(node->input[2]))
#define DST_RCDISCN__C (*(node->input[3]))
static DISCRETE_RESET(dst_rcdiscN)
{
#if 0
double f = 1.0 / (2 * M_PI * DST_RCDISCN__R * DST_RCDISCN__C);
/* !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!! */
/* Put this stuff in a context */
node->input[2] = f;
node->input[3] = DISC_FILTER_LOWPASS;
/* Use first order filter */
dst_filter1_reset(node);
#endif
}
static DISCRETE_STEP(dst_rcdiscN)
{
struct dss_filter1_context *context = node->context;
double gain = 1.0;
if (DST_RCDISCN__ENABLE == 0.0)
{
gain = 0.0;
}
/* A rise in the input signal results in an instant charge, */
/* else discharge through the RC to zero */
if (gain* DST_RCDISCN__IN > context->x1)
node->output[0] = gain* DST_RCDISCN__IN;
else
node->output[0] = -context->a1*context->y1;
context->x1 = gain* DST_RCDISCN__IN;
context->y1 = node->output[0];
}
/************************************************************************
*
* DST_RCDISC2N - Usage of node_description values for RC discharge
* Has switchable charge resistor/input
*
* input[0] - Switch input value
* input[1] - input[0] value
* input[2] - Resistor0 value (initialization only)
* input[3] - input[1] value
* input[4] - Resistor1 value (initialization only)
* input[5] - Capacitor Value (initialization only)
*
************************************************************************/
#define DST_RCDISC2N__ENABLE (*(node->input[0]))
#define DST_RCDISC2N__IN0 (*(node->input[1]))
#define DST_RCDISC2N__R0 (*(node->input[2]))
#define DST_RCDISC2N__IN1 (*(node->input[3]))
#define DST_RCDISC2N__R1 (*(node->input[4]))
#define DST_RCDISC2N__C (*(node->input[5]))
struct dss_rcdisc2_context
{
double x1; /* x[k-1], last input value */
double y1; /* y[k-1], last output value */
double a1_0, b0_0, b1_0; /* digital filter coefficients, filter #1 */
double a1_1, b0_1, b1_1; /* digital filter coefficients, filter #2 */
};
static DISCRETE_STEP(dst_rcdisc2N)
{
struct dss_rcdisc2_context *context = node->context;
double input = ((DST_RCDISC2N__ENABLE == 0) ? DST_RCDISC2N__IN0 : DST_RCDISC2N__IN1);
if (DST_RCDISC2N__ENABLE == 0)
node->output[0] = -context->a1_0*context->y1 + context->b0_0*input + context->b1_0*context->x1;
else
node->output[0] = -context->a1_1*context->y1 + context->b0_1*input + context->b1_1*context->x1;
context->x1 = input;
context->y1 = node->output[0];
}
static DISCRETE_RESET(dst_rcdisc2N)
{
struct dss_rcdisc2_context *context = node->context;
double f1,f2;
f1 = 1.0 / (2 * M_PI * DST_RCDISC2N__R0 * DST_RCDISC2N__C);
f2 = 1.0 / (2 * M_PI * DST_RCDISC2N__R1 * DST_RCDISC2N__C);
calculate_filter1_coefficients(f1, DISC_FILTER_LOWPASS, &context->a1_0, &context->b0_0, &context->b1_0);
calculate_filter1_coefficients(f2, DISC_FILTER_LOWPASS, &context->a1_1, &context->b0_1, &context->b1_1);
/* Initialize the object */
node->output[0] = 0;
}