Browse Source

VCO: Fix minBLEP cross detection for backwards phase and narrow pulse width.

v2
Andrew Belt 1 month ago
parent
commit
dec738ffde
1 changed files with 10 additions and 9 deletions
  1. +10
    -9
      src/VCO.cpp

+ 10
- 9
src/VCO.cpp View File

@@ -286,12 +286,13 @@ struct VCOProcessor {
};

// Computes subsample time where phase crosses threshold.
auto getCrossing = [](T threshold, T startPhase, T endPhase, T startSubsample, T endSubsample) -> T {
// Wrap threshold mod 1 to be in (startPhase, startPhase + 1]
threshold -= simd::floor(threshold - startPhase);
// Map to (0, 1]
T p = (threshold - startPhase) / (endPhase - startPhase);
// Map to (startSubsample, endSubsample]
auto getCrossing = [](T thresholdPhase, T startPhase, T endPhase, T startSubsample, T endSubsample) -> T {
T delta = endPhase - startPhase;
T diff = thresholdPhase - startPhase;
// Forward: wrap thresholdPhase to (startPhase, startPhase+1]
// Backward: wrap thresholdPhase to [startPhase-1, startPhase)
thresholdPhase -= simd::ifelse(delta >= 0.f, simd::floor(diff), simd::ceil(diff));
T p = (thresholdPhase - startPhase) / delta;
return startSubsample + p * (endSubsample - startSubsample);
};

@@ -300,19 +301,19 @@ struct VCOProcessor {
// channelMask limits processing to specific channels.
auto processCrossings = [&](T startPhase, T endPhase, T startSubsample, T endSubsample, T channelMask) {
if (frame.sqrEnabled || frame.triEnabled) {
// Wrap crossing (phase crosses 0 mod 1)
// Insert minBLEP to square when phase crosses 0 (mod 1)
T wrapSubsample = getCrossing(1.f, startPhase, endPhase, startSubsample, endSubsample);
T wrapMask = channelMask & (startSubsample < wrapSubsample) & (wrapSubsample <= endSubsample);
insertMinBlep(wrapMask, wrapSubsample, 2.f * syncDirection, sqrMinBlep);

// Pulse width crossing
// Insert minBLEP to square when phase crosses pulse width
T pulseSubsample = getCrossing(pulseWidth, startPhase, endPhase, startSubsample, endSubsample);
T pulseMask = channelMask & (startSubsample < pulseSubsample) & (pulseSubsample <= endSubsample);
insertMinBlep(pulseMask, pulseSubsample, -2.f * syncDirection, sqrMinBlep);
}

if (frame.sawEnabled) {
// Saw crossing at 0.5
// Insert minBLEP to saw when crossing 0.5
T sawSubsample = getCrossing(0.5f, startPhase, endPhase, startSubsample, endSubsample);
T sawMask = channelMask & (startSubsample < sawSubsample) & (sawSubsample <= endSubsample);
insertMinBlep(sawMask, sawSubsample, -2.f * syncDirection, sawMinBlep);


Loading…
Cancel
Save