Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/synth/mono_values.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ struct MonoValues

SRProvider sr;

// Per-engine-block hoists of mono unison params, refreshed by Synth::processInternal
// so each Voice::renderBlock can derive uniRatioMul / uniPanShift without per-voice
// table lookups. unisonSpreadFactorMinus1 = 2^unisonSpread.value - 1.
float unisonSpreadFactorMinus1{0.f};
float unisonPanScalar{0.f};

float audioInBlock alignas(16)[blockSize]{}; // engine-rate audio in, mono mix
};
}; // namespace baconpaul::six_sines
Expand Down
6 changes: 6 additions & 0 deletions src/synth/synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ template <bool multiOut> void Synth::processInternal(const clap_output_events_t
loops++;
lagHandler.process();

// Hoist mono unison params so per-voice renderBlock derives uniRatioMul / uniPanShift
// from the smoothed scalars without each voice repeating the twoToTheX lookup.
monoValues.unisonSpreadFactorMinus1 =
monoValues.twoToTheX.twoToThe(patch.output.unisonSpread.value) - 1.f;
monoValues.unisonPanScalar = patch.output.unisonPan.value;

auto op1IsAudioIn =
((int)std::round(patch.sourceNodes[0].waveForm.value) == SinTable::AUDIO_IN);
if (audioInResampler && op1IsAudioIn)
Expand Down
37 changes: 11 additions & 26 deletions src/synth/synth.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,33 +158,18 @@ struct Synth
int made{0};

int lastStart{0};
auto usp = synth.patch.output.unisonSpread.value;
usp = synth.monoValues.twoToTheX.twoToThe(usp);
float uniVal[5]{1.0};
float uniPan[5]{0.0};
float uniScale[5]{0.0};
assert(ct <= 5);
if (ct > 1)
{
auto dUni = 2 * (usp - 1) / (ct - 1);
for (int i = 0; i < ct; ++i)
{
auto val = (1.0 - (usp - 1)) + dUni * i;
if (val < 1)
{
val = 1.0 / ((1.0 + (usp - 1)) - dUni * i);
}
uniVal[i] = val;
uniScale[i] = 2 * (i - 1.0 * (ct - 1) / 2) / (ct - 1);
uniPan[i] =
std::clamp(synth.patch.output.unisonPan.value * uniScale[i], -1.f, 1.f);
}
}
const bool hasCenter = (ct > 1 && (ct % 2 == 1));

auto upr = synth.patch.output.uniPhaseRand.value > 0.5;
auto prt = synth.patch.output.rephaseOnRetrigger > 0.5;
for (int vc = 0; vc < ct; ++vc)
{
// Bipolar position −1..1 across the unison field; 0 when ct==1.
// uniRatioMul and uniPanShift are derived from this in Voice::renderBlock
// each block, so they track host smoothing on unisonSpread / unisonPan.
const float uniScale = (ct > 1) ? (2.f * (vc - 0.5f * (ct - 1)) / (ct - 1)) : 0.f;

if (ibuf[vc].instruction !=
sst::voicemanager::VoiceInitInstructionsEntry<
baconpaul::six_sines::Synth::VMConfig>::Instruction::SKIP)
Expand All @@ -202,12 +187,12 @@ struct Synth
synth.voices[i].voiceValues.releaseVelocity = 0;
synth.voices[i].voiceValues.uniCount = ct;
synth.voices[i].voiceValues.uniIndex = vc;
synth.voices[i].voiceValues.hasCenterVoice = (ct > 1 && (ct % 2 == 1));
synth.voices[i].voiceValues.hasCenterVoice = hasCenter;
synth.voices[i].voiceValues.isCenterVoice =
(ct > 1 && (ct % 2 == 1)) && (std::fabs(uniScale[vc]) < 1e-4);
synth.voices[i].voiceValues.uniRatioMul = uniVal[vc];
synth.voices[i].voiceValues.uniPanShift = uniPan[vc];
synth.voices[i].voiceValues.uniPMScale = uniScale[vc];
hasCenter && (std::fabs(uniScale) < 1e-4f);
synth.voices[i].voiceValues.uniRatioMul = 1.f;
synth.voices[i].voiceValues.uniPanShift = 0.f;
synth.voices[i].voiceValues.uniPMScale = uniScale;
synth.voices[i].voiceValues.phaseRandom = (vc > 0 && upr);
synth.voices[i].voiceValues.rephaseOnRetrigger = (!upr && prt);
synth.voices[i].voiceValues.noteExpressionTuningInSemis = 0;
Expand Down
11 changes: 11 additions & 0 deletions src/synth/voice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ void Voice::attack()

void Voice::renderBlock()
{
// Refresh unison-derived per-voice scalars from the (smoothed) mono hoists so
// unisonSpread / unisonPan track host automation and UI knob moves mid-note.
if (voiceValues.uniCount > 1)
{
const float prod = monoValues.unisonSpreadFactorMinus1 * voiceValues.uniPMScale;
voiceValues.uniRatioMul =
(voiceValues.uniPMScale >= 0.f) ? (1.f + prod) : (1.f / (1.f - prod));
voiceValues.uniPanShift =
std::clamp(monoValues.unisonPanScalar * voiceValues.uniPMScale, -1.f, 1.f);
}

float retuneKey = voiceValues.key;
if (monoValues.mtsClient && MTS_HasMaster(monoValues.mtsClient))
{
Expand Down
Loading