fix: S12 R2 — marker-drag sets selectedZone_, ADSR rate-resolve, gateAdsr doc
Marker drag now sets selectedZone_ so single-capture controls stay reachable. Lifted/default ADSR rescales nominal 44100-Hz frame counts by sampleRate/44100 via adsrNeedsRateResolve; v4-authored zones skip rescale. gateAdsr documented vestigial.
This commit is contained in:
@@ -147,6 +147,23 @@ Keymap buildTier0Keymap(std::vector<AudioSample> frames, int sampleRate,
|
||||
data.rootNote = rootNote;
|
||||
data.loop = loop;
|
||||
data.play = play; // S15/S16 single-capture play params (product defaults unless overridden)
|
||||
|
||||
// The default `play` arg carries 44100-Hz nominal ADSR frame counts (kTier0Nominal*).
|
||||
// Rescale A/D/R by (sampleRate / 44100) so the wall-clock ADSR matches tier0Adsr(sampleRate)
|
||||
// exactly. Sustain (a level, not a frame count) is unchanged. At 44100 the factor is 1.0 —
|
||||
// bit-identical to the pre-fix build. The tier-0 single-capture path never carries user-edited
|
||||
// ADSR (users edit ADSR through zones, which go through buildZonedKeymap), so always rescaling
|
||||
// here is correct and safe.
|
||||
if (data.sampleRate != 44100) {
|
||||
const double factor = static_cast<double>(data.sampleRate) / 44100.0;
|
||||
data.play.adsr.attackFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.attackFrames) * factor + 0.5);
|
||||
data.play.adsr.decayFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.decayFrames) * factor + 0.5);
|
||||
data.play.adsr.releaseFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.releaseFrames) * factor + 0.5);
|
||||
}
|
||||
|
||||
return Keymap::singleSampleChromatic(std::move(data));
|
||||
}
|
||||
|
||||
@@ -190,6 +207,8 @@ ResolvedPerformance resolvePerformance(const std::string& banksJson,
|
||||
// S15/S16 per-zone play params carry through unchanged (they are instrument state, not
|
||||
// resolved against the bank) so the keymap build can stamp them onto the SampleData.
|
||||
rz.play = z.play;
|
||||
// Carry the rate-resolve flag so buildZonedKeymap can rescale 44100-nominal ADSR counts.
|
||||
rz.adsrNeedsRateResolve = z.adsrNeedsRateResolve;
|
||||
out.zones.push_back(std::move(rz));
|
||||
}
|
||||
return out;
|
||||
@@ -215,6 +234,20 @@ Keymap buildZonedKeymap(const std::vector<ResolvedZone>& zones,
|
||||
data.loop = zones[i].loop;
|
||||
data.startFrame = zones[i].startFrame; // S11 effective start (override, else 0)
|
||||
data.play = zones[i].play; // S15/S16 per-zone play mode + engine + envelopes
|
||||
|
||||
// If the zone's ADSR came from a v3 lift or a new-zone default (adsrNeedsRateResolve),
|
||||
// its A/D/R frame counts are 44100-Hz nominals. Rescale to the WAV's actual rate so
|
||||
// wall-clock ADSR durations match tier0Adsr(sampleRate) exactly. v4 zones (user-edited
|
||||
// frame counts) carry adsrNeedsRateResolve=false and are left unchanged.
|
||||
if (zones[i].adsrNeedsRateResolve && data.sampleRate != 44100) {
|
||||
const double factor = static_cast<double>(data.sampleRate) / 44100.0;
|
||||
data.play.adsr.attackFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.attackFrames) * factor + 0.5);
|
||||
data.play.adsr.decayFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.decayFrames) * factor + 0.5);
|
||||
data.play.adsr.releaseFrames = static_cast<std::int64_t>(
|
||||
static_cast<double>(data.play.adsr.releaseFrames) * factor + 0.5);
|
||||
}
|
||||
const std::size_t sampleIndex = km.samples.size();
|
||||
km.samples.push_back(std::move(data));
|
||||
KeyZone zone;
|
||||
@@ -420,10 +453,12 @@ void readZonesPayload(ByteReader& r, PerformanceMap& map) {
|
||||
}
|
||||
if (hasAdsr) {
|
||||
// S12 review fix (v4): the full per-zone A/D/S/R tail — read in the emit order.
|
||||
// These values were authored at the DAW's rate; mark them resolved (no rescaling).
|
||||
z.play.adsr.attackFrames = r.i64();
|
||||
z.play.adsr.decayFrames = r.i64();
|
||||
z.play.adsr.sustainLevel = bitsToDouble(r.u64());
|
||||
z.play.adsr.releaseFrames = r.i64();
|
||||
z.adsrNeedsRateResolve = false; // already rate-resolved; do NOT rescale at keymap build
|
||||
} else if (hasPlay) {
|
||||
// v3 blob: A/D/S/R fields are absent. Lift to the tier-0 nominal defaults (44100 Hz)
|
||||
// so a voice playing this zone sounds bit-identical to the pre-v4 build (back-compat).
|
||||
|
||||
Reference in New Issue
Block a user