Fix cross-rate Preserve splices, re-stamp on host-rate change, name the rate refusal
The splice crossfade now counts output frames and stops before the ring's far end (this also fixes a lap at matched rate). The search strides by the rate ratio. The editor takes its time base from its own decode. Same-rate output is pinned to hashes from before the change.
This commit is contained in:
@@ -178,15 +178,24 @@ voice reads SOURCE frames and emits OUTPUT frames, and `SampleData::sourceRateRa
|
||||
the shifter's tap at note-on.
|
||||
|
||||
- **Source frames:** the PCM, the loop and its crossfade, the start point, the Trigger span, the
|
||||
spline phase, the detected period, and the Preserve ring (`preserveWindowFrames`).
|
||||
spline phase, the detected period, and the Preserve ring (`preserveWindowFrames`) with every
|
||||
splice distance in it.
|
||||
- **Output frames (the host's):** every stage time in `SampleData::play` (resolved at
|
||||
`SampleData::renderRate`), the filter solve, the live ramps and the declick. A source-offset
|
||||
envelope converts through `stageFitRate`, which carries the ratio.
|
||||
`SampleData::renderRate`), the filter solve, the live ramps, the declick, and the shifter's
|
||||
splice crossfade (`PitchShifter::setSourceRateRatio`, which also strides the splice search to
|
||||
a matched rate's cost). A source-offset envelope converts through `stageFitRate`, which
|
||||
carries the ratio.
|
||||
- **Rejected alternative: resample at load.** It would round every loop point into the host
|
||||
domain (detuning a single-cycle loop), force the editor and the bank intrinsics through a
|
||||
conversion at every edge, and need a band-limited resampler in the core. The cost of the
|
||||
chosen shape is that a mismatched capture's ROOT note is interpolated like any other repitched
|
||||
note already is.
|
||||
- **That cost is asymmetric.** Nothing band-limits the read, so a file ABOVE the host rate
|
||||
folds whatever it holds over the host's Nyquist into the audible band even at its root — the
|
||||
aliasing a matched capture only meets when transposed up. A file BELOW the host rate is read
|
||||
slower than one frame per frame and only images, the milder direction. Offline captures
|
||||
render at the project rate (`shell/capture` pins `RENDER_SRATE`), so the exposed case is an
|
||||
ingested high-rate file, or a host running below the rate a capture was made at.
|
||||
|
||||
### Live parameter delivery — a knob moves the note already sounding (settled 2026-07-30)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user