Make a bus of the mix at its level, so a quiet bus starts quiet
A bus of the project's mix was made at unity and then glided to its level. Where the audio context comes with the first sound of a run, that sound already plays on the new bus. On a bus at volume 0 it was heard for a moment, loud, while the level glided down. - setMix now sets the level of a bus it makes at once, without a glide. A bus that is there already glides to a new level as before. - Found while building #436: the e2e check with a sound on a bus at volume 0 measured -7.8 dB on that bus. With the fix it is silent. Tests: - New unit test in sound-library: buses made at their level with no glide, a later change glides. Red without the fix. - sound-library 130/130, tsc clean on this change alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
70402aa19a
commit
dd2096e0df
2 files changed
+29
-1
No files matched your search
@@ -909,10 +909,15 @@ export class SoundLibrary implements AudioSink {
|
||||
const names = new Set(this.mix.map((bus) => bus.name));
|
||||
const waits: Promise<void>[] = [];
|
||||
for (const { name, volume, into, sends, fx } of this.mix) {
|
||||
const made = !this.buses.has(name);
|
||||
const bus = this.bus(name, into);
|
||||
if (sends) this.setSends(bus, sends);
|
||||
else this.route(name, bus, into);
|
||||
this.glideLevel(bus, this.mixVolumes.get(name) ?? volume);
|
||||
const level = this.mixVolumes.get(name) ?? volume;
|
||||
// A bus made now is at its level at once: made with the context, it carries the first sound of
|
||||
// a run, which would otherwise be heard through a glide down from unity (found by #436).
|
||||
if (made) this.setLevel(bus, level);
|
||||
else this.glideLevel(bus, level);
|
||||
waits.push(this.setFx(bus, fx));
|
||||
}
|
||||
const gone = [...this.buses.keys()].filter(
|
||||
@@ -923,6 +928,13 @@ export class SoundLibrary implements AudioSink {
|
||||
await Promise.all(waits);
|
||||
}
|
||||
|
||||
/** The level of a bus at `gain` from now on, without a glide. */
|
||||
private setLevel(bus: Bus, gain: number): void {
|
||||
const to = Math.max(0, gain);
|
||||
bus.gain.gain.value = to;
|
||||
bus.set = { ...bus.set, gain: to };
|
||||
}
|
||||
|
||||
/** A quick glide of the level of a bus to `gain`. */
|
||||
private glideLevel(bus: Bus, gain: number, time = 0, ease: EaseShare = 'linear'): void {
|
||||
const to = Math.max(0, gain);
|
||||
|
||||
@@ -2539,6 +2539,22 @@ describe('the master and the buses of the project (#325)', () => {
|
||||
expect(wires.filter((wire) => wire.endsWith('> destination'))).toEqual(['panner > destination']);
|
||||
});
|
||||
|
||||
it('makes a bus at its level, so the first sound of a run on a quiet bus is not heard gliding down (#436)', async () => {
|
||||
const library = new SoundLibrary(false);
|
||||
await library.setMix(mix);
|
||||
await play(library);
|
||||
expect(library.busLevels().map(({ name, level }) => [name, level])).toEqual([
|
||||
['mix', 0.5],
|
||||
['mix:a', 1],
|
||||
['mix:b', 0.25],
|
||||
]);
|
||||
expect(gains.filter((gain) => gain.glides.length > 0)).toEqual([]);
|
||||
// One there already glides to a new level, as before.
|
||||
await library.setMix([bus('mix', 0.25, null), mix[1]!, mix[2]!]);
|
||||
expect(library.busLevels()[0]).toMatchObject({ gain: 0.25, level: 0.5 });
|
||||
expect(gains.some((gain) => gain.glides.includes(0.25))).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps the mix where the first thing heard is a tab of a song, which names its bus before there is a context', async () => {
|
||||
const library = new SoundLibrary(false);
|
||||
await library.setMix(mix);
|
||||
|
||||
Reference in new issue
Block a user