Skip to main content

addEventListener

Listen for one kind of event on the hub's event bus. Every sound dispatches through the same bus, so the optional filter narrows it down to the sound you care about.

addEventListener(type: SoundEventsEnum, callback: (event: SoundEvent) => void, filter?: SoundEventFilter): () => void;

Parameters​

ParameterTypeDefaultDescription
typeSoundEventsEnumrequiredThe event to listen for. See soundEvents for the full list.
callback(event: SoundEvent) => voidrequiredCalled for every matching event.
filterSoundEventFilternoneNarrows which sounds the callback hears. Left out, it hears every sound.

SoundEventFilter​

All fields are optional and combine with AND.

PropertyTypeDescription
soundIdstringExactly this sound. The common case.
originalIdstringEvery overlapping instance of one sound, played with overlap.
instanceIdstringOne specific instance.
instancePatternRegExpInstances whose id matches a pattern.

Returns​

() => void: a function that removes this listener. That is easier to hold on to than keeping the same callback and filter around for removeEventListener.

Example​

import { SoundHub, SoundEventsEnum } from 'soundhub';

const soundHub = new SoundHub();
await soundHub.loadSound('music', '/audio/theme.mp3');

// Every sound, every start
soundHub.addEventListener(SoundEventsEnum.STARTED, (event) => {
console.log('started:', event.soundId);
});

// Just this one, with no id check in the callback
soundHub.addEventListener(SoundEventsEnum.PROGRESS, (event) => {
progressBar.value = event.progressInfo!.progress;
}, { soundId: 'music' });

soundHub.play('music', { trackProgress: true });

Removing a listener​

const off = soundHub.addEventListener(SoundEventsEnum.VOLUME_CHANGED, (event) => {
volumeLabel.textContent = `${Math.round(event.volume! * 100)}%`;
}, { soundId: 'music' });

// Later, on unmount or when the panel closes
off();

Every instance of one sound​

Sounds played with overlap get their own ids (laser:1, laser:2, and so on), and their events carry the base id as originalId:

await soundHub.loadSound('laser', '/audio/laser.mp3');
let activeLasers = 0;

soundHub.addEventListener(SoundEventsEnum.STARTED, () => {
activeLasers += 1;
}, { originalId: 'laser' });

soundHub.addEventListener(SoundEventsEnum.ENDED, () => {
activeLasers -= 1;
}, { originalId: 'laser' });

soundHub.play('laser', { overlap: true });
soundHub.play('laser', { overlap: true });

Good to know​

  • Reach for soundId first. Only the started, ended and progress events carry originalId and instanceId, so a filter on those fields never hears events such as stopped, paused or volume_changed.
  • instancePattern is only tested when the event has an instanceId. An event without one gets through the pattern.
  • A listener with an instanceId filter is removed automatically when that sound or instance stops, ends or is cleaned up. The ended event still reaches it first.
  • An error thrown inside your callback is caught and logged to the console, so the other listeners still run.
  • SoundEventFilter is exported from the package, as is SoundEventsEnum.

See also​