Omnitone is a robust implementation of
ambisonic decoding and binaural
rendering written in Web Audio API. Its rendering process is powered by the fast
native features from Web Audio API (GainNode and ConvolverNode), ensuring
optimum performance.
The implementation of Omnitone is based on the Google spatial media specification and SADIE's binaural filters. It also powers Resonance Audio SDK for web.
If you are looking for interactive panning based on Omnitone's ambisonic rendering, be sure to check out the Resonance Audio Web SDK project!
Omnitone offers ambisonic decoding and binaural rendering of:
- First-order-ambisonic stream (4 channels)
- Higher-order-ambisonic stream (2nd order / 9 channels and 3rd order / 16 channels)
- Bundler & SSR support (
#105):build/omnitone.jsandbuild/omnitone.min.jsare now built as UMD modules (working both as a<script>global and viarequire('omnitone')), paired with"module"and"exports"entry points inpackage.jsonforimport Omnitone from 'omnitone'and browser global guards for Node / SSR environments. - CSP compatibility without
'unsafe-eval'(#106,#147): RewroteBufferList.load()aroundPromise.alland removednew Function(), so Omnitone runs under strict Content Security Policies. - Setters work before
initialize()resolves (#102,#145):setChannelMap(),setRotationMatrix3(),setRotationMatrix4(),setRotationMatrixFromCamera(), andsetRenderingMode()(as well as constructor-suppliedrenderingMode: 'bypass' | 'off') now apply immediately upon renderer construction and persist across HRIR initialization. - Clean promise rejection handling (
#146,#150): Load and decode failures inBufferList,FOARenderer, andHOARenderernow reject the returned promise cleanly without throwing uncaught exceptions or leaking duplicateunhandledrejectionevents fromdecodeAudioData(). - Correctness fixes (
#143,#144): Fixed destination indices and sign mapping inHOARotator.prototype.getRotationMatrix3(), and renamedOmnitone.splitBufferbyChanneltoOmnitone.splitBufferByChannel(fixing an internalbufflerListreference error inUtils.mergeBufferListByChannel). - Modernized toolchain (
#148,#149): Upgraded build, lint, and test infrastructure to Node>=20, Rollup 4,@web/test-runner(headless Chrome), ESLint 8, and GitHub Actions CI.
The input audio stream can be either an HTMLMediaElement (<video> or
<audio> tag) or a multichannel AudioBufferSourceNode. The rotation of the
sound field can also be easily linked to a device's orientation sensor or
on-screen camera interaction.
Include the library file in an HTML document from Google's CDN:
<script
src="https://www.gstatic.com/external_hosted/omnitone/build/omnitone.min.js">
</script>
<script>
// `Omnitone` object is loaded and ready.
const audioContext = new AudioContext();
const foaRenderer = Omnitone.createFOARenderer(audioContext);
</script>Alternatively, install Omnitone as part of your local development via NPM:
npm install omnitoneOmnitone provides both ES module and UMD/CommonJS entry points for bundlers:
import Omnitone from 'omnitone';
// or: const Omnitone = require('omnitone');
const audioContext = new AudioContext();
const foaRenderer = Omnitone.createFOARenderer(audioContext);You can also git clone the repository and use the library files in build/:
git clone https://github.com/GoogleChrome/omnitone.gitFOARenderer decodes and renders a first-order-ambisonic stream (4 channels).
// Set up an audio element to feed the ambisonic source audio feed.
const audioElement = document.createElement('audio');
audioElement.src = 'audio-file-foa-acn.wav';
// Create AudioContext, MediaElementSourceNode and FOARenderer.
const audioContext = new AudioContext();
const audioElementSource = audioContext.createMediaElementSource(audioElement);
const foaRenderer = Omnitone.createFOARenderer(audioContext);
// Make connection and start play. Hook up the user input for the playback.
foaRenderer.initialize().then(function() {
audioElementSource.connect(foaRenderer.input);
foaRenderer.output.connect(audioContext.destination);
// This is necessary to activate audio playback out of autoplay block.
someButton.onclick = () => {
audioContext.resume();
audioElement.play();
};
});HOARenderer decodes and renders higher-order-ambisonic streams. Omnitone
supports 2nd and 3rd order ambisonics, which consist of 9 channels and 16
channels respectively.
// Works the same way as FOARenderer. See the usage above.
const hoaRenderer = Omnitone.createHOARenderer(audioContext);The rotation matrix in an Omnitone renderer can be updated inside your
application's animation loop to rotate the entire sound field. Omnitone supports
both 3x3 and 4x4 rotation matrices (column-major). Setter calls made before
initialize() resolves are preserved automatically.
// Rotation with 3x3 or 4x4 matrix.
renderer.setRotationMatrix3(rotationMatrix3);
renderer.setRotationMatrix4(rotationMatrix4);For example, if you want to hook up a Three.js perspective camera:
renderer.setRotationMatrix4(camera.matrixWorld.elements);Use setRenderingMode (or pass {renderingMode} to the renderer constructor)
to change the operation of the decoder. This is useful when switching between
spatial media (ambisonic) and non-spatial media (mono or stereo), or when saving
CPU power by disabling the decoder.
// Mono or regular multi-channel layouts.
renderer.setRenderingMode('bypass');
// Use ambisonic rendering.
renderer.setRenderingMode('ambisonic');
// Disable encoding completely (audio processing disabled).
renderer.setRenderingMode('off');For development, clone the repository and run the following scripts to build the library. Omnitone uses Rollup to bundle the sources.
npm ci # install dependencies.
npm run build # build omnitone library files.
npm run build-doc # build JSDoc documentation.
npm run eslint # run ESLint against source and test files.Omnitone uses GitHub Actions and
Web Test Runner for
automated testing. The test suite requires the promisified version of
OfflineAudioContext, so it runs in a locally installed Chrome. Running
npm test rebuilds the bundles first, so the tests never run against a stale
build/omnitone.min.js.
npm testThe test suite requires a Chromium-based browser, so the following setup might be necessary on Linux distros without one installed.
sudo apt install google-chrome-stableOmnitone is designed to run on any browser that supports Web Audio API; however,
it does not address incompatibility issues around media codecs across browsers.
Decoding compressed multichannel audio with more than 3 channels via <video>
or <audio> elements may not be supported on some mobile browsers.
Special thanks to Boris Smus, Brandon Jones, Dillon Cower, Drew Allen, Julius Kammerl and Marcin Gorzel for their help on this project. We are also grateful to Tim Fain and Jaunt VR for their permission to use beautiful VR contents in the demo.
If you have found an error in this library, please file an issue at: https://github.com/GoogleChrome/omnitone/issues.
Patches are encouraged, and may be submitted by forking this project and submitting a pull request through GitHub. See CONTRIBUTING for more detail.
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
