A voice used to end the moment its sources did, and Stop sound cut it dead. An echo has to outlive its sound, and a stop must not click. - Delay node: a delay line with a damped feedback loop, added at mix next to the untouched sound. Time 0.01 to 2 s, feedback up to 0.95, damping 20 kHz to 500 Hz evenly in octaves, all fed by parameters and moved by Set sound FX parameters like any other number. - Ping-pong is a setting of the node. It takes the sound into the left of the line and swaps the sides every round. - A voice with an echo rings on for its tail: until the last echo is 60 dB below the sound, from time, feedback and mix (fxTailOf). It stays reachable meanwhile, and a change counts the tail again. - The end of a tail is timed on the audio clock with a silent ConstantSourceNode, so a paused run holds it. Then the voice is disconnected, since an echo is a loop of nodes. - Stop sound fades a voice out in 10 ms instead of cutting it. Let ring fades only its sources and keeps the voice for its echoes. Where the context is suspended it cuts at once. - Stop sound takes a voice. Connected, it stops only that play, and a 0 from a Play sound that played nothing stops nothing. - Play sound hands out tail: length plus the echoes at its start values. - Destroying a behavior and ending a run still cut, echoes included. - No limit on voices. The emit of a sound FX node now also gets the node's settings. Finding: in Chrome every round of a feedback loop comes one render quantum late (128 samples, 2.7 ms at 48 kHz), measured as 0, 128, 256, 384 for the first four echoes. Left so, since a browser without it would then hear the echoes early. Written in the wiki. Tests: - sound-library, soundfx, node-catalog, sounds, keep-on-scene-load: 489 tests green. New: fade on stop, cut while suspended, echo and ping-pong wiring, ringing until the tail, tail counted again, let ring, stop by voice, echo knobs, delay compile, tail sums. - Counter-checks: no tail, a stop without fade, a connected voice 0 read as unconnected. Each fails its tests, files back by cmp. - e2e 34 (melektaus-atx): ALL PASSED, 37 checks. A blip through a ping-pong Delay (0.3 s, 0.5, 0.5) rang 2.97 s, 2.95 s worked out. Let ring kept the voice, a stop after it cut it. Rendered offline with the player's own stageNodes the echoes are 0.25 left, 0.125 right, 0.063 left. 64 stereo voices of it took about 0.3 s for 2 s, so about 400 play at once. - Gate (melektaus-atx): CHECK EXIT 0, 242 test files, 3713 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6e70421b92
commit
cf6799a784
16 files changed
+987
-72
No files matched your search
@@ -1980,14 +1980,15 @@ const CASES: Record<string, Case[]> = {
|
||||
name: 'no sound is a no-op that still continues the flow',
|
||||
inputs: { sound: '', volume: 1, loop: '' },
|
||||
next: 'exec',
|
||||
outputs: { voice: 0, length: 0 },
|
||||
outputs: { voice: 0, length: 0, tail: 0 },
|
||||
after: (ctx) => expect(ctx.played).toEqual([]),
|
||||
},
|
||||
{
|
||||
name: 'hands the id on with the volume and loop it was given, and gives out the voice (#315) and its length',
|
||||
name: 'hands the id on with the volume and loop it was given, and gives out the voice (#315), its length and its tail (#324)',
|
||||
inputs: { sound: 'snd-1', volume: 0.5, loop: 'true' },
|
||||
next: 'exec',
|
||||
outputs: { voice: 1, length: 0.25 },
|
||||
// The fake context rings a voice on for its number in tenths of a second.
|
||||
outputs: { voice: 1, length: 0.25, tail: 0.35 },
|
||||
// What the two mean – a factor on the asset's volume, an answer that overrules its loop
|
||||
// flag – is the BehaviorSystem's to resolve, since only it holds the project (see
|
||||
// `sounds.test.ts`).
|
||||
@@ -2066,6 +2067,24 @@ const CASES: Record<string, Case[]> = {
|
||||
next: 'exec',
|
||||
after: (ctx) => expect(ctx.silenced).toEqual(['']),
|
||||
},
|
||||
{
|
||||
name: 'lets the echoes of the sound ring when asked to (#324)',
|
||||
inputs: { sound: 'snd-1', letRing: true },
|
||||
next: 'exec',
|
||||
after: (ctx) => expect(ctx.silenced).toEqual(['snd-1 (let ring)']),
|
||||
},
|
||||
{
|
||||
name: 'with a voice connected silences only that one, whatever sound is named',
|
||||
inputs: { sound: 'snd-1', voice: 3, letRing: true },
|
||||
next: 'exec',
|
||||
after: (ctx) => expect(ctx.silenced).toEqual(['voice 3 (let ring)']),
|
||||
},
|
||||
{
|
||||
name: 'a connected voice of 0 – a Play sound that played nothing – silences nothing, not everything',
|
||||
inputs: { sound: '', voice: 0 },
|
||||
next: 'exec',
|
||||
after: (ctx) => expect(ctx.silenced).toEqual([]),
|
||||
},
|
||||
],
|
||||
SetSoundFxParameters: [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user