Binaural
This library permits to render sources in three-dimensional space with binaural audio.
This library provides an access to a server, in order to load a set of Head-related transfer functions (HRTF). The set of filters applies to any number of sources, given their position, and a listener.
This library is compatible with the Web Audio API. The novelty of this library is that it permits to use a custom HRTF dataset (see T. Carpentier article).
It is possible to use it without a server, with a direct URL to an HRTF set.
Documentation
You can consult the API documentation for the complete documentation.
BinauralPanner
A BinauralPanner is a panner for use with the Web Audio API. It
spatialises multiple audio sources, given a set of head-related transfer
functions HRTFs, and a listener.
ServerDataBase
The public server that hosts a database of individual HRTFs is available for beta-testers only and will open to public in 2016.
The ServerDataBase retrieves a catalogue from a SOFA server. From the
catalogue, it get URLs matching optional filters: data-base, sample-rate,
and any free pattern.
HRTF dataset
You can use any HRTF data-set that follows the SOFA standard, in JSON format, using finite impulse responses (FIR). Second-order sections (SOS) are not supported, yet. See the examples HRTF directory for a few samples.
Coordinate system types
See the files in src/geometry, for conversions:
- OpenGL, SOFA, and Spat4 (Ircam) conventions
- cartesian and spherical coordinates
- radian and degree angles
Examples
Please see the examples directory for complete code (on branch
gh-pages), and the examples online.
See also the API documentation for the complete options.
BinauralPanner
Given an audio element, and a global binaural module,
<html>
<head>
<script src="../binaural.js"></script>
</head>
<body>
<audio id="source" src="./snd/breakbeat.wav" controls loop></audio>
</body>
</html>
create a source audio node,
var audioContext = new AudioContext();
var $mediaElement = document.querySelector('#source');
var player = audioContext.createMediaElementSource($mediaElement);
instantiate a BinauralPanner and connect it.
var binauralPanner = new binaural.audio.BinauralPanner({
audioContext,
crossfadeDuration: 0.05, // in seconds
coordinateSystem: 'sofaSpherical', // [azimuth, elevation, distance]
sourceCount: 1,
sourcePositions: [ [0, 0, 1] ], // initial position
});
binauralPanner.connectOutputs(audioContext.destination);
binauralPanner.connectInputByIndex(0, player);
Load an HRTF set (this returns a Promise).
binauralPanner.loadHrtfSet(url)
.then(function () {
console.log('loaded');
})
.catch(function (error) {
console.log('Error while loading ' + url + error.message);
});
Then, any source can move:
$azimuth.on("input", function(event) {
// get current position
var position = binauralPanner.getSourcePositionByIndex(0);
// update azimuth
position[0] = event.target.value;
binauralPanner.setSourcePositionByIndex(0, position);
// update filters
window.requestAnimationFrame(function () {
binauralPanner.update();
});
});
Note that a call to the update method actually updates the filters.
ServerDataBase
Instantiate a ServerDataBase
var serverDataBase = new binaural.sofa.ServerDataBase();
and load the catalogue from the server. This returns a promise.
var catalogLoaded = serverDataBase.loadCatalogue();
Find URLs with HRIR convention, COMPENSATED equalisation, and a
sample-rate matching the one of the audio context.
var urlsFound = catalogLoaded.then(function () {
var urls = serverDataBase.getUrls({
convention: 'HRIR',
equalisation: 'COMPENSATED',
sampleRate: audioContext.sampleRate,
});
return urls;
})
.catch(function(error) {
console.log('Error accessing HRTF server. ' + error.message);
});
Then, a BinauralPanner can load one of these URLs.
urlsFound.then(function(urls) {
binauralPanner.loadHrtfSet(urls[0])
.then(function () {
console.log('loaded');
})
.catch(function (error) {
console.log('Error while loading ' + url
+ error.message);
});
});
Issues
- re-sampling is broken on full set (Chrome 48 issue): too many parallel audio contexts?
- clicks on Firefox 44-45 (during update of
convolver.buffer, becauseAudioContext.currentTimedoes not advance) - ServerDataBase: avoid server with free pattern filter?
To do
- attenuation with distance
- dry/wet outputs for (shared) reverberation
- support for infinite impulse responses, once IIRFilterNode is implemented.
Developers
The source code is in the src directory, in ES2015 standard. npm run
compile with Babel to the dist directory. Note that there is a
.babelrc file. npm run bundle runs the linters, the tests,
generates the documentation, and compiles the code.
Commit the source files to the branch develop, and update the version in
package.json if this is intended to be a release.
On the master branch, merge from the develop branch. Generate and
commit the documentation and the distribution files. Put a release tag that
corresponds to the version in package.json.
On the gh-pages branch, merge from the master branch. Commit the
examples, and the extra files (audio and HRTF set files).
Style
npm run lint to check that the code conforms with .eslintrc and
.jscsrc files. The rules derive from AirBnB with these
major points:
- ES2015
- no
'use strict'globally (already there via babel) - enforce curly braces (
if,for, etc.) - allow spaces and new lines, with fewer requirements: use them for clarity
Test
For any function or method, there is at least a test. The hierarchy in the test directory is the same as in the src directory.
npm run testfor all automated testsnpm run test-listenfor supervised listening tests. The test files must end with_listen.jsnpm run test-issuesfor unsolved issues. The issues may depend on the host: operating system, user-agent, sound-device, sample-rate, etc. The test files must end with_issues.js. Once an issue is solved, the corresponding tests are added to the automated test set.npm run test-browserstarts a server for running the tests in any browser.
Examples for specific testing, when developing or resolving an issue:
browserify test/geometry/test_Listener.js -t babelify | tape-runin a headless browserbrowserify test/geometry/test_Listener.js -t babelify | testling -ufor an URL to open in any browser
Documentation
Document any public function and method with JSDoc, and generate the HTML
pages with npm run doc. At this point, neither
jsdoc nor
esdoc gives perfect
transcription. (See the jsdoc.json and esdoc.json files.)
License
This module is released under the BSD-3-Clause license.
Acknowledgements
This research was developped by both Acoustic And Cognitive Spaces and Analysis of Musical Practices IRCAM research teams. A previous version was part of the WAVE project, funded by ANR (French National Research Agency). The current version, supporting multiple sources and a listener, the SOFA standard, and the access to a server, is part of the CoSiMa project, funded by ANR.