diff --git a/plugins/ladspa_effect/calf/src/calf/inertia.h b/plugins/ladspa_effect/calf/src/calf/inertia.h index d6bbd297a..70ba9ede1 100644 --- a/plugins/ladspa_effect/calf/src/calf/inertia.h +++ b/plugins/ladspa_effect/calf/src/calf/inertia.h @@ -35,6 +35,7 @@ public: linear_ramp(int _ramp_len) { ramp_len = _ramp_len; mul = (float)(1.0f / ramp_len); + delta = 0.f; } /// Change ramp length inline void set_length(int _ramp_len) { @@ -71,6 +72,7 @@ public: exponential_ramp(int _ramp_len) { ramp_len = _ramp_len; root = (float)(1.0f / ramp_len); + delta = 1.0; } inline void set_length(int _ramp_len) { ramp_len = _ramp_len; diff --git a/plugins/ladspa_effect/calf/src/calf/metadata.h b/plugins/ladspa_effect/calf/src/calf/metadata.h index 75505e4e1..d49594e8e 100644 --- a/plugins/ladspa_effect/calf/src/calf/metadata.h +++ b/plugins/ladspa_effect/calf/src/calf/metadata.h @@ -81,7 +81,7 @@ struct vintage_delay_metadata: public plugin_metadata struct rotary_speaker_metadata: public plugin_metadata { public: - enum { par_speed, par_spacing, par_shift, par_moddepth, par_treblespeed, par_bassspeed, par_micdistance, par_reflection, par_meter_l, par_meter_h, param_count }; + enum { par_speed, par_spacing, par_shift, par_moddepth, par_treblespeed, par_bassspeed, par_micdistance, par_reflection, par_am_depth, par_test, par_meter_l, par_meter_h, param_count }; enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = false, rt_capable = true }; PLUGIN_NAME_ID_LABEL("rotary_speaker", "rotaryspeaker", "Rotary Speaker") }; @@ -347,7 +347,7 @@ struct organ_enums par_eg1attack, par_eg1decay, par_eg1sustain, par_eg1release, par_eg1velscl, par_eg1ampctl, par_eg2attack, par_eg2decay, par_eg2sustain, par_eg2release, par_eg2velscl, par_eg2ampctl, par_eg3attack, par_eg3decay, par_eg3sustain, par_eg3release, par_eg3velscl, par_eg3ampctl, - par_lforate, par_lfoamt, par_lfowet, par_lfophase, par_lfomode, + par_lforate, par_lfoamt, par_lfowet, par_lfophase, par_lfomode, par_lfotype, par_transpose, par_detune, par_polyphony, par_quadenv, @@ -384,6 +384,14 @@ struct organ_enums ampctl_all, ampctl_count }; + enum { + lfotype_allpass = 0, + lfotype_cv1, + lfotype_cv2, + lfotype_cv3, + lfotype_cvfull, + lfotype_count + }; enum { lfomode_off = 0, lfomode_direct, diff --git a/plugins/ladspa_effect/calf/src/calf/modules_mod.h b/plugins/ladspa_effect/calf/src/calf/modules_mod.h index 6b57b0b8a..bee6d3777 100644 --- a/plugins/ladspa_effect/calf/src/calf/modules_mod.h +++ b/plugins/ladspa_effect/calf/src/calf/modules_mod.h @@ -91,7 +91,7 @@ public: /// Current phases and phase deltas for bass and treble rotors uint32_t phase_l, dphase_l, phase_h, dphase_h; dsp::simple_delay<1024, float> delay; - dsp::biquad_d2 crossover1l, crossover1r, crossover2l, crossover2r; + dsp::biquad_d2 crossover1l, crossover1r, crossover2l, crossover2r, damper1l, damper1r; dsp::simple_delay<8, float> phaseshift; uint32_t srate; int vibrato_mode; diff --git a/plugins/ladspa_effect/calf/src/calf/organ.h b/plugins/ladspa_effect/calf/src/calf/organ.h index ac415994c..fe830b179 100644 --- a/plugins/ladspa_effect/calf/src/calf/organ.h +++ b/plugins/ladspa_effect/calf/src/calf/organ.h @@ -82,6 +82,7 @@ struct organ_parameters { float lfo_wet; float lfo_phase; float lfo_mode; + float lfo_type; float global_transpose; float global_detune; @@ -174,6 +175,7 @@ public: void perc_reset(); }; +/// A simple (and bad) simulation of scanner vibrato based on a series of modulated allpass filters class organ_vibrato { protected: @@ -186,6 +188,31 @@ public: void process(organ_parameters *parameters, float (*data)[2], unsigned int len, float sample_rate); }; +/// A more sophisticated simulation of scanner vibrato. Simulates a line box +/// and an interpolating scanner. The line box is a series of 18 2nd order +/// lowpass filters with cutoff frequency ~4kHz, with loss compensation. +/// The interpolating scanner uses linear interpolation to "slide" between +/// selected outputs of the line box. +/// +/// @note +/// This is a true CPU hog, and it should be optimised some day. +/// @note +/// The line box is mono. 36 lowpass filters might be an overkill. +/// @note +/// See also: http://www.jhaible.de/interpolating_scanner_and_scanvib/jh_interpolating_scanner_and_scanvib.html +/// (though it's a very loose adaptation of that version) +class scanner_vibrato +{ +protected: + enum { ScannerSize = 18 }; + float lfo_phase; + dsp::biquad_d2 scanner[ScannerSize]; + organ_vibrato legacy; +public: + void reset(); + void process(organ_parameters *parameters, float (*data)[2], unsigned int len, float sample_rate); +}; + class organ_voice: public dsp::voice, public organ_voice_base { protected: enum { Channels = 2, BlockSize = 64, EnvCount = organ_parameters::EnvCount, FilterCount = organ_parameters::FilterCount }; @@ -197,7 +224,7 @@ protected: dsp::biquad_d1 filterL[2], filterR[2]; adsr envs[EnvCount]; dsp::inertia expression; - organ_vibrato vibrato; + scanner_vibrato vibrato; float velocity; bool perc_released; /// The envelopes have ended and the voice is in final fadeout stage @@ -260,7 +287,7 @@ public: struct drawbar_organ: public dsp::basic_synth, public calf_plugins::organ_enums { organ_parameters *parameters; percussion_voice percussion; - organ_vibrato global_vibrato; + scanner_vibrato global_vibrato; two_band_eq eq_l, eq_r; drawbar_organ(organ_parameters *_parameters) diff --git a/plugins/ladspa_effect/calf/src/metadata.cpp b/plugins/ladspa_effect/calf/src/metadata.cpp index 5bd37eb4d..f376d7779 100644 --- a/plugins/ladspa_effect/calf/src/metadata.cpp +++ b/plugins/ladspa_effect/calf/src/metadata.cpp @@ -181,11 +181,13 @@ CALF_PORT_PROPS(rotary_speaker) = { { 5, 0, 5, 1.01, PF_ENUM | PF_CTL_COMBO, rotary_speaker_speed_names, "vib_speed", "Speed Mode" }, { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "spacing", "Tap Spacing" }, { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "shift", "Tap Offset" }, - { 0.10, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mod_depth", "Mod Depth" }, + { 0.45, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mod_depth", "FM Depth" }, { 36, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "treble_speed", "Treble Motor" }, { 30, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "bass_speed", "Bass Motor" }, { 0.7, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mic_distance", "Mic Distance" }, { 0.3, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "reflection", "Reflection" }, + { 0.45, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "am_depth", "AM Depth" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "test", "Test" }, { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_l", "Low rotor" }, { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_h", "High rotor" }, {} @@ -849,6 +851,8 @@ const char *organ_ampctl_names[] = { "None", "Direct", "Flt 1", "Flt 2", "All" const char *organ_vibrato_mode_names[] = { "None", "Direct", "Flt 1", "Flt 2", "Voice", "Global" }; +const char *organ_vibrato_type_names[] = { "Allpass", "Scanner (V1/C1)", "Scanner (V2/C2)", "Scanner (V3/C3)", "Scanner (Full)" }; + const char *organ_filter_type_names[] = { "12dB/oct LP", "12dB/oct HP" }; const char *organ_filter_send_names[] = { "Output", "Filter 2" }; @@ -926,7 +930,7 @@ CALF_PORT_PROPS(organ) = { { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing8", "Routing 8" }, { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing9", "Routing 9" }, - { 96, 0, 127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" }, + { 96 + 12, 0, 127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" }, { 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_decay", "P: Carrier Decay" }, { 0.25, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "perc_level", "P: Level" }, @@ -985,11 +989,12 @@ CALF_PORT_PROPS(organ) = { { 0, 0, organ_enums::ampctl_count - 1, 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg3_amp_ctl", "EG3 To Amp"}, - { 6.6, 0.01, 80, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "vib_rate", "Vib Rate" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_amt", "Vib Mod Amt" }, + { 6.6, 0.01, 240, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "vib_rate", "Vib Rate" }, + { 1.0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_amt", "Vib Mod Amt" }, { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_wet", "Vib Wet" }, { 180, 0, 360, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vib_phase", "Vib Stereo" }, - { organ_enums::lfomode_global, 0, organ_enums::lfomode_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_vibrato_mode_names, "vib_mode", "Vib Mode" }, + { organ_enums::lfomode_global, 0, organ_enums::lfomode_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_vibrato_mode_names, "vib_mode", "Vib Mode" }, + { organ_enums::lfotype_cv3, 0, organ_enums::lfotype_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_vibrato_type_names, "vib_type", "Vib Type" }, // { 0, 0, organ_enums::ampctl_count - 1, // 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "vel_amp_ctl", "Vel To Amp"}, diff --git a/plugins/ladspa_effect/calf/src/modules_dist.cpp b/plugins/ladspa_effect/calf/src/modules_dist.cpp index 95c145a19..049e94818 100644 --- a/plugins/ladspa_effect/calf/src/modules_dist.cpp +++ b/plugins/ladspa_effect/calf/src/modules_dist.cpp @@ -333,6 +333,8 @@ uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uin meter_drive = 0.f; + float in2out = *params[param_listen] > 0.f ? 0.f : 1.f; + // process while(offset < numsamples) { // cycle through samples @@ -371,40 +373,25 @@ uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uin // all post filters in chain proc[i] = hp[i][2].process(hp[i][3].process(proc[i])); } + maxDrive = dist[0].get_distortion_level() * *params[param_amount]; if(in_count > 1 && out_count > 1) { + maxDrive = std::max(maxDrive, dist[1].get_distortion_level() * *params[param_amount]); // full stereo - if(*params[param_listen] > 0.f) - out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; - else - out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out]; + out[1] = (proc[1] * *params[param_amount] + in2out * in[1]) * *params[param_level_out]; outs[0][offset] = out[0]; - if(*params[param_listen] > 0.f) - out[1] = proc[1] * *params[param_amount] * *params[param_level_out]; - else - out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out]; outs[1][offset] = out[1]; - maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount], - dist[1].get_distortion_level() * *params[param_amount]); } else if(out_count > 1) { // mono -> pseudo stereo - if(*params[param_listen] > 0.f) - out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; - else - out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + out[1] = out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out]; outs[0][offset] = out[0]; - out[1] = out[0]; outs[1][offset] = out[1]; - maxDrive = dist[0].get_distortion_level() * *params[param_amount]; } else { // stereo -> mono // or full mono - if(*params[param_listen] > 0.f) - out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; - else - out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out]; outs[0][offset] = out[0]; - maxDrive = dist[0].get_distortion_level() * *params[param_amount]; } // set up in / out meters diff --git a/plugins/ladspa_effect/calf/src/modules_mod.cpp b/plugins/ladspa_effect/calf/src/modules_mod.cpp index 063027ef0..91c50df70 100644 --- a/plugins/ladspa_effect/calf/src/modules_mod.cpp +++ b/plugins/ladspa_effect/calf/src/modules_mod.cpp @@ -321,14 +321,27 @@ inline bool rotary_speaker_audio_module::incr_towards(float &aspeed, float raspe uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { + if (true) + { + crossover2l.set_bp_rbj(2000.f, 0.7, (float)srate); + crossover2r.copy_coeffs(crossover2l); + damper1l.set_bp_rbj(1000.f*pow(4.0, *params[par_test]), 0.7, (float)srate); + damper1r.copy_coeffs(damper1l); + } + else + { + crossover2l.set_hp_rbj(800.f, 0.7, (float)srate); + crossover2r.copy_coeffs(crossover2l); + } int shift = (int)(300000 * (*params[par_shift])), pdelta = (int)(300000 * (*params[par_spacing])); int md = (int)(100 * (*params[par_moddepth])); float mix = 0.5 * (1.0 - *params[par_micdistance]); float mix2 = *params[par_reflection]; float mix3 = mix2 * mix2; + float am_depth = *params[par_am_depth]; for (unsigned int i = 0; i < nsamples; i++) { float in_l = ins[0][i + offset], in_r = ins[1][i + offset]; - float in_mono = 0.5f * (in_l + in_r); + float in_mono = atan(0.5f * (in_l + in_r)); int xl = pseudo_sine_scl(phase_l), yl = pseudo_sine_scl(phase_l + 0x40000000); int xh = pseudo_sine_scl(phase_h), yh = pseudo_sine_scl(phase_h + 0x40000000); @@ -337,11 +350,13 @@ uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples meter_h = xh; // float out_hi_l = in_mono - delay.get_interp_1616(shift + md * xh) + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) - delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); // float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - delay.get_interp_1616(shift + pdelta + md * xh) + delay.get_interp_1616(shift + pdelta + pdelta + md * yh); - float out_hi_l = in_mono + delay.get_interp_1616(shift + md * xh) - mix2 * delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) + mix3 * delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); - float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - mix2 * delay.get_interp_1616(shift + pdelta + md * xh) + mix3 * delay.get_interp_1616(shift + pdelta + pdelta + md * yh); + float fm_hi_l = delay.get_interp_1616(shift + md * xh) - mix2 * delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) + mix3 * delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); + float fm_hi_r = delay.get_interp_1616(shift + md * 65536 - md * yh) - mix2 * delay.get_interp_1616(shift + pdelta + md * xh) + mix3 * delay.get_interp_1616(shift + pdelta + pdelta + md * yh); + float out_hi_l = lerp(in_mono, damper1l.process(fm_hi_l), lerp(0.5, xh * 1.0 / 65536.0, am_depth)); + float out_hi_r = lerp(in_mono, damper1r.process(fm_hi_r), lerp(0.5, yh * 1.0 / 65536.0, am_depth)); - float out_lo_l = in_mono + delay.get_interp_1616(shift + md * xl); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl); - float out_lo_r = in_mono + delay.get_interp_1616(shift + md * yl); // - delay.get_interp_1616(shift + pdelta + md * yl); + float out_lo_l = lerp(in_mono, delay.get_interp_1616(shift + (md * xl >> 2)), lerp(0.5, yl * 1.0 / 65536.0, am_depth)); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl); + float out_lo_r = lerp(in_mono, delay.get_interp_1616(shift + (md * yl >> 2)), lerp(0.5, xl * 1.0 / 65536.0, am_depth)); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl); out_hi_l = crossover2l.process(out_hi_l); // sanitize(out_hi_l); out_hi_r = crossover2r.process(out_hi_r); // sanitize(out_hi_r); @@ -354,8 +369,8 @@ uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples float mic_l = out_l + mix * (out_r - out_l); float mic_r = out_r + mix * (out_l - out_r); - outs[0][i + offset] = mic_l * 0.5f; - outs[1][i + offset] = mic_r * 0.5f; + outs[0][i + offset] = mic_l; + outs[1][i + offset] = mic_r; delay.put(in_mono); phase_l += dphase_l; phase_h += dphase_h; @@ -364,6 +379,8 @@ uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples crossover1r.sanitize(); crossover2l.sanitize(); crossover2r.sanitize(); + damper1l.sanitize(); + damper1r.sanitize(); float delta = nsamples * 1.0 / srate; if (vibrato_mode == 5) update_speed_manual(delta); diff --git a/plugins/ladspa_effect/calf/src/organ.cpp b/plugins/ladspa_effect/calf/src/organ.cpp index 343560760..fad15edb5 100644 --- a/plugins/ladspa_effect/calf/src/organ.cpp +++ b/plugins/ladspa_effect/calf/src/organ.cpp @@ -611,6 +611,85 @@ void organ_vibrato::process(organ_parameters *parameters, float (*data)[2], unsi } } +void scanner_vibrato::reset() +{ + legacy.reset(); + for (int i = 0; i < ScannerSize; i++) + scanner[i].reset(); + lfo_phase = 0.f; +} + +void scanner_vibrato::process(organ_parameters *parameters, float (*data)[2], unsigned int len, float sample_rate) +{ + if (!len) + return; + + int vtype = (int)parameters->lfo_type; + if (!vtype || vtype > organ_enums::lfotype_cvfull) + { + legacy.process(parameters, data, len, sample_rate); + return; + } + + // I bet the original components of the line box had some tolerance, + // hence two different values of cutoff frequency + scanner[0].set_lp_rbj(4000, 0.707, sample_rate); + scanner[1].set_lp_rbj(4200, 0.707, sample_rate); + for (int t = 2; t < ScannerSize; t ++) + { + scanner[t].copy_coeffs(scanner[t & 1]); + } + + float lfo_phase2 = lfo_phase + parameters->lfo_phase * (1.0 / 360.0); + if (lfo_phase2 >= 1.0) + lfo_phase2 -= 1.0; + float vib_wet = parameters->lfo_wet; + float dphase = parameters->lfo_rate / sample_rate; + static const int v1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8 }; + static const int v2[] = { 0, 1, 2, 4, 6, 8, 9, 10, 12 }; + static const int v3[] = { 0, 1, 3, 6, 11, 12, 15, 17, 18, 18, 18 }; + static const int vfull[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18 }; + static const int *vtypes[] = { NULL, v1, v2, v3, vfull }; + const int *vib = vtypes[vtype]; + + float vibamt = 8 * parameters->lfo_amt; + if (vtype == organ_enums::lfotype_cvfull) + vibamt = 17 * parameters->lfo_amt; + for (unsigned int i = 0; i < len; i++) + { + float line[ScannerSize + 1]; + float v0 = (data[i][0] + data[i][1]) * 0.5; + + line[0] = v0; + for (int t = 0; t < ScannerSize; t++) + line[t + 1] = scanner[t].process(line[t]) * 1.03; + + float lfo1 = lfo_phase < 0.5 ? 2 * lfo_phase : 2 - 2 * lfo_phase; + float lfo2 = lfo_phase2 < 0.5 ? 2 * lfo_phase2 : 2 - 2 * lfo_phase2; + + float pos = vibamt * lfo1; + int ipos = (int)pos; + float vl = lerp(line[vib[ipos]], line[vib[ipos + 1]], pos - ipos); + + pos = vibamt * lfo2; + ipos = (int)pos; + float vr = lerp(line[vib[ipos]], line[vib[ipos + 1]], pos - ipos); + + lfo_phase += dphase; + if (lfo_phase >= 1.0) + lfo_phase -= 1.0; + lfo_phase2 += dphase; + if (lfo_phase2 >= 1.0) + lfo_phase2 -= 1.0; + + data[i][0] += (vl - v0) * vib_wet; + data[i][1] += (vr - v0) * vib_wet; + } + for (int t = 0; t < ScannerSize; t++) + { + scanner[t].sanitize(); + } +} ////////////////////////////////////////////////////////////////////////////////////////////////////// void organ_voice::update_pitch()