loop: crossfade the Gate sustain seam, and unshadow the loop handles that made loop points look gone
This commit is contained in:
@@ -52,20 +52,33 @@ bool ReaSamplerEditor::mouseDownWaveform(const FaceLayout& fl, int x, int y) {
|
||||
}
|
||||
}
|
||||
const SetupMarkers m = pickedMarkers(frames);
|
||||
// The crossfade handle first, and only when there IS a loop to fade: at a zero fade it
|
||||
// sits exactly on the loop start, so it can only stay reachable by owning the top strip
|
||||
// (waveform_view.h's handle-vs-column split) and being asked first.
|
||||
if (m.hasLoop &&
|
||||
contains(markerHandleRect(overlay, frames, m.loopStart - m.crossfade), x, y)) {
|
||||
beginMarkerDrag(WaveMarker::kLoopXfade, m, frames, x);
|
||||
return true;
|
||||
}
|
||||
const std::int64_t markerFrames[3] = {m.start, m.loopStart, m.loopEnd};
|
||||
const int hit = markerAtPoint(overlay, frames, markerFrames, 3, x, y);
|
||||
if (hit >= 0) {
|
||||
drag_ = DragKind::kWaveMarker;
|
||||
waveMarker_ = static_cast<WaveMarker>(hit);
|
||||
dragStartX_ = x;
|
||||
dragStartMarkers_ = m;
|
||||
dragSampleFrames_ = frames;
|
||||
dragStartParams_ = params_;
|
||||
beginMarkerDrag(static_cast<WaveMarker>(hit), m, frames, x);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::beginMarkerDrag(WaveMarker which, const SetupMarkers& m,
|
||||
std::int64_t frames, int x) {
|
||||
drag_ = DragKind::kWaveMarker;
|
||||
waveMarker_ = which;
|
||||
dragStartX_ = x;
|
||||
dragStartMarkers_ = m;
|
||||
dragSampleFrames_ = frames;
|
||||
dragStartParams_ = params_;
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::dragWaveform(const FaceLayout& fl, int x, int y) {
|
||||
const OverlayArea overlay = waveformOverlayArea(fl.bands.waveform);
|
||||
const int dx = x - dragStartX_;
|
||||
@@ -96,14 +109,17 @@ void ReaSamplerEditor::dragWaveform(const FaceLayout& fl, int x, int y) {
|
||||
|
||||
// Grabbed frame at grab time, from the snapshot (so the delta is measured from grab).
|
||||
const int idx = static_cast<int>(waveMarker_);
|
||||
const std::int64_t startVals[3] = {dragStartMarkers_.start, dragStartMarkers_.loopStart,
|
||||
dragStartMarkers_.loopEnd};
|
||||
const std::int64_t startVals[4] = {dragStartMarkers_.start, dragStartMarkers_.loopStart,
|
||||
dragStartMarkers_.loopEnd,
|
||||
dragStartMarkers_.loopStart -
|
||||
dragStartMarkers_.crossfade};
|
||||
std::int64_t newFrame = resolveDragFrame(overlay, frames, startVals[idx], dx);
|
||||
|
||||
// Snap to the nearest zero crossing in the decoded PCM. Pure over the cached mono
|
||||
// frames — no host types, no file I/O.
|
||||
// frames — no host types, no file I/O. The crossfade handle is exempt: it sets a fade
|
||||
// LENGTH, and the whole point of the fade is that its edges need no zero crossing.
|
||||
const std::vector<AudioSample>& pcm = monoPcmFor(selectedId_);
|
||||
if (!pcm.empty()) {
|
||||
if (!pcm.empty() && waveMarker_ != WaveMarker::kLoopXfade) {
|
||||
newFrame = nearestZeroCrossing(pcm.data(), static_cast<std::int64_t>(pcm.size()),
|
||||
newFrame);
|
||||
}
|
||||
@@ -116,12 +132,19 @@ void ReaSamplerEditor::dragWaveform(const FaceLayout& fl, int x, int y) {
|
||||
} else if (waveMarker_ == WaveMarker::kLoopStart) {
|
||||
m.loopStart = (std::min)(newFrame, m.loopEnd);
|
||||
m.hasLoop = true;
|
||||
} else { // kLoopEnd
|
||||
} else if (waveMarker_ == WaveMarker::kLoopEnd) {
|
||||
m.loopEnd = (std::max)(newFrame, m.loopStart);
|
||||
m.hasLoop = true;
|
||||
} else { // kLoopXfade — the handle sits at loopStart - crossfade, so left lengthens it
|
||||
m.crossfade = (std::max)(std::int64_t{0}, m.loopStart - newFrame);
|
||||
}
|
||||
if (m.start < 0) m.start = 0;
|
||||
if (m.start > frames - 1) m.start = frames - 1;
|
||||
// Mirror resolveLoop's own bound so the handle can't be dragged somewhere the engine
|
||||
// would silently clamp back: the fade reads the material ahead of the loop, and cannot
|
||||
// outrun either that material or the loop itself.
|
||||
m.crossfade = (std::min)(m.crossfade, (std::min)(m.loopStart, m.loopEnd - m.loopStart));
|
||||
if (m.crossfade < 0) m.crossfade = 0;
|
||||
|
||||
applyMarkers(m);
|
||||
invalidate(); // live feedback; the commit lands on release
|
||||
|
||||
Reference in New Issue
Block a user