S12: store wall-clock ADSR/pitch-env as seconds, resolve to frames at live rate
Kill kTier0Nominal*, adsrNeedsRateResolve, tier0Adsr, gateAdsr. Zones payload v5 carries seconds; v3 legacy reads convert at the frozen authoring rate; v4 (branch-only) dropped. Editor sliders now seconds. Engine takes frames resolved at keymap build.
This commit is contained in:
@@ -37,10 +37,6 @@ namespace {
|
||||
// notes neither click on nor cut off abruptly; sustain at unity (velocity does the
|
||||
// dynamics), a short release for a natural tail. Times are in seconds, converted to
|
||||
// frames against the live sample rate at build time.
|
||||
constexpr double kAttackSeconds = 0.003;
|
||||
constexpr double kDecaySeconds = 0.0;
|
||||
constexpr double kSustainLevel = 1.0;
|
||||
constexpr double kReleaseSeconds = 0.060;
|
||||
constexpr std::size_t kMaxVoices = 16;
|
||||
|
||||
// S16 Preserve-mode voice cap: a Preserve voice runs a per-voice OLA pitch shifter and is
|
||||
@@ -50,16 +46,6 @@ constexpr std::size_t kMaxVoices = 16;
|
||||
// cost — see the handoff CPU note. 8 is a conservative half of kMaxVoices pending DAW profiling.
|
||||
constexpr std::size_t kPreserveVoiceCap = 8;
|
||||
|
||||
AdsrParams tier0Adsr(double sampleRate) {
|
||||
const double sr = sampleRate > 0.0 ? sampleRate : 44100.0;
|
||||
AdsrParams p;
|
||||
p.attackFrames = static_cast<std::int64_t>(kAttackSeconds * sr);
|
||||
p.decayFrames = static_cast<std::int64_t>(kDecaySeconds * sr);
|
||||
p.sustainLevel = kSustainLevel;
|
||||
p.releaseFrames = static_cast<std::int64_t>(kReleaseSeconds * sr);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Read a whole file into a byte buffer. Off-thread only (blocking file I/O). Empty on
|
||||
// any failure — the caller treats an unreadable WAV as "nothing to play".
|
||||
std::vector<std::uint8_t> readFileBytes(const std::string& path) {
|
||||
@@ -384,12 +370,13 @@ std::string ReaSamplerProcessor::reloadFromBank() {
|
||||
if (haveKeymap) {
|
||||
// Preserve OLA window in OUTPUT frames from the host sample rate (kPreserveWindowMs).
|
||||
// Every voice's shifter is pre-sized to this off-thread here, so process()-time
|
||||
// note-on never allocates. Floored at 2 so a valid window is always a real ring.
|
||||
// note-on never allocates. Floored at 2 so a valid window is always a real ring
|
||||
// (which also covers a pathological host rate <= 0 — no rate literal needed).
|
||||
std::int64_t preserveWindow = static_cast<std::int64_t>(
|
||||
kPreserveWindowMs * (sampleRate_ > 0.0 ? sampleRate_ : 44100.0) / 1000.0 + 0.5);
|
||||
kPreserveWindowMs * sampleRate_ / 1000.0 + 0.5);
|
||||
if (preserveWindow < 2) preserveWindow = 2;
|
||||
built = std::make_unique<LoadedInstrument>(
|
||||
std::move(km), kMaxVoices, tier0Adsr(sampleRate_), gen, kPreserveVoiceCap,
|
||||
std::move(km), kMaxVoices, gen, kPreserveVoiceCap,
|
||||
preserveWindow);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user