feat: synthesize trajectory analysis windows
This commit is contained in:
@@ -15,7 +15,16 @@ function sampleAsset(signal, assetBuffers, time) {
|
||||
return channel[left] + (rightValue - channel[left]) * fraction;
|
||||
}
|
||||
|
||||
export function renderSignal(entry, scene, assetBuffers = new Map(), seedSalt = 0) {
|
||||
/**
|
||||
* Render one signal entry into the scene-sized output buffer.
|
||||
*
|
||||
* `timeMapping` lets a short, rebased scene window retain the original signal
|
||||
* timeline. `sceneSampleOffset` maps output sample zero to an absolute sample
|
||||
* in the original scene, while `signalStartTime`/`signalStartSample` preserve
|
||||
* the entry's original tone/asset time origin and deterministic noise index.
|
||||
* Omitting it keeps the historical whole-scene behaviour exactly unchanged.
|
||||
*/
|
||||
export function renderSignal(entry, scene, assetBuffers = new Map(), seedSalt = 0, timeMapping = {}) {
|
||||
const sampleCount = Math.ceil(scene.duration * scene.sampleRate);
|
||||
const output = new Float32Array(sampleCount);
|
||||
const startTime = entry.startTime ?? 0;
|
||||
@@ -23,12 +32,25 @@ export function renderSignal(entry, scene, assetBuffers = new Map(), seedSalt =
|
||||
const gain = dbToLinear(entry.gainDb ?? 0);
|
||||
const startSample = Math.max(0, Math.ceil(startTime * scene.sampleRate));
|
||||
const endSample = Math.min(sampleCount, Math.ceil((startTime + duration) * scene.sampleRate));
|
||||
const sceneSampleOffset = timeMapping.sceneSampleOffset ?? 0;
|
||||
const signalStartTime = timeMapping.signalStartTime ?? startTime;
|
||||
const signalStartSample = timeMapping.signalStartSample ?? Math.ceil(startTime * scene.sampleRate);
|
||||
if (!Number.isSafeInteger(sceneSampleOffset) || sceneSampleOffset < 0) {
|
||||
throw new RangeError("sceneSampleOffset must be a non-negative safe integer.");
|
||||
}
|
||||
if (!Number.isFinite(signalStartTime)) {
|
||||
throw new TypeError("signalStartTime must be finite.");
|
||||
}
|
||||
if (!Number.isSafeInteger(signalStartSample) || signalStartSample < 0) {
|
||||
throw new RangeError("signalStartSample must be a non-negative safe integer.");
|
||||
}
|
||||
const signal = entry.signal;
|
||||
const seed = (scene.seed + (signal.seedOffset ?? 0) + hashString(entry.id ?? "signal") + seedSalt) >>> 0;
|
||||
|
||||
for (let sampleIndex = startSample; sampleIndex < endSample; sampleIndex += 1) {
|
||||
const localIndex = sampleIndex - startSample;
|
||||
const localTime = sampleIndex / scene.sampleRate - startTime;
|
||||
const absoluteSampleIndex = sceneSampleOffset + sampleIndex;
|
||||
const localIndex = absoluteSampleIndex - signalStartSample;
|
||||
const localTime = absoluteSampleIndex / scene.sampleRate - signalStartTime;
|
||||
let value;
|
||||
if (signal.type === "tone") {
|
||||
value = Math.sin(TAU * signal.frequency * localTime + ((signal.phaseDeg ?? 0) * Math.PI) / 180);
|
||||
|
||||
Reference in New Issue
Block a user