void pre_emphasis(fract32 data[], int arr_length) { fract32 xBuffer[BUFFER_SIZE] = {0}; // input buffer fract32 yBuffer[BUFFER_SIZE] = {0}; // output buffer int current = 0; int index; for (index = 0; index < arr_length; index++) { fract32 temp_b0 = mult_fr1x32x32(shelving_coef.b0, data[index]); fract32 temp_b1 = mult_fr1x32x32(shelving_coef.b1, xBuffer[INDEX(current-1)]); fract32 temp_b2 = mult_fr1x32x32(shelving_coef.b2, xBuffer[INDEX(current-2)]); fract32 temp_a1 = mult_fr1x32x32(shelving_coef.a1, yBuffer[INDEX(current-1)]); fract32 temp_a2 = mult_fr1x32x32(shelving_coef.a2, yBuffer[INDEX(current-2)]); fract32 temp_b = add_fr1x32(add_fr1x32(temp_b0, temp_b1), temp_b2); fract32 temp_a = add_fr1x32(temp_a1, temp_a2); fract32 temp = sub_fr1x32(temp_b, temp_a); yBuffer[current] = shl_fr1x32(temp, 2); xBuffer[current] = data[index]; //input data[index] = yBuffer[current]; //output current++; current %= BUFFER_SIZE; } }
// interpolated arbitrary mix of old buffer contents with new void buffer_tap_mix(bufferTap *tap, fract32 val, fract32 preLevel) { static s32 idxB; static fract32 a, b; a = mult_fr1x32x32(val, sub_fr1x32(FR32_MAX, tap->idx.fr)); b = mult_fr1x32x32(val, tap->idx.fr); idxB = tap->idx.i + 1; while(idxB > tap->loop) { idxB -= tap->loop; } // we can assume idxA is already wrapped tap->buf->data[tap->idx.i] = add_fr1x32(a, mult_fr1x32x32(tap->buf->data[tap->idx.i], preLevel)); tap->buf->data[tap->idx.i] = add_fr1x32(b, mult_fr1x32x32(tap->buf->data[idxB], preLevel)); tap->buf->data[idxB] = b; }
// calculate modulated and bandlimited waveshape static inline void osc_calc_wm(osc* osc) { fract32 sm; // mod shape // fract32 sl; // shape limit given current freq // add modulation sm = add_fr1x32(osc->shape, mult_fr1x32x32(osc->wmIn, osc->wmAmt) ); //- hacky magic formula for pseudo-bandlimiting: //- with maximal bandlimiting, want to limit shape to a function of unit freq //- max freq = min shape, min freq = max shape // : // map phase increment to [0,1] fract32 /* sl = (fract32)(((u32)(osc->inc) - incRange) * shapeLimMul); */ /* // invert [0,1] to [1,0] */ /* sl = sub_fr1x32(FR32_MAX, sl); */ /* // limit */ /* if(sl < sm) { */ /* sm = dsp_lerp32(sm, sl, osc->bandLim); */ /* } */ // ok, time for serious bullshit! sm = sub_fr1x32(sm, mult_fr1x32x32( (fract32)(fix16_sub(osc->inc, incMin) * shapeLimMul), osc->bandLim ) ); if(sm < 0) { sm = 0; } osc->shapeMod = sm; }
// get next filtered value fract32 filter_ramp_tog_next(filter_ramp_tog* f) { // gcc intrinsics are saturating f->y = add_fr1x32(f->y, f->sinc); if(f->y < 0) { f->y = 0; } /// fixme: slow f->sync = (f->x == f->y); f->sinc = f->sync ? 0 : f->sinc; return f->y; }
void module_process_frame(void) { static fract32 tmpDel, tmpSvf; u8 i; tmpDel = 0; tmpSvf = 0; // mix inputs to delay lines mix_del_inputs(); /// TEST for(i=0; i<NLINES; i++) { // process fade integrator // lines[i].fadeWr = filter_ramp_tog_next(&(lpFadeWr[i])); lines[i].fadeRd = filter_ramp_tog_next(&(lpFadeRd[i])); // process delay line tmpDel = delayFadeN_next( &(lines[i]), in_del[i]); // process filters // check integrators for filter params if( !(svfCutSlew[i].sync) ) { filter_svf_set_coeff( &(svf[i]), filter_1p_lo_next(&(svfCutSlew[i])) ); } if( !(svfRqSlew[i].sync) ) { filter_svf_set_rq( &(svf[i]), filter_1p_lo_next(&(svfRqSlew[i])) ); } tmpSvf = filter_svf_next( &(svf[i]), tmpDel); // mix tmpDel = mult_fr1x32x32( tmpDel, mix_fdry[i] ); tmpDel = add_fr1x32(tmpDel, mult_fr1x32x32(tmpSvf, mix_fwet[i]) ); out_del[i] = tmpDel; } // end lines loop // mix outputs to DACs /// TEST /* out[0] = in[0]; */ /* out[1] = in[1]; */ /* out[2] = in[2]; */ /* out[3] = in[3]; */ out[0] = out[1] = out[2] = out[3] = 0x00000000; mix_outputs(); /// do CV output if( cvSlew[cvChan].sync ) { ;; } else { cvVal[cvChan] = filter_1p_lo_next(&(cvSlew[cvChan])); dac_update(cvChan, cvVal[cvChan]); } if(++cvChan == 4) { cvChan = 0; } }
// interpolated read fract32 buffer_tap_read(bufferTap *tap) { static s32 idxB; static fract32 a, b; idxB = tap->idx.i + 1; while(idxB >= tap->loop) { idxB -= tap->loop; } // we can assume idxA is already wrapped a = tap->buf->data[tap->idx.i]; b = tap->buf->data[idxB]; // apply interpolation from fractional index return add_fr1x32(a, mult_fr1x32x32(tap->idx.fr, sub_fr1x32(b, a))); }
static fract32 filter_svf_calc_frame( filter_svf* f, fract32 in) { // fract32 out; f->low = add_fr1x32(f->low, mult_fr1x32x32(f->freq, f->band)); f->high = sub_fr1x32( sub_fr1x32( in, shl_fr1x32(mult_fr1x32x32(f->rq, f->band), f->rqShift) ), f->low ); f->band = add_fr1x32(f->band, mult_fr1x32x32(f->freq, f->high) ); // f->notch = add_fr1x32(f->low, f->high); // return out; return *(f->mode); }
// add 32.32 value with overflow/underflow checking void add_fix32(fix32* a, fix32* b) { // tmp fract fract32 tfr = a->fr; // tmp int s32 ti = a->i + b->i; /// FIXME: could be arch-specific inline ASM here for better speed /// (e.g. add fract32, check overflow flag ?) if(tfr >= 0) { if( sub_fr1x32(FRACT32_MAX,tfr) < b->fr) { // wrap by subtraction tfr = sub_fr1x32( add_fr1x32( sub_fr1x32(tfr, FR32_MAX), b->fr), FR32_MAX); ti += 1; // carry } } else { if(b->fr < sub_fr1x32(FRACT32_MAX,tfr)) { // wrap by addition tfr = add_fr1x32( add_fr1x32( add_fr1x32(tfr, FR32_MAX), b->fr), FR32_MAX); ti -= 1; // carry (negative) } } // yet another comparison and carry for negative fr if(tfr < 0) { a->fr = add_fr1x32(FR32_MAX, tfr); a->i = ti -1; } else { a->fr = tfr; a->i = ti; } }
static inline void mix_adc (void) { /// can't handle the mix! use pointers for patch points right now int i, j; volatile fract32** pout = &(patch_adc_dac[0][0]); fract32* pin = in; for(i=0; i < 4; i++) { for(j=0; j < 4; j++) { **pout = add_fr1x32(**pout, *pin); pout++; } pin++; } }
// get next filtered value fract32 filter_ramp_next(filter_ramp* f) { /// FIXME: conditionals suck if( !(f->sync) ) { f->y = add_fr1x32(f->x, f->sinc); if( f->dec ) { if (f->y < f->x) { f->y = f->x; } } else { if (f->y > f->x) { f->y = f->x; } } } return f->y; }
float calc_energy(fract32 data[], int arr_length) { int shift = 9; // shift = log_2(arr_length) fract32 energy_fr = float_to_fr32(0.0); int index; for (index = 0; index < arr_length; index++) { fract32 temp = mult_fr1x32x32(data[index], data[index]); temp = shl_fr1x32(temp, -shift); // right shift in case of overflow energy_fr = add_fr1x32(energy_fr, temp); } float energy = fr32_to_float(energy_fr) * (1<<shift); return energy; }
// read fract32 buffer_tapN_read(bufferTapN *tap) { fract32 a, b; fix16 tmp; #if 1 if(tap->divCount == 0) { return tap->buf->data[tap->idx]; } else { // interpolate during phase-division a = tap->buf->data[tap->idx]; if( (tap->idx + 1) >= tap->loop) { b = tap->buf->data[0]; } else { b = tap->buf->data[ tap->idx + 1 ]; } tmp = FRACT_FIX16( sub_fr1x32(b, a) ); tmp = fix16_mul(tmp, fix16_from_int(tap->divCount)); return add_fr1x32(a, FIX16_FRACT_TRUNC(tmp)); } #else return tap->buf->data[tap->idx]; #endif }
// frame calculation static void calc_frame(void) { #if 1 u8 i; wavesVoice* v; for(i=0; i<WAVES_NVOICES; i++) { v = &(voice[i]); // oscillator class includes hz and mod integrators v->oscOut = shr_fr1x32( osc_next( &(v->osc) ), 2); // phase mod with fixed 1-frame delay osc_pm_in( &(v->osc), v->pmIn ); // shape mod with fixed 1-frame delay osc_wm_in( &(v->osc), v->wmIn ); // process filter integrators and set filter_svf_set_coeff( &(v->svf), filter_1p_lo_next( &(v->cutSlew) ) ); filter_svf_set_rq( &(v->svf), filter_1p_lo_next( &(v->rqSlew) ) ); // process filter v->svfOut = filter_svf_next( &(v->svf), shr_fr1x32(v->oscOut, 1) ); // process amp smoother v->amp = filter_1p_lo_next( &(v->ampSlew) ); // mix to output bus v->out = mult_fr1x32x32(v->amp, add_fr1x32(mult_fr1x32x32( v->oscOut, v->fDry), mult_fr1x32x32( v->svfOut, v->fWet) ) ); } // end voice loop /// FIXME: later, more voices, mod matrix, arbitrary mod delay. /// for now, simple direct mod feedback routing and 1-frame delay. voice[0].pmIn = voice[1].oscOut; // voice[0].wmIn = voice[1].oscOut << 1; voice[1].pmIn = voice[0].oscOut; // voice[1].wmIn = voice[0].oscOut << 1; // mix outputs using matrix mix_outputs(); #else /* // fract32 out1, out0; */ /* // osc output */ /* oscOut1 = shr_fr1x32(osc_next( &(osc1) ), 2); */ /* oscOut0 = shr_fr1x32(osc_next( &(osc0) ), 2); */ /* // phase mod feedback with 1frame delay */ /* osc_pm_in( &osc1, oscOut0 ); */ /* osc_pm_in( &osc0, oscOut1 ); */ /* // shape mod feedback with 1frame delay */ /* osc_wm_in( &osc1, oscOut0 ); */ /* osc_wm_in( &osc0, oscOut1 ); */ /* /////////// */ /* /////////// */ /* // apply filters */ /* if( !(svfCutSlew[i].sync) ) { */ /* filter_svf_set_coeff( &(svf[i]), filter_1p_lo_next(&(svfCutSlew[i])) ); */ /* } */ /* if( !(svfRqSlew[i].sync) ) { */ /* filter_svf_set_rq( &(svf[i]), filter_1p_lo_next(&(svfRqSlew[i])) ); */ /* } */ /* // svfOut1 = shl_fr1x32(filter_svf_next( &(svf1), shr_fr1x32(oscOut1, 1)), 1); */ /* // svfOut2 = shl_fr1x32(filter_svf_next( &(svf2), shr_fr1x32(oscOut2, 1)), 1); */ /* svfOut1 = filter_svf_next( &(svf1), shr_fr1x32(oscOut1, 1)); */ /* svfOut0 = filter_svf_next( &(svf0), shr_fr1x32(oscOut0, 1)); */ /* ///////// */ /* ///////// */ /* // amp smoothers */ /* oscAmp1 = filter_1p_lo_next(amp1Lp); */ /* oscAmp0 = filter_1p_lo_next(amp0Lp); */ /* // apply osc amplitudes and sum */ /* oscOut1 = mult_fr1x32x32(oscAmp1, */ /* add_fr1x32(mult_fr1x32x32( oscOut1, fdry1), */ /* mult_fr1x32x32( svfOut1, fwet1) */ /* )); */ /* oscOut0 = mult_fr1x32x32(oscAmp0, */ /* add_fr1x32(mult_fr1x32x32( oscOut0, fdry0), */ /* mult_fr1x32x32( svfOut0, fwet0) */ /* )); */ /* //// */ /* /// fixme: mono */ /* frameVal = add_fr1x32( oscOut0, oscOut1); */ /* // mix to output */ /* //...todo */ #endif }
static void mix_outputs(void) { fract32 mul; //fract32 oscs; //-- out 0 out[0] = 0; // osc mul = mix_osc_dac[0][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(voice[0].out, mul)); mul = mix_osc_dac[1][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(voice[1].out, mul)); // adc mul = mix_adc_dac[0][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[3], mul)); //-- out 1 out[1] = 0; // osc mul = mix_osc_dac[0][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(voice[0].out, mul)); mul = mix_osc_dac[1][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(voice[1].out, mul)); // adc mul = mix_adc_dac[0][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[3], mul)); ////////////////// /// TEST: skip outs 3+4, see where we run out of CPU... out[2] = out[0]; out[3] = out[1]; return; ///////////// //////////// //-- out 2 out[2] = 0; // osc mul = mix_osc_dac[0][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(voice[0].out, mul)); mul = mix_osc_dac[1][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(voice[1].out, mul)); // adc mul = mix_adc_dac[0][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[3], mul)); //-- out 3 out[3] = 0; // osc mul = mix_osc_dac[0][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(voice[0].out, mul)); mul = mix_osc_dac[1][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(voice[1].out, mul)); // adc mul = mix_adc_dac[0][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[3], mul)); }
// mix delay inputs static void mix_del_inputs(void) { // u8 i, j; // fract32* pIn; fract32 mul; //--- del 0 in_del[0] = 0; //adc->del mul = mix_adc_del[0][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(in[0], mul)); mul = mix_adc_del[1][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(in[1], mul)); mul = mix_adc_del[2][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(in[2], mul)); mul = mix_adc_del[3][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(in[3], mul)); // del->del mul = mix_del_del[0][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_del[1][0]; in_del[0] = add_fr1x32(in_del[0], mult_fr1x32x32(out_del[1], mul)); //--- del 1 in_del[1] = 0; // adc mul = mix_adc_del[0][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(in[0], mul)); mul = mix_adc_del[1][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(in[1], mul)); mul = mix_adc_del[2][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(in[2], mul)); mul = mix_adc_del[3][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(in[3], mul)); // del mul = mix_del_del[0][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_del[1][1]; in_del[1] = add_fr1x32(in_del[1], mult_fr1x32x32(out_del[1], mul)); }
static void mix_outputs(void) { fract32 mul; //-- out 0 out[0] = 0; // del mul = mix_del_dac[0][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_dac[1][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(out_del[1], mul)); // adc mul = mix_adc_dac[0][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][0]; out[0] = add_fr1x32(out[0], mult_fr1x32x32(in[3], mul)); //-- out 1 out[1] = 0; // del mul = mix_del_dac[0][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_dac[1][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(out_del[1], mul)); // adc mul = mix_adc_dac[0][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][1]; out[1] = add_fr1x32(out[1], mult_fr1x32x32(in[3], mul)); //-- out 2 out[2] = 0; // del mul = mix_del_dac[0][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_dac[1][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(out_del[1], mul)); // adc mul = mix_adc_dac[0][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][2]; out[2] = add_fr1x32(out[2], mult_fr1x32x32(in[3], mul)); //-- out 3 out[3] = 0; // del mul = mix_del_dac[0][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(out_del[0], mul)); mul = mix_del_dac[1][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(out_del[1], mul)); // adc mul = mix_adc_dac[0][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[0], mul)); mul = mix_adc_dac[1][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[1], mul)); mul = mix_adc_dac[2][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[2], mul)); mul = mix_adc_dac[3][3]; out[3] = add_fr1x32(out[3], mult_fr1x32x32(in[3], mul)); }
// interpolated addition of input to buffer contents void buffer_tapN_add(bufferTapN *tap, fract32 val) { tap->buf->data[tap->idx] = add_fr1x32( tap->buf->data[tap->idx], val ); }
// arbitrary mix of old buffer contents with new void buffer_tapN_mix(bufferTapN *tap, fract32 val, fract32 preLevel) { tap->buf->data[tap->idx] = add_fr1x32( mult_fr1x32x32(tap->buf->data[tap->idx], preLevel), val ); }
// get next value (with input) extern fract32 filter_svf_next( filter_svf* f, fract32 in) { // process 2x and average fract32 out = shr_fr1x32(filter_svf_calc_frame(f, in), 1); out = add_fr1x32(out, shr_fr1x32(filter_svf_calc_frame(f, in), 1)); return out; }
// frame calculation static void calc_frame(void) { int i; wavesVoice* v = voice; fract32* vout = voiceOut; for(i=0; i<WAVES_NVOICES; i++) { // v = &(voice[i]); // oscillator class includes hz and mod integrators v->oscOut = shr_fr1x32( osc_next( &(v->osc) ), 2); // /set modulation - FIXME this is redundant... osc_pm_in( &(v->osc), v->pmIn ); osc_wm_in( &(v->osc), v->wmIn ); // set filter params slew32_calc(v->cutSlew); slew32_calc(v->rqSlew); filter_svf_set_coeff( &(v->svf), v->cutSlew.y ); filter_svf_set_rq( &(v->svf), v->rqSlew.y ); // process filter v->svfOut = filter_svf_next( &(v->svf), shr_fr1x32(v->oscOut, 1) ); // process amp/mix smoothing slew32_calc(v->ampSlew); slew16_calc(v->drySlew); slew16_calc(v->wetSlew); // mix dry/filter and apply amp *vout = mult_fr1x32x32( v->ampSlew.y, add_fr1x32( mult_fr1x32( trunc_fr1x32(v->oscOut), v->drySlew.y ), mult_fr1x32( trunc_fr1x32(v->svfOut), v->wetSlew.y ) ) ); // advance phase del indices v->pmDelWrIdx = (v->pmDelWrIdx + 1) & WAVES_PM_DEL_SAMPS_1; v->pmDelRdIdx = (v->pmDelRdIdx + 1) & WAVES_PM_DEL_SAMPS_1; // set pm input from delay v->pmIn = v->pmDelBuf[v->pmDelRdIdx]; // no tricky modulation routing here! v->wmIn = v->pmDelBuf[v->pmDelRdIdx]; // advance pointers vout++; v++; } // end voice loop // // simple cross-patch modulation // add delay, before filter voice[0].pmDelBuf[voice[0].pmDelWrIdx] = voice[1].oscOut; voice[1].pmDelBuf[voice[1].pmDelWrIdx] = voice[0].oscOut; /* voice[0].pmIn = voice[1].oscOut; */ /* voice[1].pmIn = voice[0].oscOut; */ // zero the outputs out[0] = out[1] = out[2] = out[3] = 0; // patch filtered oscs outputs mix_voice(); // oatch adc mix_adc(); }
// frame calculation static void calc_frame(void) { // ----- smoothers: // amp amp = filter_1p_fix16_next(ampLp); // time if(timeLp->sync) { ;; } else { time = filter_1p_fix16_next(timeLp); buffer_tap_sync(&tapRd, &tapWr, time); #if ARCH_LINUX if(dbgFlag) { fprintf(dbgFile, "%d \t %f \r\n", dbgCount, fix16_to_float(time) ); dbgCount++; } #endif } // rate //// NOTE: setting a different rate is pretty much pointless in this simple application. /// leaving it in just to test fractional interpolation methods. if(rateLp->sync) { ;; } else { rate = filter_1p_fix16_next(rateLp); buffer_tap_set_rate(&tapRd, rate); buffer_tap_set_rate(&tapWr, rate); } // get interpolated echo value echoVal = buffer_tap_read(&tapRd); /* // store interpolated input+fb value */ // buffer_tap_write(&tapWr, add_fr1x32(in0, mult_fr1x32x32(echoVal, fb ) ) ); buffer_tap_write(&tapWr, add_fr1x32(in0 >> 1, mult_fr1x32x32(echoVal, fb ) ) ); //FIXME: clip / saturate input buf here //// potentially, scale input by inverse feedback /// test: no fb //buffer_tap_write(&tapWr, in0); /* // output */ frameVal = add_fr1x32( mult_fr1x32x32( echoVal, FIX16_FRACT_TRUNC(amp) ), mult_fr1x32x32( in0, FIX16_FRACT_TRUNC(dry) ) ); //// test: no dry // frameVal = echoVal; /// FIXME: clip here buffer_tap_next(&tapRd); buffer_tap_next(&tapWr); }