Skip to main content

Migrating from Howler.js

Added in 6.5.0

soundhub/howler is a separate entry point with the Howler.js API, Howl and Howler, on top of soundhub. Change the import and the code you have keeps running:

-import { Howl, Howler } from 'howler';
+import { Howl, Howler } from 'soundhub/howler';

const sfx = new Howl({
src: ['/audio/sfx.webm', '/audio/sfx.mp3'],
sprite: { laser: [0, 400], coin: [500, 300] },
onend: (id) => console.log('done', id),
});
const id = sfx.play('laser');
sfx.volume(0.5, id);

Then remove howler from your dependencies. The entry point is 3.7 KB gzipped on top of the main package, and it uses the soundhub you install rather than carrying a copy of it.

npm uninstall howler
npm install soundhub

What is covered​

AreaCovered
new Howl() optionssrc, volume, loop, rate, mute, sprite, autoplay, preload, html5, and the callbacks onload, onloaderror, onplayerror, onplay, onend, onpause, onstop, onmute, onvolume, onrate, onseek, onfade, onunlock
Howl methodsplay, pause, stop, mute, volume, fade, rate, seek, loop, playing, duration, state, stereo, pos, load, unload, on, once, off
Howlervolume, mute, stop, unload, codecs, ctx, masterGain
Voice idsplay() returns a numeric id, also before the file has loaded, and every method takes it as the last argument

The details of each method are on the Howl and Howler pages.

What is not covered​

  • Howler.autoSuspend, Howler.autoUnlock, Howler.html5PoolSize, Howler.usingWebAudio and Howler.noAudio.
  • Howler.pos, Howler.orientation and howl.orientation.
  • pannerAttr and the other per-Howl panner settings.
  • The format, pool and xhr options. TypeScript flags them, since they are not in HowlOptions.
  • The stereo, pos and orientation events.

Use the hub for those, see below. The hub unlocks audio on the first touch by itself, and autoUnlock and autoSuspend are in its config.

Units​

The units are Howler's, not soundhub's, so nothing in your code has to change:

WhereUnit
sprite ranges, [offset, duration]milliseconds
fade(from, to, duration)milliseconds
seek() and duration()seconds

When you move a call over to the hub itself, keep in mind that soundhub uses seconds everywhere. A Howler sprite [500, 300] is [0.5, 0.8] as a start and end in setSoundSprite.

One hub underneath​

Every Howl is a sound in one shared SoundHub, and Howler.hub hands it to you. howl.soundhubId is the id of a Howl in that hub. So you can move over one feature at a time, and use what Howler has no answer for:

import { Howl, Howler } from 'soundhub/howler';
import { SoundEventsEnum } from 'soundhub';

const music = new Howl({ src: '/audio/music.mp3', loop: true });
const voice = new Howl({ src: '/audio/voice.mp3' });

// Music that drops while the voice plays
Howler.hub.duck(music.soundhubId, { when: voice.soundhubId });

// One typed event bus for every Howl
Howler.hub.addEventListener(SoundEventsEnum.DUCK_STARTED, () => {
subtitles.show();
}, { soundId: music.soundhubId });

A sprite of a Howl is the sound <soundhubId>_<name> in the hub, so the laser sprite above is `${sfx.soundhubId}_laser`. Every play() of a Howl is an overlapping instance in the hub, such as 'howl1:3'. A filter on soundId reaches the Howl in events such as duck_started, and originalId reaches its voices in started, ended and progress.

Configuring the hub​

Howler.configure() sets the SoundHubConfig of the shared hub. Call it before the first Howl:

import { Howl, Howler } from 'soundhub/howler';

Howler.configure({ masterLimiter: true, debug: false });

const sfx = new Howl({ src: '/audio/sfx.mp3' });
  • The hub is made once, by the first new Howl() or the first use of Howler.hub, ctx, masterGain, volume, mute or codecs. configure() after that throws an error.
  • Without a config the hub starts with autoMuteOnHidden: false and trackProgress: false, since Howler has neither. Pass them to configure() to turn them on.
  • After Howler.unload() the next Howl makes a new hub, with the config you set.

Differences you may notice​

  • html5: true streams the file through loadStream. The stream stays in the Web Audio graph, so volume and fades go through the same nodes as every other sound. It has one voice at a time and no sprites, as in Howler.
  • preload: 'metadata' loads the whole file, the same as true.
  • onend fires at the end of every pass of a loop, as in Howler.
  • onfade fires from a timer set to the fade duration.
  • Howler.mute(true) mutes the master bus, so a Howl that starts afterwards is muted too.

See also​

  • Howl: the constructor options and every method.
  • Howler: the global object.
  • Ducking and Variations: two things to reach for through Howler.hub.