diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index ce2af1e..6605caa 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -83,7 +83,8 @@ const int16_t AudioWaveformSine[257] = { -4808, -4011, -3212, -2410, -1608, -804, 0 }; -AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) +AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) : + FXElement(samplerate) { input_attn = 0.5f; in_allp_k = INP_ALLP_COEFF; @@ -156,9 +157,33 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) reverb_level = 0.0f; } +AudioEffectPlateReverb::~AudioEffectPlateReverb() +{ +} + // #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift)) -void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len) +void AudioEffectPlateReverb::reset() +{ + memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); + memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); + memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); + memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); + memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); + memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); + memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); + memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); + memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); + memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); + memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); + memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); + memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); + memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); + memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); + memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); +} + +void AudioEffectPlateReverb::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { float32_t input, acc, temp1, temp2; uint16_t temp16; @@ -169,6 +194,259 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t int32_t y0, y1; int64_t y; uint32_t idx; + + rv_time = rv_time_k; + + // do the LFOs + lfo1_phase_acc += lfo1_adder; + idx = lfo1_phase_acc >> 24; // 8bit lookup table address + y0 = AudioWaveformSine[idx]; + y1 = AudioWaveformSine[idx+1]; + idx = lfo1_phase_acc & 0x00FFFFFF; // lower 24 bit = fractional part + y = (int64_t)y0 * (0x00FFFFFF - idx); + y += (int64_t)y1 * idx; + lfo1_out_sin = (int32_t) (y >> (32-8)); // 16bit output + idx = ((lfo1_phase_acc >> 24)+64) & 0xFF; + y0 = AudioWaveformSine[idx]; + y1 = AudioWaveformSine[idx + 1]; + y = (int64_t)y0 * (0x00FFFFFF - idx); + y += (int64_t)y1 * idx; + lfo1_out_cos = (int32_t) (y >> (32-8)); // 16bit output + + lfo2_phase_acc += lfo2_adder; + idx = lfo2_phase_acc >> 24; // 8bit lookup table address + y0 = AudioWaveformSine[idx]; + y1 = AudioWaveformSine[idx+1]; + idx = lfo2_phase_acc & 0x00FFFFFF; // lower 24 bit = fractional part + y = (int64_t)y0 * (0x00FFFFFF - idx); + y += (int64_t)y1 * idx; + lfo2_out_sin = (int32_t) (y >> (32-8)); //32-8->output 16bit, + idx = ((lfo2_phase_acc >> 24)+64) & 0xFF; + y0 = AudioWaveformSine[idx]; + y1 = AudioWaveformSine[idx + 1]; + y = (int64_t)y0 * (0x00FFFFFF - idx); + y += (int64_t)y1 * idx; + lfo2_out_cos = (int32_t) (y >> (32-8)); // 16bit output + + input = inL * input_attn; + + // chained input allpasses, channel L + acc = in_allp1_bufL[in_allp1_idxL] + input * in_allp_k; + in_allp1_bufL[in_allp1_idxL] = input - in_allp_k * acc; + input = acc; + if (++in_allp1_idxL >= sizeof(in_allp1_bufL)/sizeof(float32_t)) in_allp1_idxL = 0; + + acc = in_allp2_bufL[in_allp2_idxL] + input * in_allp_k; + in_allp2_bufL[in_allp2_idxL] = input - in_allp_k * acc; + input = acc; + if (++in_allp2_idxL >= sizeof(in_allp2_bufL)/sizeof(float32_t)) in_allp2_idxL = 0; + + acc = in_allp3_bufL[in_allp3_idxL] + input * in_allp_k; + in_allp3_bufL[in_allp3_idxL] = input - in_allp_k * acc; + input = acc; + if (++in_allp3_idxL >= sizeof(in_allp3_bufL)/sizeof(float32_t)) in_allp3_idxL = 0; + + acc = in_allp4_bufL[in_allp4_idxL] + input * in_allp_k; + in_allp4_bufL[in_allp4_idxL] = input - in_allp_k * acc; + in_allp_out_L = acc; + if (++in_allp4_idxL >= sizeof(in_allp4_bufL)/sizeof(float32_t)) in_allp4_idxL = 0; + + input = inR * input_attn; + + // chained input allpasses, channel R + acc = in_allp1_bufR[in_allp1_idxR] + input * in_allp_k; + in_allp1_bufR[in_allp1_idxR] = input - in_allp_k * acc; + input = acc; + if (++in_allp1_idxR >= sizeof(in_allp1_bufR)/sizeof(float32_t)) in_allp1_idxR = 0; + + acc = in_allp2_bufR[in_allp2_idxR] + input * in_allp_k; + in_allp2_bufR[in_allp2_idxR] = input - in_allp_k * acc; + input = acc; + if (++in_allp2_idxR >= sizeof(in_allp2_bufR)/sizeof(float32_t)) in_allp2_idxR = 0; + + acc = in_allp3_bufR[in_allp3_idxR] + input * in_allp_k; + in_allp3_bufR[in_allp3_idxR] = input - in_allp_k * acc; + input = acc; + if (++in_allp3_idxR >= sizeof(in_allp3_bufR)/sizeof(float32_t)) in_allp3_idxR = 0; + + acc = in_allp4_bufR[in_allp4_idxR] + input * in_allp_k; + in_allp4_bufR[in_allp4_idxR] = input - in_allp_k * acc; + in_allp_out_R = acc; + if (++in_allp4_idxR >= sizeof(in_allp4_bufR)/sizeof(float32_t)) in_allp4_idxR = 0; + + // input allpases done, start loop allpases + input = lp_allp_out + in_allp_out_R; + acc = lp_allp1_buf[lp_allp1_idx] + input * loop_allp_k; // input is the lp allpass chain output + lp_allp1_buf[lp_allp1_idx] = input - loop_allp_k * acc; + input = acc; + if (++lp_allp1_idx >= sizeof(lp_allp1_buf)/sizeof(float32_t))lp_allp1_idx = 0; + + acc = lp_dly1_buf[lp_dly1_idx]; // read the end of the delay + lp_dly1_buf[lp_dly1_idx] = input; // write new sample + input = acc; + if (++lp_dly1_idx >= sizeof(lp_dly1_buf)/sizeof(float32_t)) lp_dly1_idx = 0; // update index + + // hi/lo shelving filter + temp1 = input - lpf1; + lpf1 += temp1 * lp_lowpass_f; + temp2 = input - lpf1; + temp1 = lpf1 - hpf1; + hpf1 += temp1 * lp_hipass_f; + acc = lpf1 + temp2*lp_hidamp_k + hpf1*lp_lodamp_k; + acc = acc * rv_time * rv_time_scaler; // scale by the reveb time + + input = acc + in_allp_out_L; + + acc = lp_allp2_buf[lp_allp2_idx] + input * loop_allp_k; + lp_allp2_buf[lp_allp2_idx] = input - loop_allp_k * acc; + input = acc; + if (++lp_allp2_idx >= sizeof(lp_allp2_buf)/sizeof(float32_t)) lp_allp2_idx = 0; + acc = lp_dly2_buf[lp_dly2_idx]; // read the end of the delay + lp_dly2_buf[lp_dly2_idx] = input; // write new sample + input = acc; + if (++lp_dly2_idx >= sizeof(lp_dly2_buf)/sizeof(float32_t)) lp_dly2_idx = 0; // update index + // hi/lo shelving filter + temp1 = input - lpf2; + lpf2 += temp1 * lp_lowpass_f; + temp2 = input - lpf2; + temp1 = lpf2 - hpf2; + hpf2 += temp1 * lp_hipass_f; + acc = lpf2 + temp2*lp_hidamp_k + hpf2*lp_lodamp_k; + acc = acc * rv_time * rv_time_scaler; + + input = acc + in_allp_out_R; + + acc = lp_allp3_buf[lp_allp3_idx] + input * loop_allp_k; + lp_allp3_buf[lp_allp3_idx] = input - loop_allp_k * acc; + input = acc; + if (++lp_allp3_idx >= sizeof(lp_allp3_buf)/sizeof(float32_t)) lp_allp3_idx = 0; + acc = lp_dly3_buf[lp_dly3_idx]; // read the end of the delay + lp_dly3_buf[lp_dly3_idx] = input; // write new sample + input = acc; + if (++lp_dly3_idx >= sizeof(lp_dly3_buf)/sizeof(float32_t)) lp_dly3_idx = 0; // update index + // hi/lo shelving filter + temp1 = input - lpf3; + lpf3 += temp1 * lp_lowpass_f; + temp2 = input - lpf3; + temp1 = lpf3 - hpf3; + hpf3 += temp1 * lp_hipass_f; + acc = lpf3 + temp2*lp_hidamp_k + hpf3*lp_lodamp_k; + acc = acc * rv_time * rv_time_scaler; + + input = acc + in_allp_out_L; + + acc = lp_allp4_buf[lp_allp4_idx] + input * loop_allp_k; + lp_allp4_buf[lp_allp4_idx] = input - loop_allp_k * acc; + input = acc; + if (++lp_allp4_idx >= sizeof(lp_allp4_buf)/sizeof(float32_t)) lp_allp4_idx = 0; + acc = lp_dly4_buf[lp_dly4_idx]; // read the end of the delay + lp_dly4_buf[lp_dly4_idx] = input; // write new sample + input = acc; + if (++lp_dly4_idx >= sizeof(lp_dly4_buf)/sizeof(float32_t)) lp_dly4_idx= 0; // update index + // hi/lo shelving filter + temp1 = input - lpf4; + lpf4 += temp1 * lp_lowpass_f; + temp2 = input - lpf4; + temp1 = lpf4 - hpf4; + hpf4 += temp1 * lp_hipass_f; + acc = lpf4 + temp2*lp_hidamp_k + hpf4*lp_lodamp_k; + acc = acc * rv_time * rv_time_scaler; + + lp_allp_out = acc; + + // channel L: +#ifdef TAP1_MODULATED + temp16 = (lp_dly1_idx + lp_dly1_offset_L + (lfo1_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); + temp1 = lp_dly1_buf[temp16++]; // sample now + if (temp16 >= sizeof(lp_dly1_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly1_buf[temp16]; // sample next + input = (float32_t)(lfo1_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc = (temp1*(1.0f-input) + temp2*input)* 0.8f; +#else + temp16 = (lp_dly1_idx + lp_dly1_offset_L) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); + acc = lp_dly1_buf[temp16]* 0.8f; +#endif + + +#ifdef TAP2_MODULATED + temp16 = (lp_dly2_idx + lp_dly2_offset_L + (lfo1_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); + temp1 = lp_dly2_buf[temp16++]; + if (temp16 >= sizeof(lp_dly2_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly2_buf[temp16]; + input = (float32_t)(lfo1_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; +#else + temp16 = (lp_dly2_idx + lp_dly2_offset_L) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); + acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; +#endif + + temp16 = (lp_dly3_idx + lp_dly3_offset_L + (lfo2_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly3_buf)/sizeof(float32_t)); + temp1 = lp_dly3_buf[temp16++]; + if (temp16 >= sizeof(lp_dly3_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly3_buf[temp16]; + input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; + + temp16 = (lp_dly4_idx + lp_dly4_offset_L + (lfo2_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly4_buf)/sizeof(float32_t)); + temp1 = lp_dly4_buf[temp16++]; + if (temp16 >= sizeof(lp_dly4_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly4_buf[temp16]; + input = (float32_t)(lfo2_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.5f; + + // Master lowpass filter + temp1 = acc - master_lowpass_l; + master_lowpass_l += temp1 * master_lowpass_f; + + outL = master_lowpass_l; + + // Channel R +#ifdef TAP1_MODULATED + temp16 = (lp_dly1_idx + lp_dly1_offset_R + (lfo2_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); + temp1 = lp_dly1_buf[temp16++]; // sample now + if (temp16 >= sizeof(lp_dly1_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly1_buf[temp16]; // sample next + input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + + acc = (temp1*(1.0f-input) + temp2*input)* 0.8f; + #else + temp16 = (lp_dly1_idx + lp_dly1_offset_R) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); + acc = lp_dly1_buf[temp16] * 0.8f; + #endif +#ifdef TAP2_MODULATED + temp16 = (lp_dly2_idx + lp_dly2_offset_R + (lfo1_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); + temp1 = lp_dly2_buf[temp16++]; + if (temp16 >= sizeof(lp_dly2_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly2_buf[temp16]; + input = (float32_t)(lfo1_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; +#else + temp16 = (lp_dly2_idx + lp_dly2_offset_R) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); + acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; +#endif + temp16 = (lp_dly3_idx + lp_dly3_offset_R + (lfo2_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly3_buf)/sizeof(float32_t)); + temp1 = lp_dly3_buf[temp16++]; + if (temp16 >= sizeof(lp_dly3_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly3_buf[temp16]; + input = (float32_t)(lfo2_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; + + temp16 = (lp_dly4_idx + lp_dly4_offset_R + (lfo1_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly4_buf)/sizeof(float32_t)); + temp1 = lp_dly4_buf[temp16++]; + if (temp16 >= sizeof(lp_dly4_buf)/sizeof(float32_t)) temp16 = 0; + temp2 = lp_dly4_buf[temp16]; + input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k + acc += (temp1*(1.0f-input) + temp2*input)* 0.5f; + + // Master lowpass filter + temp1 = acc - master_lowpass_r; + master_lowpass_r += temp1 * master_lowpass_f; + + outR = master_lowpass_r; +} + +void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len) +{ static bool cleanup_done = false; // handle bypass, 1st call will clean the buffers to avoid continuing the previous reverb tail @@ -176,23 +454,7 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t { if (!cleanup_done) { - memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); - memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); - memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); - memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); - memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); - memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); - memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); - memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); - memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); - memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); - memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); - memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); - memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); - memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); - memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); - memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); - + this->reset(); cleanup_done = true; } @@ -200,255 +462,8 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t } cleanup_done = false; - rv_time = rv_time_k; - for (uint16_t i=0; i < len; i++) { - // do the LFOs - lfo1_phase_acc += lfo1_adder; - idx = lfo1_phase_acc >> 24; // 8bit lookup table address - y0 = AudioWaveformSine[idx]; - y1 = AudioWaveformSine[idx+1]; - idx = lfo1_phase_acc & 0x00FFFFFF; // lower 24 bit = fractional part - y = (int64_t)y0 * (0x00FFFFFF - idx); - y += (int64_t)y1 * idx; - lfo1_out_sin = (int32_t) (y >> (32-8)); // 16bit output - idx = ((lfo1_phase_acc >> 24)+64) & 0xFF; - y0 = AudioWaveformSine[idx]; - y1 = AudioWaveformSine[idx + 1]; - y = (int64_t)y0 * (0x00FFFFFF - idx); - y += (int64_t)y1 * idx; - lfo1_out_cos = (int32_t) (y >> (32-8)); // 16bit output - - lfo2_phase_acc += lfo2_adder; - idx = lfo2_phase_acc >> 24; // 8bit lookup table address - y0 = AudioWaveformSine[idx]; - y1 = AudioWaveformSine[idx+1]; - idx = lfo2_phase_acc & 0x00FFFFFF; // lower 24 bit = fractional part - y = (int64_t)y0 * (0x00FFFFFF - idx); - y += (int64_t)y1 * idx; - lfo2_out_sin = (int32_t) (y >> (32-8)); //32-8->output 16bit, - idx = ((lfo2_phase_acc >> 24)+64) & 0xFF; - y0 = AudioWaveformSine[idx]; - y1 = AudioWaveformSine[idx + 1]; - y = (int64_t)y0 * (0x00FFFFFF - idx); - y += (int64_t)y1 * idx; - lfo2_out_cos = (int32_t) (y >> (32-8)); // 16bit output - - input = inblockL[i] * input_attn; - - // chained input allpasses, channel L - acc = in_allp1_bufL[in_allp1_idxL] + input * in_allp_k; - in_allp1_bufL[in_allp1_idxL] = input - in_allp_k * acc; - input = acc; - if (++in_allp1_idxL >= sizeof(in_allp1_bufL)/sizeof(float32_t)) in_allp1_idxL = 0; - - acc = in_allp2_bufL[in_allp2_idxL] + input * in_allp_k; - in_allp2_bufL[in_allp2_idxL] = input - in_allp_k * acc; - input = acc; - if (++in_allp2_idxL >= sizeof(in_allp2_bufL)/sizeof(float32_t)) in_allp2_idxL = 0; - - acc = in_allp3_bufL[in_allp3_idxL] + input * in_allp_k; - in_allp3_bufL[in_allp3_idxL] = input - in_allp_k * acc; - input = acc; - if (++in_allp3_idxL >= sizeof(in_allp3_bufL)/sizeof(float32_t)) in_allp3_idxL = 0; - - acc = in_allp4_bufL[in_allp4_idxL] + input * in_allp_k; - in_allp4_bufL[in_allp4_idxL] = input - in_allp_k * acc; - in_allp_out_L = acc; - if (++in_allp4_idxL >= sizeof(in_allp4_bufL)/sizeof(float32_t)) in_allp4_idxL = 0; - - input = inblockR[i] * input_attn; - - // chained input allpasses, channel R - acc = in_allp1_bufR[in_allp1_idxR] + input * in_allp_k; - in_allp1_bufR[in_allp1_idxR] = input - in_allp_k * acc; - input = acc; - if (++in_allp1_idxR >= sizeof(in_allp1_bufR)/sizeof(float32_t)) in_allp1_idxR = 0; - - acc = in_allp2_bufR[in_allp2_idxR] + input * in_allp_k; - in_allp2_bufR[in_allp2_idxR] = input - in_allp_k * acc; - input = acc; - if (++in_allp2_idxR >= sizeof(in_allp2_bufR)/sizeof(float32_t)) in_allp2_idxR = 0; - - acc = in_allp3_bufR[in_allp3_idxR] + input * in_allp_k; - in_allp3_bufR[in_allp3_idxR] = input - in_allp_k * acc; - input = acc; - if (++in_allp3_idxR >= sizeof(in_allp3_bufR)/sizeof(float32_t)) in_allp3_idxR = 0; - - acc = in_allp4_bufR[in_allp4_idxR] + input * in_allp_k; - in_allp4_bufR[in_allp4_idxR] = input - in_allp_k * acc; - in_allp_out_R = acc; - if (++in_allp4_idxR >= sizeof(in_allp4_bufR)/sizeof(float32_t)) in_allp4_idxR = 0; - - // input allpases done, start loop allpases - input = lp_allp_out + in_allp_out_R; - acc = lp_allp1_buf[lp_allp1_idx] + input * loop_allp_k; // input is the lp allpass chain output - lp_allp1_buf[lp_allp1_idx] = input - loop_allp_k * acc; - input = acc; - if (++lp_allp1_idx >= sizeof(lp_allp1_buf)/sizeof(float32_t)) lp_allp1_idx = 0; - - acc = lp_dly1_buf[lp_dly1_idx]; // read the end of the delay - lp_dly1_buf[lp_dly1_idx] = input; // write new sample - input = acc; - if (++lp_dly1_idx >= sizeof(lp_dly1_buf)/sizeof(float32_t)) lp_dly1_idx = 0; // update index - - // hi/lo shelving filter - temp1 = input - lpf1; - lpf1 += temp1 * lp_lowpass_f; - temp2 = input - lpf1; - temp1 = lpf1 - hpf1; - hpf1 += temp1 * lp_hipass_f; - acc = lpf1 + temp2*lp_hidamp_k + hpf1*lp_lodamp_k; - acc = acc * rv_time * rv_time_scaler; // scale by the reveb time - - input = acc + in_allp_out_L; - - acc = lp_allp2_buf[lp_allp2_idx] + input * loop_allp_k; - lp_allp2_buf[lp_allp2_idx] = input - loop_allp_k * acc; - input = acc; - if (++lp_allp2_idx >= sizeof(lp_allp2_buf)/sizeof(float32_t)) lp_allp2_idx = 0; - acc = lp_dly2_buf[lp_dly2_idx]; // read the end of the delay - lp_dly2_buf[lp_dly2_idx] = input; // write new sample - input = acc; - if (++lp_dly2_idx >= sizeof(lp_dly2_buf)/sizeof(float32_t)) lp_dly2_idx = 0; // update index - // hi/lo shelving filter - temp1 = input - lpf2; - lpf2 += temp1 * lp_lowpass_f; - temp2 = input - lpf2; - temp1 = lpf2 - hpf2; - hpf2 += temp1 * lp_hipass_f; - acc = lpf2 + temp2*lp_hidamp_k + hpf2*lp_lodamp_k; - acc = acc * rv_time * rv_time_scaler; - - input = acc + in_allp_out_R; - - acc = lp_allp3_buf[lp_allp3_idx] + input * loop_allp_k; - lp_allp3_buf[lp_allp3_idx] = input - loop_allp_k * acc; - input = acc; - if (++lp_allp3_idx >= sizeof(lp_allp3_buf)/sizeof(float32_t)) lp_allp3_idx = 0; - acc = lp_dly3_buf[lp_dly3_idx]; // read the end of the delay - lp_dly3_buf[lp_dly3_idx] = input; // write new sample - input = acc; - if (++lp_dly3_idx >= sizeof(lp_dly3_buf)/sizeof(float32_t)) lp_dly3_idx = 0; // update index - // hi/lo shelving filter - temp1 = input - lpf3; - lpf3 += temp1 * lp_lowpass_f; - temp2 = input - lpf3; - temp1 = lpf3 - hpf3; - hpf3 += temp1 * lp_hipass_f; - acc = lpf3 + temp2*lp_hidamp_k + hpf3*lp_lodamp_k; - acc = acc * rv_time * rv_time_scaler; - - input = acc + in_allp_out_L; - - acc = lp_allp4_buf[lp_allp4_idx] + input * loop_allp_k; - lp_allp4_buf[lp_allp4_idx] = input - loop_allp_k * acc; - input = acc; - if (++lp_allp4_idx >= sizeof(lp_allp4_buf)/sizeof(float32_t)) lp_allp4_idx = 0; - acc = lp_dly4_buf[lp_dly4_idx]; // read the end of the delay - lp_dly4_buf[lp_dly4_idx] = input; // write new sample - input = acc; - if (++lp_dly4_idx >= sizeof(lp_dly4_buf)/sizeof(float32_t)) lp_dly4_idx= 0; // update index - // hi/lo shelving filter - temp1 = input - lpf4; - lpf4 += temp1 * lp_lowpass_f; - temp2 = input - lpf4; - temp1 = lpf4 - hpf4; - hpf4 += temp1 * lp_hipass_f; - acc = lpf4 + temp2*lp_hidamp_k + hpf4*lp_lodamp_k; - acc = acc * rv_time * rv_time_scaler; - - lp_allp_out = acc; - - // channel L: -#ifdef TAP1_MODULATED - temp16 = (lp_dly1_idx + lp_dly1_offset_L + (lfo1_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); - temp1 = lp_dly1_buf[temp16++]; // sample now - if (temp16 >= sizeof(lp_dly1_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly1_buf[temp16]; // sample next - input = (float32_t)(lfo1_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc = (temp1*(1.0f-input) + temp2*input)* 0.8f; -#else - temp16 = (lp_dly1_idx + lp_dly1_offset_L) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); - acc = lp_dly1_buf[temp16]* 0.8f; -#endif - - -#ifdef TAP2_MODULATED - temp16 = (lp_dly2_idx + lp_dly2_offset_L + (lfo1_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); - temp1 = lp_dly2_buf[temp16++]; - if (temp16 >= sizeof(lp_dly2_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly2_buf[temp16]; - input = (float32_t)(lfo1_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; -#else - temp16 = (lp_dly2_idx + lp_dly2_offset_L) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); - acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; -#endif - - temp16 = (lp_dly3_idx + lp_dly3_offset_L + (lfo2_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly3_buf)/sizeof(float32_t)); - temp1 = lp_dly3_buf[temp16++]; - if (temp16 >= sizeof(lp_dly3_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly3_buf[temp16]; - input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; - - temp16 = (lp_dly4_idx + lp_dly4_offset_L + (lfo2_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly4_buf)/sizeof(float32_t)); - temp1 = lp_dly4_buf[temp16++]; - if (temp16 >= sizeof(lp_dly4_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly4_buf[temp16]; - input = (float32_t)(lfo2_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.5f; - - // Master lowpass filter - temp1 = acc - master_lowpass_l; - master_lowpass_l += temp1 * master_lowpass_f; - - rvbblockL[i] = master_lowpass_l; - - // Channel R - #ifdef TAP1_MODULATED - temp16 = (lp_dly1_idx + lp_dly1_offset_R + (lfo2_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); - temp1 = lp_dly1_buf[temp16++]; // sample now - if (temp16 >= sizeof(lp_dly1_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly1_buf[temp16]; // sample next - input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - - acc = (temp1*(1.0f-input) + temp2*input)* 0.8f; - #else - temp16 = (lp_dly1_idx + lp_dly1_offset_R) % (sizeof(lp_dly1_buf)/sizeof(float32_t)); - acc = lp_dly1_buf[temp16] * 0.8f; - #endif -#ifdef TAP2_MODULATED - temp16 = (lp_dly2_idx + lp_dly2_offset_R + (lfo1_out_cos>>LFO_FRAC_BITS)) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); - temp1 = lp_dly2_buf[temp16++]; - if (temp16 >= sizeof(lp_dly2_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly2_buf[temp16]; - input = (float32_t)(lfo1_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; -#else - temp16 = (lp_dly2_idx + lp_dly2_offset_R) % (sizeof(lp_dly2_buf)/sizeof(float32_t)); - acc += (temp1*(1.0f-input) + temp2*input)* 0.7f; -#endif - temp16 = (lp_dly3_idx + lp_dly3_offset_R + (lfo2_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly3_buf)/sizeof(float32_t)); - temp1 = lp_dly3_buf[temp16++]; - if (temp16 >= sizeof(lp_dly3_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly3_buf[temp16]; - input = (float32_t)(lfo2_out_sin & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.6f; - - temp16 = (lp_dly4_idx + lp_dly4_offset_R + (lfo1_out_sin>>LFO_FRAC_BITS)) % (sizeof(lp_dly4_buf)/sizeof(float32_t)); - temp1 = lp_dly4_buf[temp16++]; - if (temp16 >= sizeof(lp_dly4_buf)/sizeof(float32_t)) temp16 = 0; - temp2 = lp_dly4_buf[temp16]; - input = (float32_t)(lfo2_out_cos & LFO_FRAC_MASK) / ((float32_t)LFO_FRAC_MASK); // interp. k - acc += (temp1*(1.0f-input) + temp2*input)* 0.5f; - - // Master lowpass filter - temp1 = acc - master_lowpass_r; - master_lowpass_r += temp1 * master_lowpass_f; - - rvbblockR[i] = master_lowpass_r; + this->processSample(inblockL[i], inblockR[i], rvbblockL[i], rvbblockR[i]); } } diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 23538c4..4dfbc47 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -44,9 +44,7 @@ #ifndef _EFFECT_PLATERVBSTEREO_H #define _EFFECT_PLATERVBSTEREO_H -#include -#include -#include "common.h" +#include "fx_components.h" /*** * Loop delay modulation: comment/uncomment to switch sin/cos @@ -56,11 +54,18 @@ //#define TAP1_MODULATED #define TAP2_MODULATED -class AudioEffectPlateReverb +class AudioEffectPlateReverb : public FXElement { + DISALLOW_COPY_AND_ASSIGN(AudioEffectPlateReverb); + public: AudioEffectPlateReverb(float32_t samplerate); - void doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR,uint16_t len); + virtual ~AudioEffectPlateReverb(); + + virtual void reset() override; + virtual void processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) override; + + void doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len); void size(float n) { diff --git a/src/fx_components.cpp b/src/fx_components.cpp index f613f99..dfa5f7c 100644 --- a/src/fx_components.cpp +++ b/src/fx_components.cpp @@ -91,7 +91,7 @@ float32_t LFO::process() switch(this->waveform_) { case Waveform::Sine: - out = std::sin(this->phase_); + out = arm_sin_f32(this->phase_); break; case Waveform::Saw: out = Constants::M1_PI * this->phase_ - 1.0f; @@ -187,7 +187,7 @@ void JitterGenerator::reset() float32_t JitterGenerator::process() { - float32_t out = std::sin(this->phase_); + float32_t out = arm_sin_f32(this->phase_); this->phase_ += this->phase_increment_ * (1.0f + this->magnitude_ * this->rnd_distribution_(this->rnd_generator_)); if(this->phase_ > Constants::M2PI) diff --git a/src/fx_engine.hpp b/src/fx_engine.hpp index 9f5b371..d295d0b 100644 --- a/src/fx_engine.hpp +++ b/src/fx_engine.hpp @@ -98,8 +98,11 @@ public: virtual void reset() override { this->clear(); - this->lfo_[LFOIndex::LFO_1]->reset(); - this->lfo_[LFOIndex::LFO_2]->reset(); + if(enable_lfo) + { + this->lfo_[LFOIndex::LFO_1]->reset(); + this->lfo_[LFOIndex::LFO_2]->reset(); + } } struct Empty diff --git a/src/fx_phaser.cpp b/src/fx_phaser.cpp index 93f88f9..5a778c4 100644 --- a/src/fx_phaser.cpp +++ b/src/fx_phaser.cpp @@ -33,7 +33,7 @@ void Phaser::AllpassDelay::setDelay(float32_t delay) } -Phaser::Phaser(float32_t sampling_rate, float32_t rate, float32_t depth, float32_t feedback) : +Phaser::Phaser(float32_t sampling_rate, float32_t rate, float32_t depth, float32_t feedback, unsigned nb_stages) : FXElement(sampling_rate), lfo_(sampling_rate, LFO::Waveform::Sine, 0.0f, 2.5f), depth_(0.0f), @@ -44,6 +44,7 @@ Phaser::Phaser(float32_t sampling_rate, float32_t rate, float32_t depth, float32 this->setRate(rate); this->setDepth(depth); this->setFeedback(feedback); + this->setNbStages(nb_stages); this->setFrequencyRange(440.0f, 1600.0f); this->reset(); @@ -57,7 +58,7 @@ void Phaser::reset() { memset(this->z_, 0, 2 * sizeof(float32_t)); - for(unsigned i = 0; i < this->nb_stages_; ++i) + for(unsigned i = 0; i < MAX_NB_PHASES; ++i) { this->stages_[i].reset(); } diff --git a/src/fx_phaser.h b/src/fx_phaser.h index c07f654..e7f97fd 100644 --- a/src/fx_phaser.h +++ b/src/fx_phaser.h @@ -45,7 +45,7 @@ public: float32_t z_[2]; }; - Phaser(float32_t sampling_rate, float32_t rate = 0.5f, float32_t depth = 1.0f, float32_t feedback = 0.7f); + Phaser(float32_t sampling_rate, float32_t rate = 0.5f, float32_t depth = 1.0f, float32_t feedback = 0.7f, unsigned nb_stages = 12); virtual ~Phaser(); virtual void reset() override; diff --git a/src/fx_rack.cpp b/src/fx_rack.cpp index 60d5641..874fd33 100644 --- a/src/fx_rack.cpp +++ b/src/fx_rack.cpp @@ -39,22 +39,22 @@ FXRack::~FXRack() delete this->fxShimmerReverb_; } -inline void FXRack::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) +inline void FXRack::reset() { for(FXChain::iterator it = this->fx_chain_.begin(); it != this->fx_chain_.end(); it++) { - (*it)->processSample(inL, inR, outL, outR); - - inL = outL; - inR = outR; + (*it)->reset();; } } -void FXRack::reset() +inline void FXRack::processSample(float32_t inL, float32_t inR, float32_t& outL, float32_t& outR) { for(FXChain::iterator it = this->fx_chain_.begin(); it != this->fx_chain_.end(); it++) { - (*it)->reset();; + (*it)->processSample(inL, inR, outL, outR); + + inL = outL; + inR = outR; } } diff --git a/src/fx_unit.hpp b/src/fx_unit.hpp index 5c2d540..913fcb6 100644 --- a/src/fx_unit.hpp +++ b/src/fx_unit.hpp @@ -20,6 +20,9 @@ #include "fx_components.h" +#include +using namespace std; + class FXUnitModule { DISALLOW_COPY_AND_ASSIGN(FXUnitModule); @@ -94,10 +97,7 @@ public: { if(!this->isEnable() || this->getWetLevel() == 0.0f) { - if(!this->isEnable()) - { - _FXElement::reset(); - } + this->reset(); outL = inL; outR = inR; diff --git a/src/minidexed.h b/src/minidexed.h index f54d09d..194c0ea 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -45,7 +45,7 @@ #include "effect_platervbstereo.h" #include "effect_compressor.h" -#ifdef ARM_ALLOW_MULTI_CORE +#ifdef FXRACK_ENABLE #include "fx_rack.h" #endif diff --git a/src/test/Makefile b/src/test/Makefile index 5f61429..f8778a4 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,6 +1,6 @@ CXX := gcc # CXXFLAGS := -O2 -CXXFLAGS := -g +CXXFLAGS := -g DEFINES := -DCPU=x86 INCLUDES := -I../../CMSIS_5/CMSIS/DSP/Include/ -I../../CMSIS_5/CMSIS/Core/Include/ GCC := $(CXX) $(INCLUDES) $(CXXFLAGS) @@ -9,8 +9,6 @@ LD := gcc LIBS := -lm -lstdc++ OBJS := \ - wavein.o \ - waveout.o \ fx.o \ fx_components.o \ fx_svf.o \ @@ -22,13 +20,16 @@ OBJS := \ fx_delay.o \ fx_shimmer_reverb.o \ fx_rack.o \ + effect_platervbstereo.o \ + wavein.o \ + waveout.o \ fxrack_test.o test: fxrack_test ./fxrack_test -# %.o: ../%.cpp -# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +%.o: ../%.cpp + $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ wavein.o: wavein.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ @@ -36,50 +37,53 @@ wavein.o: wavein.cpp waveout.o: waveout.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -# waveplay.o: waveplay.cpp +# # waveplay.o: waveplay.cpp +# # $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ + +# fx.o: ../fx.cpp # $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx.o: ../fx.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_components.o: ../fx_components.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_components.o: ../fx_components.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_svf.o: ../fx_svf.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_svf.o: ../fx_svf.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_tube.o: ../fx_tube.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_tube.o: ../fx_tube.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# ../fx_chorus.cpp: ../fx_engine.hpp +# touch ../fx_chorus.cpp -../fx_chorus.cpp: ../fx_engine.hpp - touch ../fx_chorus.cpp +# fx_chorus.o: ../fx_chorus.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_chorus.o: ../fx_chorus.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_phaser.o: ../fx_phaser.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_phaser.o: ../fx_phaser.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# ../fx_orbitone.cpp: ../fx_engine.hpp +# touch ../fx_orbitone.cpp -../fx_orbitone.cpp: ../fx_engine.hpp - touch ../fx_orbitone.cpp +# fx_orbitone.o: ../fx_orbitone.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_orbitone.o: ../fx_orbitone.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_flanger.o: ../fx_flanger.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_flanger.o: ../fx_flanger.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_delay.o: ../fx_delay.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_delay.o: ../fx_delay.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# ../fx_shimmer_reverb.cpp: ../fx_engine.hpp +# touch ../fx_shimmer_reverb.cpp -../fx_shimmer_reverb.cpp: ../fx_engine.hpp - touch ../fx_shimmer_reverb.cpp +# fx_shimmer_reverb.o: ../fx_shimmer_reverb.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_shimmer_reverb.o: ../fx_shimmer_reverb.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# fx_rack.o: ../fx_rack.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ -fx_rack.o: ../fx_rack.cpp - $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ +# effect_platervbstereo.o: ../effect_platervbstereo.cpp +# $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ fxrack_test.o: fxrack_test.cpp $(CXX) $(DEFINES) $(INCLUDES) $(CXXFLAGS) -c $^ -o $@ diff --git a/src/test/fxrack_test.cpp b/src/test/fxrack_test.cpp index 9e75e3c..b09b3a9 100644 --- a/src/test/fxrack_test.cpp +++ b/src/test/fxrack_test.cpp @@ -1,10 +1,15 @@ #include "../fx_rack.h" +#include "../effect_platervbstereo.h" + #include #include #include +#include +#include #include #include +#include #include #include "wave.h" @@ -14,9 +19,103 @@ using namespace std; #define MAX_SVF_SAMPLES 10000000 #define MAX_NB_ERRORS 100 -std::random_device rd; -std::mt19937 gen(rd()); -std::uniform_real_distribution dist(-1.0f, 1.0f); +random_device rd; +mt19937 gen(rd()); +uniform_real_distribution dist(-1.0f, 1.0f); + +float32_t arm_sin_f32(float32_t phase) +{ + return sin(phase); +} + +void arm_scale_f32(const float32_t *pSrc, float32_t scale, float32_t *pDst, uint32_t blockSize) +{ + for(unsigned i = 0; i < blockSize; ++i) + { + pDst[i] = scale * pSrc[i]; + } +} + +void testPlateReverb(unsigned& step) +{ + const unsigned nbRepeats = 4; + + cout << "Step #" << (++step) << " - PlateReverb creation"; + + AudioEffectPlateReverb* reverb = new AudioEffectPlateReverb(44100.0f); + + cout << "done" << endl; + cout << "Step #" << (++step) << " - Setup PlateReverb: "; + + reverb->set_bypass(false); + reverb->size(0.7f); + reverb->hidamp(0.5f); + reverb->lodamp(0.5f); + reverb->lowpass(0.3f); + reverb->diffusion(0.65f); + reverb->level(1.0f); + + + unsigned size; + float32_t** samples = readWaveFile("test.wav", size); + float32_t* sampleOutL = new float32_t[size * nbRepeats]; + float32_t* sampleOutR = new float32_t[size * nbRepeats]; + memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); + memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); + + cout << "done" << endl; + cout << "Step #" << (++step) << " - Processing PlateReverb new algo: "; + + unsigned index = 0; + for(unsigned i = 0; i < nbRepeats; ++i) + { + for(unsigned j = 0; j < size; ++j) + { + reverb->processSample(samples[0][j], samples[1][j], sampleOutL[index], sampleOutR[index]); + ++index; + } + } + saveWaveFile("result-new.wav", sampleOutL, sampleOutR, nbRepeats * size, static_cast(FS), 16); + + cout << "done" << endl; + cout << "Step #" << (++step) << " - Processing PlateReverb legacy algo: "; + + unsigned indexOut = 0; + for (unsigned i = 0; i < nbRepeats; ++i) + { + unsigned len = size; + unsigned indexIn = 0; + + while(len > 0) + { + unsigned grainSize = (len < 1024 ? len : 1024); + + reverb->doReverb(samples[0] + indexIn, samples[1] + indexIn, sampleOutL + indexOut, sampleOutR + indexOut, grainSize); + + indexIn += grainSize; + indexOut += grainSize; + len -= grainSize; + } + + } + saveWaveFile("result-legacy.wav", sampleOutL, sampleOutR, nbRepeats * size, static_cast(FS), 16); + + cout << "done" << endl; + cout << "Step #" << (++step) << " - Cleanup: "; + + delete[] sampleOutL; + delete[] sampleOutR; + delete[] samples[0]; + delete[] samples[1]; + delete[] samples; + + cout << "done" << endl; + cout << "Step #" << (++step) << " - Deleting PlateReverb: "; + + delete reverb; + + cout << "done" << endl; +} void testLFO(unsigned& step) { @@ -32,12 +131,12 @@ void testLFO(unsigned& step) // float32_t* output = new float32_t[size]; ofstream out("result.csv"); - struct comma_separator : std::numpunct + struct comma_separator : numpunct { virtual char do_decimal_point() const override { return ','; } }; - out.imbue(std::locale(out.getloc(), new comma_separator)); + out.imbue(locale(out.getloc(), new comma_separator)); out << fixed << showpoint; out << "index;LFO" << endl; @@ -88,9 +187,9 @@ void testSVF(unsigned& step) inR = dist(gen); svf.processSample(inL, inR, outL, outR); - if (std::abs(outL) > 1.0f) + if (abs(outL) > 1.0f) nbErrors++; - if (std::abs(outR) > 1.0f) + if (abs(outR) > 1.0f) nbErrors++; } cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl; @@ -110,9 +209,9 @@ void testSVF(unsigned& step) inR = dist(gen); svf.processSample(inL, inR, outL, outR); - if (std::abs(outL) > 1.0f) + if (abs(outL) > 1.0f) nbErrors++; - if (std::abs(outR) > 1.0f) + if (abs(outR) > 1.0f) nbErrors++; } cout << "nbSamples: " << nbSamples << " -- nbErrors: " << nbErrors << endl; @@ -127,62 +226,246 @@ enum FXSitch Orbitone = 1 << 3, Flanger = 1 << 4, Delay = 1 << 5, - Shimmer = 1 << 6 + Shimmer = 1 << 6, + kNbFX = 7 +}; + +int scenarii[] = +{ + 0, + Tube, + Chorus, + Phaser, + Orbitone, + Flanger, + Delay, + Shimmer, + Tube | Chorus, + Tube | Phaser, + Tube | Orbitone, + Tube | Flanger, + Tube | Delay, + Tube | Shimmer, + Chorus | Phaser, + Chorus | Orbitone, + Chorus | Flanger, + Chorus | Delay, + Chorus | Shimmer, + Phaser | Orbitone, + Phaser | Flanger, + Phaser | Delay, + Phaser | Shimmer, + Orbitone | Flanger, + Orbitone | Delay, + Orbitone | Shimmer, + Flanger | Delay, + Flanger | Shimmer, + Delay | Shimmer, + Tube | Chorus | Phaser, + Tube | Chorus | Orbitone, + Tube | Chorus | Flanger, + Tube | Chorus | Delay, + Tube | Chorus | Shimmer, + Tube | Phaser | Orbitone, + Tube | Phaser | Flanger, + Tube | Phaser | Delay, + Tube | Phaser | Shimmer, + Tube | Orbitone | Flanger, + Tube | Orbitone | Delay, + Tube | Orbitone | Shimmer, + Tube | Flanger | Delay, + Tube | Flanger | Shimmer, + Tube | Delay | Shimmer, + Tube | Chorus | Phaser | Orbitone, + Tube | Chorus | Phaser | Flanger, + Tube | Chorus | Phaser | Delay, + Tube | Chorus | Phaser | Shimmer, + Tube | Chorus | Orbitone | Flanger, + Tube | Chorus | Orbitone | Delay, + Tube | Chorus | Orbitone | Shimmer, + Tube | Chorus | Flanger | Delay, + Tube | Chorus | Flanger | Shimmer, + Tube | Phaser | Orbitone | Flanger, + Tube | Phaser | Orbitone | Delay, + Tube | Phaser | Orbitone | Shimmer, + Tube | Phaser | Flanger | Delay, + Tube | Phaser | Flanger | Shimmer, + Tube | Phaser | Delay | Shimmer, + Tube | Chorus | Phaser | Orbitone | Flanger, + Tube | Chorus | Phaser | Orbitone | Delay, + Tube | Chorus | Phaser | Orbitone | Shimmer, + Tube | Chorus | Phaser | Flanger | Delay, + Tube | Chorus | Phaser | Flanger | Shimmer, + Tube | Chorus | Phaser | Delay | Shimmer, + Tube | Chorus | Orbitone | Flanger | Delay, + Tube | Chorus | Orbitone | Flanger | Shimmer, + Tube | Chorus | Flanger | Delay | Shimmer, + Tube | Phaser | Orbitone | Flanger | Delay, + Tube | Phaser | Orbitone | Flanger | Shimmer, + Tube | Phaser | Orbitone | Delay | Shimmer, + Tube | Orbitone | Flanger | Delay | Shimmer, + Tube | Chorus | Phaser | Orbitone | Flanger | Delay, + Tube | Chorus | Phaser | Orbitone | Flanger | Shimmer, + Tube | Chorus | Phaser | Orbitone | Delay | Shimmer, + Tube | Chorus | Phaser | Flanger | Delay | Shimmer, + Tube | Chorus | Orbitone | Flanger | Delay | Shimmer, + Tube | Phaser | Orbitone | Flanger | Delay | Shimmer, + Tube | Chorus | Phaser | Orbitone | Flanger | Delay | Shimmer, + -1 }; -#define Active(fxSwitch, FxID) (fxSwitch & FxID) == FxID +#define Active(fxSwitch, FxID) ((fxSwitch & FxID) == FxID) -void testFXRack(unsigned& step, unsigned fxSwitch) +string getScenarioName(int scenario) { - cout << "Step #" << (++step) << ": Intanciation FXRack" << endl; - FXRack *rack = new FXRack(44100.0f); + stringstream ss; - cout << "Step #" << (++step) << ": Test preparation" << endl; - rack->setEnable(true); + bool fxTube = Active(scenario, FXSitch::Tube); + bool fxChorus = Active(scenario, FXSitch::Chorus); + bool fxPhaser = Active(scenario, FXSitch::Phaser); + bool fxOrbitone = Active(scenario, FXSitch::Orbitone); + bool fxFlanger = Active(scenario, FXSitch::Flanger); + bool fxDelay = Active(scenario, FXSitch::Delay); + bool fxShimmer = Active(scenario, FXSitch::Shimmer); + bool first = true; + + ss << "[ "; + + if(fxTube) + { + if(!first) ss << ", "; + ss << "Tube"; + first = false; + } + + if(fxChorus) + { + if(!first) ss << ", "; + ss << "Chorus"; + first = false; + } + + if(fxPhaser) + { + if(!first) ss << ", "; + ss << "Phaser"; + first = false; + } + + if(fxOrbitone) + { + if(!first) ss << ", "; + ss << "Orbitone"; + first = false; + } + + if(fxFlanger) + { + if(!first) ss << ", "; + ss << "Flanger"; + first = false; + } + + if(fxDelay) + { + if(!first) ss << ", "; + ss << "Delay"; + first = false; + } + + if(fxShimmer) + { + if(!first) ss << ", "; + ss << "Shimmer"; + first = false; + } + + ss << " ]"; + + return ss.str(); +} + +void setupRack(unsigned& step, FXRack* rack) +{ + cout << "Step #" << (++step) << ": Set FXRack parameters" << endl; rack->setWetLevel(1.0f); - rack->getTube()->setEnable(Active(fxSwitch, FXSitch::Tube)); rack->getTube()->setWetLevel(0.25f); rack->getTube()->setOverdrive(0.25f); - rack->getChorus()->setEnable(Active(fxSwitch, FXSitch::Chorus)); rack->getChorus()->setWetLevel(0.5f); rack->getChorus()->setRate(0.4f); rack->getChorus()->setDepth(0.5f); - rack->getPhaser()->setEnable(Active(fxSwitch, FXSitch::Phaser)); rack->getPhaser()->setWetLevel(1.0f); rack->getPhaser()->setRate(0.1f); rack->getPhaser()->setDepth(1.0f); rack->getPhaser()->setFeedback(0.5f); rack->getPhaser()->setNbStages(12); - rack->getOrbitone()->setEnable(Active(fxSwitch, FXSitch::Orbitone)); rack->getOrbitone()->setWetLevel(0.8f); rack->getOrbitone()->setRate(0.4f); rack->getOrbitone()->setDepth(0.5f); - rack->getFlanger()->setEnable(Active(fxSwitch, FXSitch::Flanger)); rack->getFlanger()->setWetLevel(0.5f); rack->getFlanger()->setRate(0.03f); rack->getFlanger()->setDepth(0.75f); rack->getFlanger()->setFeedback(0.5f); - rack->getDelay()->setEnable(Active(fxSwitch, FXSitch::Delay)); rack->getDelay()->setWetLevel(0.6f); rack->getDelay()->setLeftDelayTime(0.075f); rack->getDelay()->setLeftDelayTime(0.05f); rack->getDelay()->setFeedbak(0.5f); - rack->getShimmerReverb()->setEnable(Active(fxSwitch, FXSitch::Shimmer)); rack->getShimmerReverb()->setWetLevel(0.5f); rack->getShimmerReverb()->setInputGain(0.35f); rack->getShimmerReverb()->setTime(0.89f); rack->getShimmerReverb()->setDiffusion(0.75f); rack->getShimmerReverb()->setLP(0.8f); +} + +void activateRackFXUnitScenario(unsigned& step, FXRack* rack, int scenario) +{ + rack->getTube()->setEnable(Active(scenario, FXSitch::Tube)); + rack->getChorus()->setEnable(Active(scenario, FXSitch::Chorus)); + rack->getPhaser()->setEnable(Active(scenario, FXSitch::Phaser)); + rack->getOrbitone()->setEnable(Active(scenario, FXSitch::Orbitone)); + rack->getFlanger()->setEnable(Active(scenario, FXSitch::Flanger)); + rack->getDelay()->setEnable(Active(scenario, FXSitch::Delay)); + rack->getShimmerReverb()->setEnable(Active(scenario, FXSitch::Shimmer)); +} + +void testReset(unsigned& step) +{ + FXRack *rack = new FXRack(44100.0f); + rack->setEnable(true); + + setupRack(step, rack); + + unsigned i = 0; + while(true) + { + int fxSwitch = scenarii[i]; + if(fxSwitch == -1) + { + break; + } + + activateRackFXUnitScenario(step, rack, fxSwitch); + + cout << "Step #" << (++step) << ": Reset for scenario #" << i << " => " << getScenarioName(fxSwitch) << ": "; + rack->reset(); + cout << "done" << endl; - unsigned nbRepeats = 4; + ++i; + } + + delete rack; +} +void testProcessing(unsigned& step) +{ + const unsigned nbRepeats = 1; unsigned size; float32_t** samples = readWaveFile("test.wav", size); float32_t* sampleOutL = new float32_t[size * nbRepeats]; @@ -190,46 +473,58 @@ void testFXRack(unsigned& step, unsigned fxSwitch) memset(sampleOutL, 0, size * nbRepeats * sizeof(float32_t)); memset(sampleOutR, 0, size * nbRepeats * sizeof(float32_t)); - for (unsigned i = 0; i < nbRepeats; ++i) + FXRack *rack = new FXRack(44100.0f); + rack->setEnable(true); + + setupRack(step, rack); + + unsigned i = 0; + while(true) { - rack->process(samples[0], samples[1], sampleOutL + i * size, sampleOutR + i * size, size); + int fxSwitch = scenarii[i]; + if(fxSwitch == -1) + { + break; + } + + activateRackFXUnitScenario(step, rack, fxSwitch); + + string name = getScenarioName(fxSwitch); + cout << "Step #" << (++step) << ": Processing for scenario #" << i << " => " << name << ": "; + + for (unsigned i = 0; i < nbRepeats; ++i) + { + rack->process(samples[0], samples[1], sampleOutL + i * size, sampleOutR + i * size, size); + } + + // stringstream ss; + // ss << "result " << name << ".wav"; + // saveWaveFile(ss.str(), sampleOutL, sampleOutR, nbRepeats * size, static_cast(FS), 16); + + cout << "done" << endl; + + ++i; } - saveWaveFile("result.wav", sampleOutL, sampleOutR, nbRepeats * size, static_cast(FS), 16); + delete rack; - delete[] sampleOutL; - delete[] sampleOutR; delete[] samples[0]; delete[] samples[1]; delete[] samples; - - cout << "Step #" << (++step) << ": Test cleanup" << endl; - delete rack; + delete[] sampleOutL; + delete[] sampleOutR; } int main() { unsigned step = 0; - // testLFO(step); - // testFlutter(step); - // testSVF(step); - // testFXRack(step, FXSitch::Tube); - // testFXRack(step, FXSitch::Flanger); - // testFXRack(step, FXSitch::Phaser); - // testFXRack(step, FXSitch::Chorus); - // testFXRack(step, FXSitch::Orbitone); - // testFXRack(step, FXSitch::Delay); - // testFXRack(step, FXSitch::Shimmer); - testFXRack( - step, - FXSitch::Tube | - FXSitch::Chorus | - FXSitch::Flanger | - FXSitch::Orbitone | - FXSitch::Phaser | - FXSitch::Delay | - FXSitch::Shimmer); + testLFO(step); + testFlutter(step); + testSVF(step); + testPlateReverb(step); + testReset(step); + testProcessing(step); return 0; }