Ramp sound FX parameters over a time on the audio clock
A pitch sweep counted down in On update or On fixed update runs in game time, while the sound runs on the clock of the audio device. A short sound magnifies any offset between the two, so the sweep came out different on every play and most of all on the first. - Set sound FX parameters has a new input time in seconds. The values run evenly to their target in that time, scheduled on the audio clock with linearRampToValueAtTime or exponentialRampToValueAtTime. - Evenly in their own unit: a pitch in semitones and a gain in decibels, an EQ band and a Mix share linearly in their value. - A time of 0 or below keeps the quick glide of about 0.1 s. - Each change starts from where the voice is now. Whatever was still planned is dropped, so a change never queues behind an older one. Firefox lacks cancelAndHoldAtTime, there the value is held by hand. - A voice still waiting on its bytes starts a timed change with the sound, so the whole sweep is heard. Tests: - node-catalog: time is handed on, a time below 0 is a quick glide. - sound-library: semitones and decibels ramp in their own steps, a timed change on a waiting voice starts with the sound. - sound-library + node-catalog + soundfx: 419 tests, green. - e2e 34 on melektaus-atx: ALL PASSED, 31 checks. A 2 s ramp from depth 7 to -5 read speed 0.979, 0.926 and 0.778 half a second on. - Counter-check: folding a timed change on a waiting voice into its start values fails the new test. - The gate did not run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ed2b58b3c0
commit
501a1524ed
9 files changed
+154
-29
No files matched your search
+2
-2
@@ -214,7 +214,7 @@ export type FakeContext = NodeContext & {
|
||||
fxParams: Readonly<Record<string, number>>;
|
||||
}[];
|
||||
silenced: string[];
|
||||
tuned: { voice: number; fxParams: Readonly<Record<string, number>> }[];
|
||||
tuned: { voice: number; fxParams: Readonly<Record<string, number>>; time: number }[];
|
||||
/** The scenes the context was asked to load, in order. */
|
||||
loaded: string[];
|
||||
/** The time scale and the pause the context holds, as the game nodes left them. */
|
||||
@@ -271,7 +271,7 @@ export function fakeContext(overrides: Partial<NodeContext> = {}): FakeContext {
|
||||
ctx.played.push({ assetId, volume, loop, detached, fx, fxParams }),
|
||||
stopSound: (assetId) => ctx.silenced.push(assetId),
|
||||
tuned: [],
|
||||
tuneSound: (voice, fxParams) => ctx.tuned.push({ voice, fxParams }),
|
||||
tuneSound: (voice, fxParams, time) => ctx.tuned.push({ voice, fxParams, time }),
|
||||
loadScene: (sceneId) => ctx.loaded.push(sceneId),
|
||||
spawn: () => null,
|
||||
addJoint: () => null,
|
||||
|
||||
Reference in new issue
Block a user