Skip to content

Commit

Permalink
Shepard sync (#127)
Browse files Browse the repository at this point in the history
* checkpoint

* checkpoint 2

* blang-format
  • Loading branch information
Andreya-Autumn authored Sep 6, 2024
1 parent 0a7d9d5 commit 60f6799
Showing 1 changed file with 98 additions and 30 deletions.
128 changes: 98 additions & 30 deletions include/sst/voice-effects/modulation/ShepardPhaser.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "sst/basic-blocks/mechanics/block-ops.h"
#include "sst/basic-blocks/modulators/SimpleLFO.h"
#include "sst/basic-blocks/dsp/RNG.h"

namespace sst::voice_effects::modulation
{
Expand All @@ -38,6 +39,8 @@ template <typename VFXConfig> struct ShepardPhaser : core::VoiceEffectTemplateBa
static constexpr int numFloatParams{4};
static constexpr int numIntParams{2};

basic_blocks::dsp::RNG rng;

enum FloatParams
{
fpResonance,
Expand Down Expand Up @@ -65,7 +68,7 @@ template <typename VFXConfig> struct ShepardPhaser : core::VoiceEffectTemplateBa
case fpResonance:
return pmd().asPercent().withDefault(1.0f).withName("Resonance");
case fpRate:
return pmd().asLfoRate(-7, 0).withDefault(-3).withName("Rate");
return pmd().asLfoRate(-7, 3).withDefault(0).withName("Rate");
case fpStartFreq:
return pmd().asAudibleFrequency().withName("Start Freq").withDefault(-30);
case fpEndFreq:
Expand Down Expand Up @@ -113,25 +116,101 @@ template <typename VFXConfig> struct ShepardPhaser : core::VoiceEffectTemplateBa
void processStereo(float *datainL, float *datainR, float *dataoutL, float *dataoutR,
float pitch)
{
auto lfoRate = this->getFloatParam(fpRate);
auto range = this->getFloatParam(fpEndFreq) - this->getFloatParam(fpStartFreq);
auto res = std::clamp(this->getFloatParam(fpResonance) * .2f + .8f, 0.f, 1.0f);
auto stereo = this->getIntParam(ipStereo);
auto range = std::clamp(this->getFloatParam(fpEndFreq), -60.f, 70.f) -
std::clamp(this->getFloatParam(fpStartFreq), -60.f, 70.f);
auto res = std::clamp(this->getFloatParam(fpResonance) * .08f + .9f, 0.f, .98f);
int peaks = this->getIntParam(ipPeaks);

namespace mech = sst::basic_blocks::mechanics;
if (peaks != priorPeaks)
{
logOfPeaks = std::log2f(peaks);
priorPeaks = peaks;
}
auto lfoRate = this->getFloatParam(fpRate) - logOfPeaks;

if (isFirst)
{
phasor.attack(lfo_t::RAMP);
phasor.applyPhaseOffset(rng.unif01());
isFirst = false;
}
phasor.process_block(lfoRate, 0.f, lfo_t::RAMP);
auto phasorValue = phasor.lastTarget * .5f + .5f;

namespace mech = sst::basic_blocks::mechanics;
mech::clear_block<VFXConfig::blockSize>(dataoutL);
mech::clear_block<VFXConfig::blockSize>(dataoutR);

for (int i = 0; i < peaks; ++i)
{
auto offset = static_cast<double>(i) / static_cast<double>(peaks);
auto halfway = 0.5 / static_cast<double>(peaks);
auto iPhaseL = std::fmod(phasorValue + offset, 1.0);
auto iPhaseR = !stereo ? iPhaseL : std::fmod(phasorValue + offset + halfway, 1.0);

auto iTriL = triangle(iPhaseL);
auto iTriR = triangle(iPhaseR);

auto freqL = 440.f * this->note_to_pitch_ignoring_tuning(
this->getFloatParam(fpStartFreq) + (range * iPhaseL));
auto freqR = 440.f * this->note_to_pitch_ignoring_tuning(
this->getFloatParam(fpStartFreq) + (range * iPhaseR));

filters[i].template setCoeffForBlock<VFXConfig::blockSize>(
sst::filters::CytomicSVF::Mode::BP, freqL, freqR, res, res,
this->getSampleRateInv(), 1.f, 1.f);

float tmpL alignas(16)[VFXConfig::blockSize];
float tmpR alignas(16)[VFXConfig::blockSize];
mech::copy_from_to<VFXConfig::blockSize>(datainL, tmpL);
mech::copy_from_to<VFXConfig::blockSize>(datainR, tmpR);

for (int k = 0; k < VFXConfig::blockSize; ++k)
{
filters[i].processBlockStep(tmpL[k], tmpR[k]);
}

if (!stereo)
{
lipolLevel[i].set_target(iTriL * iTriL * iTriL);
lipolLevel[i].multiply_2_blocks(tmpL, tmpR);
}
else
{
lipolLevel[i].set_target(iTriL * iTriL * iTriL);
lipolLevel[i].multiply_block(tmpL);
lipolLevel[i + 12].set_target(iTriR * iTriR * iTriR);
lipolLevel[i + 12].multiply_block(tmpR);
}

mech::scale_accumulate_from_to<VFXConfig::blockSize>(tmpL, tmpR, 0.5f, dataoutL,
dataoutR);
}
}

void processMonoToMono(float *datainL, float *dataoutL, float pitch)
{
auto range = std::clamp(this->getFloatParam(fpEndFreq), -60.f, 70.f) -
std::clamp(this->getFloatParam(fpStartFreq), -60.f, 70.f);
auto res = std::clamp(this->getFloatParam(fpResonance) * .08f + .9f, 0.f, .98f);
int peaks = this->getIntParam(ipPeaks);
if (peaks != priorPeaks)
{
logOfPeaks = std::log2f(peaks);
priorPeaks = peaks;
}
auto lfoRate = this->getFloatParam(fpRate) - logOfPeaks;

if (isFirst)
{
phasor.applyPhaseOffset(rng.unif01());
isFirst = false;
}
phasor.process_block(lfoRate, 0.f, lfo_t::RAMP);
auto phasorValue = phasor.lastTarget * .5f + .5f;

namespace mech = sst::basic_blocks::mechanics;
mech::clear_block<VFXConfig::blockSize>(dataoutL);

for (int i = 0; i < peaks; ++i)
{

Expand All @@ -145,50 +224,39 @@ template <typename VFXConfig> struct ShepardPhaser : core::VoiceEffectTemplateBa
auto freqMod = this->getFloatParam(fpStartFreq) + (range * iPhase);
auto freq = 440.f * this->note_to_pitch_ignoring_tuning(freqMod);
filters[i].template setCoeffForBlock<VFXConfig::blockSize>(
sst::filters::CytomicSVF::Mode::BP, freq, freq, res, res, this->getSampleRateInv(),
1.f, 1.f);
sst::filters::CytomicSVF::Mode::BP, freq, res, this->getSampleRateInv(), 1.f);

float tmpL alignas(16)[VFXConfig::blockSize];
float tmpR alignas(16)[VFXConfig::blockSize];
mech::copy_from_to<VFXConfig::blockSize>(datainL, tmpL);
mech::copy_from_to<VFXConfig::blockSize>(datainR, tmpR);
float tmp alignas(16)[VFXConfig::blockSize];
mech::copy_from_to<VFXConfig::blockSize>(datainL, tmp);

for (int k = 0; k < VFXConfig::blockSize; ++k)
{
filters[i].processBlockStep(tmpL[k], tmpR[k]);
softClip(tmpL[k], tmpR[k]);
filters[i].processBlockStep(tmp[k]);
}

lipolLevel[i].set_target(iTri * iTri * iTri);
lipolLevel[i].multiply_2_blocks(tmpL, tmpR);
lipolLevel[i].multiply_block(tmp);

mech::scale_accumulate_from_to<VFXConfig::blockSize>(tmpL, tmpR, 0.3333f, dataoutL,
dataoutR);
mech::scale_accumulate_from_to<VFXConfig::blockSize>(tmp, 0.5f, dataoutL);
}
}

void softClip(float &L, float &R)
void processMonoToStereo(float *datainL, float *dataoutL, float *dataoutR, float pitch)
{
L = std::clamp(L, -1.5f, 1.5f);
L = L - 4.0 / 27.0 * L * L * L;

R = std::clamp(R, -1.5f, 1.5f);
R = R - 4.0 / 27.0 * R * R * R;
processStereo(datainL, datainL, dataoutL, dataoutR, pitch);
}

void softClip(float &C)
{
C = std::clamp(C, -1.5f, 1.5f);
C = C - 4.0 / 27.0 * C * C * C;
}
bool getMonoToStereoSetting() const { return this->getIntParam(ipStereo) > 0; }

protected:
std::array<float, numFloatParams> mLastParam{};
std::array<int, numIntParams> mLastIParam{};

std::array<sst::filters::CytomicSVF, 12> filters;

sst::basic_blocks::dsp::lipol_sse<VFXConfig::blockSize, true> lipolLevel[12];
sst::basic_blocks::dsp::lipol_sse<VFXConfig::blockSize, true> lipolLevel[24];
float logOfPeaks{0.f};
int priorPeaks{0};
bool isFirst{true};
};
} // namespace sst::voice_effects::modulation
Expand Down

0 comments on commit 60f6799

Please sign in to comment.