feat: synthesize trajectory analysis windows
This commit is contained in:
@@ -74,13 +74,73 @@ export function sampleQuasiStaticWindow(scene, startTime, endTime) {
|
||||
if (Number.isFinite(scene?.duration) && endTime > scene.duration) {
|
||||
throw new RangeError("window endTime must not exceed scene.duration.");
|
||||
}
|
||||
const sampleTime = startTime + (endTime - startTime) / 2;
|
||||
const sampleRate = scene?.sampleRate;
|
||||
if (!Number.isInteger(sampleRate) || sampleRate <= 0) {
|
||||
const sampleTime = startTime + (endTime - startTime) / 2;
|
||||
return {
|
||||
startTime,
|
||||
endTime,
|
||||
sampleTime,
|
||||
duration: endTime - startTime,
|
||||
scene: sceneAtTime(scene, sampleTime),
|
||||
};
|
||||
}
|
||||
|
||||
// Ceil selects the first sample whose timestamp is inside each half-open
|
||||
// boundary. Adjacent windows therefore share an exact boundary without a
|
||||
// duplicated or omitted sample, even when their requested times are not
|
||||
// integer multiples of the sample period.
|
||||
const startSample = Math.ceil(startTime * sampleRate);
|
||||
const endSample = Math.ceil(endTime * sampleRate);
|
||||
if (endSample <= startSample) {
|
||||
throw new RangeError("window must contain at least one sample.");
|
||||
}
|
||||
const alignedStartTime = startSample / sampleRate;
|
||||
const alignedEndTime = endSample / sampleRate;
|
||||
const sampleTime = (startSample + endSample) / (2 * sampleRate);
|
||||
const sources = [];
|
||||
const sourceOffsets = [];
|
||||
|
||||
for (const source of scene.sources) {
|
||||
const signalStartTime = source.startTime ?? 0;
|
||||
const signalDuration = source.duration ?? scene.duration;
|
||||
const signalStartSample = Math.ceil(signalStartTime * sampleRate);
|
||||
const signalEndSample = Math.ceil((signalStartTime + signalDuration) * sampleRate);
|
||||
const activeStartSample = Math.max(startSample, signalStartSample);
|
||||
const activeEndSample = Math.min(endSample, signalEndSample);
|
||||
if (activeEndSample <= activeStartSample) continue;
|
||||
|
||||
sources.push({
|
||||
...source,
|
||||
position: sourcePositionAtTime(source, sampleTime),
|
||||
startTime: (activeStartSample - startSample) / sampleRate,
|
||||
duration: (activeEndSample - activeStartSample) / sampleRate,
|
||||
});
|
||||
sourceOffsets.push({ signalStartTime, signalStartSample });
|
||||
}
|
||||
|
||||
const ambient = Array.isArray(scene.ambient) ? scene.ambient.slice() : scene.ambient;
|
||||
const signalOffsets = {
|
||||
sceneSampleOffset: startSample,
|
||||
sources: sourceOffsets,
|
||||
ambient: (scene.ambient ?? []).map(() => ({ signalStartTime: 0, signalStartSample: 0 })),
|
||||
};
|
||||
const duration = (endSample - startSample) / sampleRate;
|
||||
return {
|
||||
startTime,
|
||||
endTime,
|
||||
startTime: alignedStartTime,
|
||||
endTime: alignedEndTime,
|
||||
sampleTime,
|
||||
duration: endTime - startTime,
|
||||
scene: sceneAtTime(scene, sampleTime),
|
||||
startSample,
|
||||
endSample,
|
||||
sampleCount: endSample - startSample,
|
||||
duration,
|
||||
signalOffsets,
|
||||
scene: {
|
||||
...scene,
|
||||
duration,
|
||||
sources,
|
||||
...(Array.isArray(scene.ambient) ? { ambient } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user