feat(sim): pure altitude-scrub math module + node unit suite
Per plan Task 1. position->segment, frac->currentTime, audio gains, and integer-crossing detection; 9 node --test cases green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// Pure altitude-scrub math — no DOM. A continuous `pos` (float) is the knob:
|
||||
// integers are altitudes/detents, fractions are mid-morph blend. UMD so the
|
||||
// browser gets a `HEFScrub` global and `node --test` can require() it.
|
||||
(function (root, factory) {
|
||||
const api = factory();
|
||||
if (typeof module !== "undefined" && module.exports) module.exports = api;
|
||||
else root.HEFScrub = api;
|
||||
})(typeof self !== "undefined" ? self : this, function () {
|
||||
"use strict";
|
||||
|
||||
const clamp01 = (x) => Math.max(0, Math.min(1, x));
|
||||
const wrapIndex = (i, n) => ((i % n) + n) % n;
|
||||
|
||||
function segmentOf(pos) {
|
||||
const lo = Math.floor(pos);
|
||||
return { lo, frac: pos - lo };
|
||||
}
|
||||
|
||||
function accumToPos(restPos, accumDeg, stepDeg) {
|
||||
return restPos + accumDeg / stepDeg;
|
||||
}
|
||||
|
||||
function fracToTime(frac, duration) {
|
||||
return clamp01(frac) * (duration || 0);
|
||||
}
|
||||
|
||||
function crossfadeGains(frac) {
|
||||
const f = clamp01(frac);
|
||||
return { from: 1 - f, to: f };
|
||||
}
|
||||
|
||||
// Integers strictly crossed moving prevPos -> pos, in travel order. Landing
|
||||
// exactly on an integer counts as crossing it (it commits that altitude).
|
||||
function integerCrossings(prevPos, pos) {
|
||||
const out = [];
|
||||
if (pos > prevPos) {
|
||||
for (let k = Math.floor(prevPos) + 1; k <= pos + 1e-9; k++) out.push({ index: k, dir: 1 });
|
||||
} else if (pos < prevPos) {
|
||||
for (let k = Math.ceil(prevPos) - 1; k >= pos - 1e-9; k--) out.push({ index: k, dir: -1 });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
return { clamp01, wrapIndex, segmentOf, accumToPos, fracToTime, crossfadeGains, integerCrossings };
|
||||
});
|
||||
Reference in New Issue
Block a user