Bound the automation hold to the window the model has not caught up on, and make that authority model stated, enforced and tested
This commit is contained in:
@@ -6,7 +6,11 @@
|
||||
namespace reasampler::instrument::engine {
|
||||
|
||||
LiveValues foldLive(const PlayParams& params, double keyTrack) {
|
||||
LiveValues v;
|
||||
// Value-initialized, so the padding is determinate too. Nothing reads it — the block's
|
||||
// equality is field-wise for exactly that reason — but this is the one construction site
|
||||
// every publisher goes through, and an object with indeterminate bytes travelling under a
|
||||
// seqlock is a hazard worth not having. Off the audio thread; the memset costs nothing here.
|
||||
LiveValues v{};
|
||||
v.keyTrack = keyTrack;
|
||||
// Folded here, not at the voice: Voice::start reads the block's value directly, so the
|
||||
// spline rule has to be applied on the way in or the two would answer differently.
|
||||
@@ -26,6 +30,48 @@ LiveValues foldLive(const PlayParams& params, double keyTrack) {
|
||||
return v;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool sameAdsr(const AdsrParams& a, const AdsrParams& b) {
|
||||
return a.attackFrames == b.attackFrames && a.holdFrames == b.holdFrames &&
|
||||
a.decayFrames == b.decayFrames && a.sustainLevel == b.sustainLevel &&
|
||||
a.releaseFrames == b.releaseFrames && a.attackCurve == b.attackCurve &&
|
||||
a.decayCurve == b.decayCurve && a.releaseCurve == b.releaseCurve;
|
||||
}
|
||||
|
||||
bool sameAhd(const AhdParams& a, const AhdParams& b) {
|
||||
return a.attackFrames == b.attackFrames && a.decayFrames == b.decayFrames &&
|
||||
a.holdFraction == b.holdFraction && a.attackCurve == b.attackCurve &&
|
||||
a.decayCurve == b.decayCurve;
|
||||
}
|
||||
|
||||
bool sameFilterSettings(const filter::FilterSettings& a, const filter::FilterSettings& b) {
|
||||
return a.cutoffNorm == b.cutoffNorm && a.resonanceNorm == b.resonanceNorm &&
|
||||
a.morphNorm == b.morphNorm && a.driveNorm == b.driveNorm &&
|
||||
a.morphLaw == b.morphLaw;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool operator==(const LiveValues& a, const LiveValues& b) {
|
||||
return sameFilterSettings(a.filterSettings, b.filterSettings) &&
|
||||
a.filterModAmount == b.filterModAmount &&
|
||||
a.filterVelAmount == b.filterVelAmount &&
|
||||
a.filterKeyTrack == b.filterKeyTrack &&
|
||||
sameAdsr(a.filterEnv, b.filterEnv) &&
|
||||
sameAhd(a.filterAhd, b.filterAhd) &&
|
||||
sameAdsr(a.adsr, b.adsr) &&
|
||||
sameAhd(a.ampAhd, b.ampAhd) &&
|
||||
a.pitchEnv.enabled == b.pitchEnv.enabled &&
|
||||
a.pitchEnv.peakSemitones == b.pitchEnv.peakSemitones &&
|
||||
sameAhd(a.pitchEnv.shape, b.pitchEnv.shape) &&
|
||||
a.playRate == b.playRate &&
|
||||
a.pitchOffsetSemitones == b.pitchOffsetSemitones &&
|
||||
a.keyTrack == b.keyTrack &&
|
||||
a.lengthFraction == b.lengthFraction &&
|
||||
a.splineActive == b.splineActive;
|
||||
}
|
||||
|
||||
double liveRampStep(double sampleRate) {
|
||||
if (!(sampleRate > 0.0)) return 0.0; // also catches NaN
|
||||
return 1.0 / (kLiveRampSeconds * sampleRate);
|
||||
|
||||
Reference in New Issue
Block a user