Fix waveform_view comment accuracy, cut duplicate comments, align xToFrame to OverlayArea
This commit is contained in:
@@ -33,8 +33,10 @@ WaveformSurface waveformSurface(const Rect& band, bool stereoMode, int sourceCha
|
|||||||
waveformLanes(band, twoLanes ? LaneSplit::Stereo : LaneSplit::Single);
|
waveformLanes(band, twoLanes ? LaneSplit::Stereo : LaneSplit::Single);
|
||||||
s.upper = lanes.upper;
|
s.upper = lanes.upper;
|
||||||
s.lower = lanes.lower;
|
s.lower = lanes.lower;
|
||||||
// Derived from the resolved lanes, not `twoLanes`, so it can never contradict them (a
|
// Derived from the resolved lanes, not `twoLanes` — a stereo split's integer division
|
||||||
// band barely over the two-lane floor can still yield an empty lower lane).
|
// rounds the lower lane to empty for a band this thin (height <= 3), far below the
|
||||||
|
// allocator's kWaveformMinHeight floor but reachable if this is called directly with an
|
||||||
|
// arbitrary rect (as tests do).
|
||||||
s.laneCount = lanes.lower.empty() ? 1 : 2;
|
s.laneCount = lanes.lower.empty() ? 1 : 2;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -53,12 +55,13 @@ int frameToX(const OverlayArea& area, std::int64_t frameCount, std::int64_t fram
|
|||||||
return area.rect.x + static_cast<int>(num / frameCount);
|
return area.rect.x + static_cast<int>(num / frameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int64_t xToFrame(const Rect& area, std::int64_t frameCount, int x) {
|
std::int64_t xToFrame(const OverlayArea& area, std::int64_t frameCount, int x) {
|
||||||
const int w = std::max(0, area.width);
|
const Rect& r = area.rect;
|
||||||
|
const int w = std::max(0, r.width);
|
||||||
if (frameCount <= 0 || w <= 0) return 0;
|
if (frameCount <= 0 || w <= 0) return 0;
|
||||||
if (x <= area.x) return 0;
|
if (x <= r.x) return 0;
|
||||||
if (x >= area.right()) return frameCount;
|
if (x >= r.right()) return frameCount;
|
||||||
const std::int64_t dx = static_cast<std::int64_t>(x - area.x);
|
const std::int64_t dx = static_cast<std::int64_t>(x - r.x);
|
||||||
// Inverse of frameToX: frame = round(dx * frameCount / w).
|
// Inverse of frameToX: frame = round(dx * frameCount / w).
|
||||||
const std::int64_t num = dx * frameCount + static_cast<std::int64_t>(w) / 2;
|
const std::int64_t num = dx * frameCount + static_cast<std::int64_t>(w) / 2;
|
||||||
return clampFrame(num / static_cast<std::int64_t>(w), frameCount);
|
return clampFrame(num / static_cast<std::int64_t>(w), frameCount);
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ using audio::AudioSample;
|
|||||||
struct WaveformSurface {
|
struct WaveformSurface {
|
||||||
Rect upper; // lane 0 -> channel 0 (LEFT); the whole band when single-lane
|
Rect upper; // lane 0 -> channel 0 (LEFT); the whole band when single-lane
|
||||||
Rect lower; // lane 1 -> channel 1 (RIGHT); empty() when single-lane
|
Rect lower; // lane 1 -> channel 1 (RIGHT); empty() when single-lane
|
||||||
OverlayArea overlay; // the full band, both modes — a distinct type (not Rect) so an
|
OverlayArea overlay; // the full band, both modes
|
||||||
// overlay-only API can't accept a lane rect by mistake
|
int laneCount = 0; // 0 on a degenerate band, else 1 or 2 — matches `lower`'s emptiness
|
||||||
int laneCount = 0; // 0 on a degenerate band, else 1 or 2 — derived from the resolved
|
// (2 iff lower non-empty). For a non-empty band <= 2px tall, `upper`
|
||||||
// lanes (never contradicts upper/lower)
|
// can be empty too while this still reports 1 — unreachable through
|
||||||
|
// the band-stack allocator's kWaveformMinHeight floor.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolves the surface for a waveform band. Two lanes need BOTH stereo mode and a source
|
// Resolves the surface for a waveform band. Two lanes need BOTH stereo mode and a source
|
||||||
@@ -62,7 +63,7 @@ int frameToX(const OverlayArea& area, std::int64_t frameCount, std::int64_t fram
|
|||||||
|
|
||||||
// Inverse of frameToX: the frame a point x maps to, clamped to [0, frameCount]. A point left of
|
// Inverse of frameToX: the frame a point x maps to, clamped to [0, frameCount]. A point left of
|
||||||
// area.x yields 0; right of area.right() yields frameCount.
|
// area.x yields 0; right of area.right() yields frameCount.
|
||||||
std::int64_t xToFrame(const Rect& area, std::int64_t frameCount, int x);
|
std::int64_t xToFrame(const OverlayArea& area, std::int64_t frameCount, int x);
|
||||||
|
|
||||||
// Which marker (index into the caller's parallel `frames` array, in draw order) a grab at
|
// Which marker (index into the caller's parallel `frames` array, in draw order) a grab at
|
||||||
// (x, y) lands on, or -1 for a miss. A marker is grabbed when x is within kMarkerGrabWidth of
|
// (x, y) lands on, or -1 for a miss. A marker is grabbed when x is within kMarkerGrabWidth of
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ static bool findNode(const std::vector<EnvVertex>& poly, EnvNode node, EnvVertex
|
|||||||
static Rect wideArea() { return Rect::ltrb(20, 10, 1020, 110); }
|
static Rect wideArea() { return Rect::ltrb(20, 10, 1020, 110); }
|
||||||
static constexpr double kTotal = 2.0;
|
static constexpr double kTotal = 2.0;
|
||||||
|
|
||||||
// nodeAtPoint/resolveNodeDrag take the overlay type, not a bare Rect (the distinct-type
|
|
||||||
// enforcement in editor_geometry.h) — this wraps a plain test Rect for them.
|
|
||||||
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
||||||
static const double kGateSecPerPx = 1.0 / gatePxPerSecond(wideArea());
|
static const double kGateSecPerPx = 1.0 / gatePxPerSecond(wideArea());
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ static int g_fail = 0;
|
|||||||
#define CHECK(cond) do { if(!(cond)) { \
|
#define CHECK(cond) do { if(!(cond)) { \
|
||||||
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
||||||
|
|
||||||
// buildEnvelopePolyline takes the overlay type, not a bare Rect (the distinct-type
|
|
||||||
// enforcement in editor_geometry.h) — this wraps a plain test Rect for it.
|
|
||||||
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
||||||
|
|
||||||
// A comfortable overlay area: 1000px wide, 100px tall, offset so left/top != 0 (catches origin
|
// A comfortable overlay area: 1000px wide, 100px tall, offset so left/top != 0 (catches origin
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ static int g_fail = 0;
|
|||||||
#define CHECK(cond) do { if(!(cond)) { \
|
#define CHECK(cond) do { if(!(cond)) { \
|
||||||
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
||||||
|
|
||||||
// frameToX/markerAtPoint/resolveDragFrame take the overlay type, not a bare Rect (the
|
|
||||||
// distinct-type enforcement in editor_geometry.h) — this wraps a plain test Rect for them.
|
|
||||||
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
static OverlayArea overlayOf(const Rect& r) { return OverlayArea{r}; }
|
||||||
|
|
||||||
// A comfortable waveform area: 1000px wide, offset so left != 0 (catches origin bugs).
|
// A comfortable waveform area: 1000px wide, offset so left != 0 (catches origin bugs).
|
||||||
@@ -57,16 +55,16 @@ static void testFrameToXDegenerate() {
|
|||||||
|
|
||||||
static void testXToFrameInverse() {
|
static void testXToFrameInverse() {
|
||||||
const Rect a = wideArea();
|
const Rect a = wideArea();
|
||||||
CHECK(xToFrame(a, 1000, a.x) == 0);
|
CHECK(xToFrame(overlayOf(a), 1000, a.x) == 0);
|
||||||
CHECK(xToFrame(a, 1000, a.right()) == 1000);
|
CHECK(xToFrame(overlayOf(a), 1000, a.right()) == 1000);
|
||||||
CHECK(xToFrame(a, 1000, a.x + 250) == 250); // 1:1 map here
|
CHECK(xToFrame(overlayOf(a), 1000, a.x + 250) == 250); // 1:1 map here
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testXToFrameClampsOutside() {
|
static void testXToFrameClampsOutside() {
|
||||||
const Rect a = wideArea();
|
const Rect a = wideArea();
|
||||||
CHECK(xToFrame(a, 1000, a.x - 100) == 0); // left of area -> 0
|
CHECK(xToFrame(overlayOf(a), 1000, a.x - 100) == 0); // left of area -> 0
|
||||||
CHECK(xToFrame(a, 1000, a.right() + 100) == 1000); // right of area -> frameCount
|
CHECK(xToFrame(overlayOf(a), 1000, a.right() + 100) == 1000); // right of area -> frameCount
|
||||||
CHECK(xToFrame(a, 0, a.x + 10) == 0); // no frames -> 0
|
CHECK(xToFrame(overlayOf(a), 0, a.x + 10) == 0); // no frames -> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testFrameToXRoundTrip() {
|
static void testFrameToXRoundTrip() {
|
||||||
@@ -75,7 +73,7 @@ static void testFrameToXRoundTrip() {
|
|||||||
const Rect a = Rect::ltrb(0, 0, 800, 60);
|
const Rect a = Rect::ltrb(0, 0, 800, 60);
|
||||||
for (std::int64_t f = 0; f <= 2000; f += 137) {
|
for (std::int64_t f = 0; f <= 2000; f += 137) {
|
||||||
const int x = frameToX(overlayOf(a), 2000, f);
|
const int x = frameToX(overlayOf(a), 2000, f);
|
||||||
const std::int64_t back = xToFrame(a, 2000, x);
|
const std::int64_t back = xToFrame(overlayOf(a), 2000, x);
|
||||||
CHECK(back >= f - 3 && back <= f + 3);
|
CHECK(back >= f - 3 && back <= f + 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,6 +267,15 @@ static void testSurfaceDegenerateBandDrawsNothing() {
|
|||||||
CHECK(waveformOverlayArea(Rect{10, 10, 0, 0}).rect.empty());
|
CHECK(waveformOverlayArea(Rect{10, 10, 0, 0}).rect.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testSurfaceThinBandRoundsLowerLaneEmpty() {
|
||||||
|
// Height 3 is the edge where the stereo split's integer division rounds the lower lane to
|
||||||
|
// empty even though the band itself isn't degenerate — pins the laneCount derivation.
|
||||||
|
const WaveformSurface s = waveformSurface(Rect{0, 0, 100, 3}, true, 2);
|
||||||
|
CHECK(s.laneCount == 1);
|
||||||
|
CHECK(!s.upper.empty());
|
||||||
|
CHECK(s.lower.empty());
|
||||||
|
}
|
||||||
|
|
||||||
// --- Hit-testing across the stacked lanes -------------------------------------
|
// --- Hit-testing across the stacked lanes -------------------------------------
|
||||||
|
|
||||||
static void testMarkerGrabReachesTheLowerStereoLane() {
|
static void testMarkerGrabReachesTheLowerStereoLane() {
|
||||||
@@ -367,6 +374,7 @@ int main() {
|
|||||||
testSurfaceMonoSourceInStereoModeStaysOneLane();
|
testSurfaceMonoSourceInStereoModeStaysOneLane();
|
||||||
testSurfaceOverlayIsFullStackedHeightInBothModes();
|
testSurfaceOverlayIsFullStackedHeightInBothModes();
|
||||||
testSurfaceDegenerateBandDrawsNothing();
|
testSurfaceDegenerateBandDrawsNothing();
|
||||||
|
testSurfaceThinBandRoundsLowerLaneEmpty();
|
||||||
|
|
||||||
testMarkerGrabReachesTheLowerStereoLane();
|
testMarkerGrabReachesTheLowerStereoLane();
|
||||||
testMarkerGrabInMonoSpansTheBand();
|
testMarkerGrabInMonoSpansTheBand();
|
||||||
|
|||||||
Reference in New Issue
Block a user