fix(align): review round 1 for the alignment page
- server: collapse leading slashes so //host/x is never proxied off-host or redirected cross-origin; 1 MB body limit; max 10k anchors; a corrupt alignment.json no longer 500s /api/songs (song falls back to auto with a warning); comments on cookie scope and the loopback inner server - warp (ruling A6): adding/moving a manual anchor removes autos only within 10 s (MIDI) of the new/old position, never past a manual, plus any auto that would break audio monotonicity - page: first anchor clamped at >= 0 s; ruler scrubbing seeks on release; wording for the new auto-removal rule; removed-count excludes the dragged anchor; shows server warnings - manifest: unique tmp name for alignment.json; clear error for a corrupt file - resample test: speed asserted as a ratio to the direct path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
894fd9b9ef
commit
f0249995cf
10 files changed
+192
-45
No files matched your search
@@ -108,8 +108,8 @@ describe("addManual", () => {
|
||||
expect(addManual([], { midiSec: 2, audioSec: 2.5 })).toEqual([M(2, 2.5)]);
|
||||
});
|
||||
|
||||
test("removes the whole contiguous auto run up to the nearest manual on each side", () => {
|
||||
// M0 | A2 | A4 | M8 ; insert manual at 6 -> both autos between M0 and M8 go (the run stops at manuals)
|
||||
test("removes autos near the new anchor (both within 10 s here), never past a manual", () => {
|
||||
// M0 | A2 | A4 | M8 ; insert manual at 6 -> both autos between M0 and M8 go
|
||||
const base = [M(0, 0), A(2, 2), A(4, 4.5), M(8, 8)];
|
||||
expect(addManual(base, { midiSec: 6, audioSec: 6.2 })).toEqual([M(0, 0), M(6, 6.2), M(8, 8)]);
|
||||
});
|
||||
@@ -126,7 +126,39 @@ describe("addManual", () => {
|
||||
test("moving a manual anchor across several autos succeeds and removes the crossed autos", () => {
|
||||
// M0 | A10 | A20 | M30 | A40 | M60 ; move M30 -> midi 45 (crosses A40, stays before M60)
|
||||
const base = [M(0, 0), A(10, 10), A(20, 20), M(30, 30), A(40, 40), M(60, 60)];
|
||||
expect(moveAnchor(base, 3, { midiSec: 45, audioSec: 45 })).toEqual([M(0, 0), M(45, 45), M(60, 60)]);
|
||||
// A40 is within 10 s of the new position, A20 within 10 s of the old one; A10 is further than 10 s from both and kept
|
||||
expect(moveAnchor(base, 3, { midiSec: 45, audioSec: 45 })).toEqual([M(0, 0), A(10, 10), M(45, 45), M(60, 60)]);
|
||||
});
|
||||
|
||||
test("autos every 2 s, no manuals: a manual at 60 s removes only the autos within 10 s (50..70)", () => {
|
||||
const base = Array.from({ length: 60 }, (_, k) => A(2 * k + 1, 2 * k + 1)); // 1, 3, ..., 119
|
||||
const out = addManual(base, { midiSec: 60, audioSec: 60 });
|
||||
expect(out.filter((a) => a.kind === "auto").map((a) => a.midiSec)).toEqual(base.map((a) => a.midiSec).filter((m) => m < 50 || m > 70));
|
||||
expect(out.find((a) => a.kind === "manual")).toEqual(M(60, 60));
|
||||
});
|
||||
|
||||
test("autos outside the 10 s window that would break audio monotonicity are removed too", () => {
|
||||
const base = Array.from({ length: 60 }, (_, k) => A(2 * k + 1, 2 * k + 1));
|
||||
// a manual at midi 60 placed at audio 75: autos at midi 71, 73 (outside the window) sit at audio < 75 after it
|
||||
const out = addManual(base, { midiSec: 60, audioSec: 75 });
|
||||
const autos = out.filter((a) => a.kind === "auto").map((a) => a.midiSec);
|
||||
expect(autos).not.toContain(71);
|
||||
expect(autos).not.toContain(73);
|
||||
expect(autos).toContain(75 + 2); // 77 > 75 stays
|
||||
expect(autos).toContain(49);
|
||||
expect(() => makeWarp(out)).not.toThrow();
|
||||
});
|
||||
|
||||
test("a drag that crosses an auto outside the window removes it via the monotonicity rule", () => {
|
||||
const base = [...Array.from({ length: 30 }, (_, k) => A(2 * k + 1, 2 * k + 1)).filter((a) => a.midiSec !== 31), M(30, 30)].sort((x, y) => x.midiSec - y.midiSec);
|
||||
const i = base.findIndex((a) => a.kind === "manual");
|
||||
// keep MIDI 30, drag the recording end to 45 s: autos at midi 41, 43 (window is 20..40) now lie before it in audio
|
||||
const out = moveAnchor(base, i, { midiSec: 30, audioSec: 45 });
|
||||
const autos = out.filter((a) => a.kind === "auto").map((a) => a.midiSec);
|
||||
expect(autos.filter((m) => m >= 20 && m <= 44)).toEqual([]);
|
||||
expect(autos).toContain(47);
|
||||
expect(autos).toContain(19);
|
||||
expect(() => makeWarp(out)).not.toThrow();
|
||||
});
|
||||
|
||||
test("auto runs are removed even when they are the only anchors besides the moved one", () => {
|
||||
|
||||
Reference in new issue
Block a user