CALF: updated up to commit 3889df5d1448faf5078b0a2bdd4c220823b82bf9
* Simplify exciter code. No functional change... I hope! * Work in progress on rotary speaker. May contain bugs. * Replace allpass vibrato in Calf Organ with a simulation of scanner vibrato. * Implement switchable vibrato type. * Initialise delta members in ramp classes.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -81,7 +81,7 @@ struct vintage_delay_metadata: public plugin_metadata<vintage_delay_metadata>
|
||||
struct rotary_speaker_metadata: public plugin_metadata<rotary_speaker_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,
|
||||
|
||||
@@ -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<float> crossover1l, crossover1r, crossover2l, crossover2r;
|
||||
dsp::biquad_d2<float> crossover1l, crossover1r, crossover2l, crossover2r, damper1l, damper1r;
|
||||
dsp::simple_delay<8, float> phaseshift;
|
||||
uint32_t srate;
|
||||
int vibrato_mode;
|
||||
|
||||
@@ -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<float> 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<float> filterL[2], filterR[2];
|
||||
adsr envs[EnvCount];
|
||||
dsp::inertia<dsp::linear_ramp> 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)
|
||||
|
||||
@@ -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"},
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user