diff --git a/src/common/dsp/oscillators/WavetableOscillator.cpp b/src/common/dsp/oscillators/WavetableOscillator.cpp index 9ee8469dbde..a17b238dc5e 100644 --- a/src/common/dsp/oscillators/WavetableOscillator.cpp +++ b/src/common/dsp/oscillators/WavetableOscillator.cpp @@ -43,6 +43,7 @@ WavetableOscillator::~WavetableOscillator() {} void WavetableOscillator::init(float pitch, bool is_display, bool nonzero_init_drift) { assert(storage); + readDeformType(); first_run = true; osc_out = _mm_set1_ps(0.f); osc_outR = _mm_set1_ps(0.f); @@ -86,15 +87,25 @@ void WavetableOscillator::init(float pitch, bool is_display, bool nonzero_init_d // rather than wavetable from first to second to last frame nointerp = !oscdata->p[wt_morph].extend_range; - float shape = limit_range( - l_shape.v + (localcopy[id_shape].f - unmodulatedLocalcopy[id_shape].f), 0.f, 1.f); + float shape; float intpart; + if (deformType == XT_134_EARLIER) + { + shape = oscdata->p[wt_morph].val.f; + } + else + { + shape = getMorph(); + } + shape *= ((float)oscdata->wt.n_tables - 1.f + nointerp) * 0.99999f; - tableipol = shape; - modff(shape, &intpart); + tableipol = deformType == XT_134_EARLIER ? shape : modff(shape, &intpart); tableid = limit_range((int)intpart, 0, std::max((int)oscdata->wt.n_tables - 2 + nointerp, 0)); last_tableipol = tableipol; last_tableid = tableid; + + selectDeform(); + hskew = 0.f; last_hskew = 0.f; @@ -194,10 +205,19 @@ void WavetableOscillator::convolute(int voice, bool FM, bool stereo) last_hskew = hskew; hskew = l_hskew.v; + int paddingLoop = 4; + int paddingEnd = 1; + + if (deformType == XT_134_EARLIER) + { + paddingLoop = 3 - nointerp; + paddingEnd = 2 - nointerp; + } + if (oscdata->wt.flags & wtf_is_sample) { tableid++; - if (tableid > oscdata->wt.n_tables - 4) + if (tableid > oscdata->wt.n_tables - paddingLoop) { if (sampleloop < 7) sampleloop--; @@ -208,14 +228,17 @@ void WavetableOscillator::convolute(int voice, bool FM, bool stereo) } else { - tableid = oscdata->wt.n_tables - 1; + tableid = oscdata->wt.n_tables - paddingEnd; oscstate[voice] = 100000000000.f; // rather large number return; } } - tableipol = tableid; - last_tableipol = tableid; + if (deformType != XT_134_EARLIER) + { + tableipol = tableid; + last_tableipol = tableid; + } } int ts = oscdata->wt.size; @@ -299,20 +322,8 @@ void WavetableOscillator::convolute(int voice, bool FM, bool stereo) state[voice] = state[voice] & (wtsize - 1); - float tblip_ipol = (1 - block_pos) * last_tableipol + block_pos * tableipol; float newlevel; - - // in Continuous Morph mode tblip_ipol gives us position between current and next frame - int tempTableId = floor(tblip_ipol); - float interpolationProc = (tblip_ipol - tempTableId) * (1 - nointerp); - - // that 1 - nointerp makes sure we don't read the table off memory, keeps us bounded - // and since it gets multiplied by lipol, in morph mode ends up being zero - no sweat! - newlevel = distort_level( - (oscdata->wt.TableF32WeakPointers[mipmap[voice]][tempTableId][state[voice]] * - (1.f - interpolationProc)) + - (oscdata->wt.TableF32WeakPointers[mipmap[voice]][tempTableId + 1 - nointerp][state[voice]] * - interpolationProc)); + newlevel = distort_level((this->*deformSelected)(block_pos, voice)); g = newlevel - last_level[voice]; last_level[voice] = newlevel; @@ -379,7 +390,16 @@ template void WavetableOscillator::update_lagvals() l_hskew.newValue(limit_range(localcopy[id_hskew].f, -1.f, 1.f)); float a = limit_range(localcopy[id_clip].f, 0.f, 1.f); l_clip.newValue(-8 * a * a * a); - l_shape.newValue(unmodulatedLocalcopy[id_shape].f); + + if (deformType == XT_134_EARLIER) + { + l_shape.newValue(localcopy[id_shape].f); + } + else + { + l_shape.newValue(unmodulatedLocalcopy[id_shape].f); + } + formant_t = max(0.f, localcopy[id_formant].f); float invt = min(1.0, (8.175798915 * storage->note_to_pitch_tuningctr(pitch_t)) * @@ -405,10 +425,108 @@ template void WavetableOscillator::update_lagvals() } } +void WavetableOscillator::readDeformType() +{ + deformType = (FeatureDeform)oscdata->p[wt_morph].deform_type; +} + +void WavetableOscillator::selectDeform() +{ + if (deformType == XT_134_EARLIER) + { + deformSelected = &WavetableOscillator::deformLegacy; + } + else + { + /* + switch to morph mode when frame skips are larger than x amount of frames in one block. + this will reduce noise from scrubbing over a short amount of time and also reduce noise from + adjusting values via GUI + */ + if (abs(last_tableipol - tableipol) > 5) + { + deformSelected = &WavetableOscillator::deformMorph; + } + else + { + deformSelected = &WavetableOscillator::deformContinuous; + } + } +} + +float WavetableOscillator::getMorph() +{ + + float shape; + if (deformType == XT_134_EARLIER) + { + + shape = l_shape.v; + } + else + { + shape = limit_range(l_shape.v + (localcopy[id_shape].f - unmodulatedLocalcopy[id_shape].f), + 0.f, 1.f); + } + return shape; +} +/* + Interpolation modes +*/ +float WavetableOscillator::deformLegacy(float block_pos, int voice) +{ + float tblip_ipol = (1 - block_pos) * last_tableipol + block_pos * tableipol; + + // in Continuous Morph mode tblip_ipol gives us position between current and next frame + // when not in Continuous Morph mode, we don't interpolate so this position should be + // zero + float lipol = (1 - nointerp) * tblip_ipol; + + // that 1 - nointerp makes sure we don't read the table off memory, keeps us bounded + // and since it gets multiplied by lipol, in morph mode ends up being zero - no sweat! + return (oscdata->wt.TableF32WeakPointers[mipmap[voice]][tableid][state[voice]] * + (1.f - lipol)) + + (oscdata->wt.TableF32WeakPointers[mipmap[voice]][tableid + 1 - nointerp][state[voice]] * + lipol); +} + +float WavetableOscillator::deformContinuous(float block_pos, int voice) +{ + + float tblip_ipol = (1 - block_pos) * last_tableipol + block_pos * tableipol; + + int tempTableId = floor(tblip_ipol); + float interpolationProc = (tblip_ipol - tempTableId) * (1 - nointerp); + + return (oscdata->wt.TableF32WeakPointers[mipmap[voice]][tempTableId][state[voice]] * + (1.f - interpolationProc)) + + (oscdata->wt + .TableF32WeakPointers[mipmap[voice]][tempTableId + 1 - nointerp][state[voice]] * + interpolationProc); +} + +float WavetableOscillator::deformMorph(float block_pos, int voice) +{ + + float frames[2] = {(last_tableipol), (tableipol)}; + for (int i = 0; i < 2; i++) + { + int actualFrame = floor(frames[i]); + float proc = frames[i] - floor(frames[i]); + + int d = min((int)(actualFrame + 1), (int)(oscdata->wt.n_tables - 1)); + frames[i] = oscdata->wt.TableF32WeakPointers[mipmap[voice]][actualFrame][state[voice]] * + (1.f - proc) + + oscdata->wt.TableF32WeakPointers[mipmap[voice]][d][state[voice]] * (proc); + } + + return frames[0] * (1.f - block_pos) + frames[1] * block_pos; +} + void WavetableOscillator::process_block(float pitch0, float drift, bool stereo, bool FM, float depth) { - auto fd = (FeatureDeform)oscdata->p[wt_morph].deform_type; + #if 0 if (fd == XT_134_EARLIER) { @@ -420,6 +538,8 @@ void WavetableOscillator::process_block(float pitch0, float drift, bool stereo, } #endif + readDeformType(); + pitch_last = pitch_t; pitch_t = min(148.f, pitch0); pitchmult_inv = @@ -446,43 +566,57 @@ void WavetableOscillator::process_block(float pitch0, float drift, bool stereo, } else if (oscdata->wt.flags & wtf_is_sample) { - tableipol = tableid; - last_tableipol = tableid; + if (deformType == XT_134_EARLIER) + { + tableipol = 0.f; + last_tableipol = 0.f; + } + else + { + tableipol = tableid; + last_tableipol = tableid; + } } else { last_tableipol = tableipol; last_tableid = tableid; - float shape = limit_range( - l_shape.v + (localcopy[id_shape].f - unmodulatedLocalcopy[id_shape].f), 0.f, 1.f); + float shape; float intpart; + + shape = getMorph(); + shape *= ((float)oscdata->wt.n_tables - 1.f + nointerp) * 0.99999f; - tableipol = shape; + tableipol = deformType == XT_134_EARLIER ? modff(shape, &intpart) : shape; modff(shape, &intpart); tableid = limit_range((int)intpart, 0, (int)oscdata->wt.n_tables - 2 + nointerp); - /* - if (tableid > last_tableid) + + selectDeform(); + + if (deformType == XT_134_EARLIER) { - if (last_tableipol != 1.f) + if (tableid > last_tableid) { - tableid = last_tableid; - tableipol = 1.f; + if (last_tableipol != 1.f) + { + tableid = last_tableid; + tableipol = 1.f; + } + else + last_tableipol = 0.0f; } - else - last_tableipol = 0.0f; - } - else if (tableid < last_tableid) - { - if (last_tableipol != 0.f) + else if (tableid < last_tableid) { - tableid = last_tableid; - tableipol = 0.f; + if (last_tableipol != 0.f) + { + tableid = last_tableid; + tableipol = 0.f; + } + else + last_tableipol = 1.0f; } - else - last_tableipol = 1.0f; } - */ } if (FM) diff --git a/src/common/dsp/oscillators/WavetableOscillator.h b/src/common/dsp/oscillators/WavetableOscillator.h index 4fcb72e7e16..a3b11192575 100644 --- a/src/common/dsp/oscillators/WavetableOscillator.h +++ b/src/common/dsp/oscillators/WavetableOscillator.h @@ -65,6 +65,14 @@ class WavetableOscillator : public AbstractBlitOscillator void convolute(int voice, bool FM, bool stereo); template void update_lagvals(); inline float distort_level(float); + void readDeformType(); + void selectDeform(); + float getMorph(); + float deformLegacy(float, int); + float deformContinuous(float, int); + float deformMorph(float, int); + + float (WavetableOscillator::*deformSelected)(float, int); bool first_run; float oscpitch[MAX_UNISON]; float dc, dc_uni[MAX_UNISON], last_level[MAX_UNISON]; @@ -80,6 +88,7 @@ class WavetableOscillator : public AbstractBlitOscillator float FMmul_inv; int sampleloop; pdata *unmodulatedLocalcopy; + FeatureDeform deformType; }; #endif // SURGE_SRC_COMMON_DSP_OSCILLATORS_WAVETABLEOSCILLATOR_H