For starters, the API is low level and complex. For the simple background music or sound effect, web audio can feel like trying to take a sip of water out of a firehose. (For the record, it should stay that way — to build complex audio experiences, you need something that offers a lot of control.) While there are libraries out there that offer abstractions over web audio, we’ve found them old and outdated. A coworker of mine once said, “Whenever an audio plugin related bug is discovered, instead of quickly fixing it and moving on, we need to spend a whole day debugging internal implementation [of our 3rd party library].”
I’m here to say that there’s a new way forward. Over the last six months, I’ve been working on Sonorous- a new open source audio library. Sonorous is easy to use, clear to follow, and built with today’s standards in mind.
Sonorous abstracts the complexity of web audio.
Just to start playing a sound, web audio requires several set up steps.
Sonorous reduces this to 3 lines of code.
Sonorous provides other major advantages other than ease-of-use. If the web audio APIs weren’t tricky enough to understand on their own, there’s the added complexity of each browser implementing the APIs differently. For example, Chrome may allow you to call stop() on a source node before it’s been started, but Safari will throw an error and crash your program. On the other hand, sometimes Safari will fail to initialize an AudioContext but won’t throw an error, and Chrome would. In many browsers now, you are unable to start playing audio without a user interaction first. This is just the tip of the iceberg, but Sonorous handles all of this for you. It’s abstracted by the library, so your code can remain clean and concise.
While well-defined architecture is thrilling (to me, at least), I’m more excited to talk about Sonorous’s memory management. Audio buffers, once decoded, can be huge. Unfortunately, audio files must be decoded to be played back. And with Howler, as soon as the sound is loaded, the decoded buffer is kept in memory at runtime. 60 seconds of uncompressed audio translates to 23MB of memory at runtime. If your program contains just 20 minutes’ worth of audio files, all loaded at once, that’s over 460MB of memory, which is more than enough to cause an iOS Safari tab to crash instantly. Sonorous gives you the option of storing the encoded buffer or the decoded buffer when the sound loads. If you store the encoded buffer, it would only be decoded when play() is called. Once the play operation finishes, the decoded buffer would be removed again. There might be a lag before playing if the audio file is large, but this solution offers more control over how much memory this library uses when not playing a sound.
At eko, we integrated Sonorous into our audio plugin. Any sound effects or background music played in any of our videos now come through Sonorous. There’s a simple bridge in place for backwards compatibility- any projects that assume the audio plugin uses Howler will receive a wrapped version of Sonorous that matches the Howler API. The audio plugin also adds functionality on top of Sonorous- the ability to link the sound effect playback to video playback (play when the video plays, pause when the video pauses), the ability to load sound effects relative to when they need to be played in the video, etc. Head to eko.com and watch any video to see Sonorous in action!
Sonorous is an easy to use audio library for the modern age. Whether you’re building a complex game with lots of audio or just adding background music to your website, Sonorous can help you. It hides the complications of working with audio across browsers and is built with the modern browser in mind. If you’re already using Howler, the switch to Sonorous should be pretty painless. Sonorous is just getting started, and I’m excited to share it with you. If you’re as interested in this as I am, feel free to contribute! Sonorous is open source, and we welcome any and all looking to participate in Sonorous going forward.