duck
Added in 6.5.0
Turn a target down while one of its trigger sounds plays, and bring it back up when the last trigger stops. The usual case is music that makes room for a voice. See Ducking for how it works underneath.
duck(target: string | string[], options: DuckOptions): () => void;
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
target | string | string[] | required | What goes down. A sound id, a group, a stream or a variation name, or a list of them. |
options | DuckOptions | required | The triggers and the shape of the duck, see below. |
DuckOptions
| Property | Type | Default | Description |
|---|---|---|---|
when | string | string[] | required | The sound, group, stream or variation whose playing turns the target down. One name or several. |
amount | number | 0.3 | The level the target drops to, from 0 (silent) to 1 (no change). |
attack | number | 0.05 | Seconds to go down once a trigger starts. |
release | number | 0.5 | Seconds to come back up after the last trigger stops. |
The full type is on the DuckOptions page.
Returns
() => void: a function that removes the duck again. It does the same as unduck, for every target you passed.
Example
import { SoundHub } from 'soundhub';
const soundHub = new SoundHub();
await soundHub.loadSounds([
{ id: 'music', url: '/audio/theme.mp3' },
{ id: 'voice', url: '/audio/line-01.mp3' },
]);
soundHub.duck('music', { when: 'voice', amount: 0.3 });
soundHub.play('music', { loop: true });
soundHub.play('voice'); // the music drops to 30% in 50 ms
// and comes back over half a second when the voice ends
A group of lines as the trigger
soundHub.createSoundGroup('dialogue');
soundHub.duck(['music', 'ambience'], {
when: 'dialogue',
amount: 0.25,
attack: 0.1,
release: 0.8,
});
soundHub.play('line-12', { groupId: 'dialogue' });
soundHub.play('line-13', { groupId: 'dialogue' });
// The music and the ambience stay down until the second line has finished
Removing it again
const removeDuck = soundHub.duck('music', { when: 'voice' });
// Later, when the cutscene is over
removeDuck();
How names match
Every name in target and when is compared against:
- a sound id, such as
'music' - the sound its overlapping instances came from, so
'laser'covers'laser:3' - the sound a sprite was cut from, so
'ui'covers the sprite'ui_click' - a group name
- a stream id
- a variation name from
createVariations
Good to know
- Only a trigger you can hear counts. A paused or muted trigger does not duck, and resuming or unmuting it takes the target down again.
- Several triggers, or overlapping instances of one, keep the target down until the last of them stops.
- The duck has a gain node of its own between the target and the master bus. The target's volume, mute and any fade in progress are left alone, so a
setSoundVolumeduring a duck is still there after it. - The duck follows the triggers whether the target plays or not. A sound that starts while its trigger plays starts at the ducked level.
- A sound that joins a target group later, with
addToSoundGroup, is routed through the duck from then on. - A sound never ducks itself, even when it matches both a target and a trigger name.
- Calling
duck()again for the same target replaces its options. When the target is down at that moment, it glides from its current level to the newamountover the newattack, without going back up first and without a secondduck_started. amountis clamped to 0 to 1, and a negativeattackorreleasecounts as 0.- An empty target or an empty
whenthrows an error. - The target is checked on every change in playback, including a play, pause, resume or stop with
skipDispatchEvent, which dispatches no event. duck_startedandduck_endedarrive on the event bus with the target assoundIdand the level asvolume.
See also
- Ducking: the idea, the routing and the events.
unduck: remove a duck.isDucked: whether a target is down right now.getDuckLevel: the level it is down to.