Introduction

SopaJS is a JavaScript library package for reproducing panoramic sounds on the Web browser. It is an open source package provided under the MIT license.

<We are not affiliated with the SOPA (Safety Observation Performance Analysis) web app.>

By using SopaJS, you can make Web sites full of immersive panoramic sounds. As long as JavaScript is supported in the browser, panoramic sounds can be played without any plugins.

Repository
https://github.com/KaoruAshihara/SopaJS

If you are interested in creating panoramic sounds on your own, see Create and share panoramic sound.

Contents of the package

SopaJS package contains 2 JavaScript (.js) files, 2 binary (.bin) files and a sample project. They are listed below.

[JavaScript files]

Sopa.js contains source code of the library and Sopa.min.js is its minified version.

[Binary files]

Two binary files (hrtf3d512.bin and phase3d512.bin) convey the database of the HRTF (Head Related Transfer Function). Both of them are needed to generate binaural signals from the SOPA data.

[Sample project]

The sample project consists of the following files.

Its working demo can be found HERE. Although the sample project is very simple, by using SopaJS, you can make much more powerful pages like the pages below.

Getting started

To use the library, you have to put either "Sopa.js" or "Sopa.min.js" and the binary files (hrtf3d512.bin and phase3d512.bin) in your Web server.

You have to create an HTML file and a JavaScript file. Alternatively, you can create an HTML file with JavaScript code. Place them also in the server.

Program code

Code Reference

Constructor

To generate the panoramic sound from a SOPA file, you have to construct an instance of "Sopa".

In SopaJS, the constructor is defined as follows.


Sopa = function(url){};

If the name of the instance is "sopa," for instance, the constructor of the Sopa instance in your JavaScript code looks like the following.


	sopa = new Sopa(url);

The parameter of the constructor is the location of the SOPA file to be reproduced. If you want to play
"https://unit.aist.go.jp/hiri/hi-infodesign/as_ss0/ railway.sopa,"
the constructor can be like this.


	sopa = new Sopa("https://unit.aist.go.jp/hiri/hi-infodesign/as_ss0/railway.sopa");
This parameter can be changed afterward by the method 'setUrl.'

Methods

To play panoramic sounds, at least the following methods have to be called.

The following methods are also available.

LoadDatabase(hrtf,phase) starts loading the HRTF data from the binary files. The arguments "hrtf" and "phase" are the locations of "hrtf3d512.bin" and "phase3d512.bin", respectively.

LoadSopaData() starts loading the SOPA data from the SOPA file.

Once the instance ('sopa' in this case) is constructed, you can call "loadDatabase()" and "loadSopaData()" in code below.


	sopa.loadDatabase(hrtf,phase);
	sopa.loadSopaData();

Sopa.setup() has to be called after the HRTF data and SOPA data has been loaded successfully. You can check if loading the HRTF data is completed or not by calling databaseReady(). If it returns "false," the HRTF data have not been loaded yet.

To check if the SOPA data are loaded or not, you can call fftWinSize(). It returns the FFT window size that is specified in the SOPA file. If it returns 0, the SOPA data are not yet loaded.

When databaseReady() returns "true" and fftWinSize() is a power of 2, you can call setup().

If setup() returns "true," you can start repdoducing panoramic sound by calling Play().

Consequently, code to start reproducing panoramic sound will be like the following.


var fsize = sopa.fftWinSize();
if(sopa.databaseReady() && fsize > 0 && (fsize & (fsize - 1)) == 0){
	if(sopa.setup()){
		sopa.Play();
	}
}

Setup() returns "false," in case either when "AudioContext" is not supported or when the SOPA data are not available.

When you want to stop the reproduction, call Play() again.

In SopaJS 1.1, the SOPA file can be played in either 'single play' mode or 'loop playback' mode. In the 'loop playback' mode, the browser keeps on playing the sound until Play() is called. You can select the 'single play' mode by calling setLastLoop(true) before or during the reproduction.

If setLastLoop(true) is called in advance, the browser automatically stops reproducing the sound at the end of the SOPA file.

You can get the current sample position in the reproduction by calling totalOffset(). In the 'loop playback' mode, this value can be greater than the total samples of the SOPA file.

Pan and tilt

Pan of the sound can be changed by calling setPan(deg). The argument is the horizontal angle in degrees. It should be between -180 and 179.

Tilt can be changed by calling setTilt(deg). The argument, "deg" in this case, should be between -90 and 89.

If you want to pan to the right by 60 degrees and tilt up 30 degrees, you can use code below.


	sopa.setPan(-60);	// 60 degrees to the right from the default position
	sopa.setTilt(30);	// tilt 30 degrees above the horizon

Directionality

In reproducing SOPA data, 3 directionality modes are available. They are "Omnidirectional(default)," "Cardioid," and "Cardioid2." To select the mode, call setCardioid(toggle,focusHor,focusVer).

The first argument has to be 0, 1, or 2. 0 is for "Omnidirectional." 1 and 2 are for "Cardioid" and "Cardioid2," respectively.

The second and third arguments are the horizontal angle and the vertical angle of the target direction in radians.

If you want to use "Cardioid2" directionality targetting to the front (facing direction), code is supposed to be like below.


	sopa.setCardioid(2,0,0);

Sounds from the rear will be suppressed.

When you want to suppress sounds from the front, the following code can be used.


	sopa.setCardioid(2,Math.PI,0);

Sample project

In the sample project, it is assumed that the directory tree looks like the figure below.

directory tree
Fig. Directory tree of the sample project

A SOPA file ("cygne22k.sopa"), JavaScript file ("sopaTest.js") and an HTML file ("test_page.html.") are in the same directory. Two binary files and "Sopa.min.js" are in the upper directory.

HTML

In this sample project, the locations of the SOPA file and binary files are specified in the HTML file (test_page.html).


< div id="sopaUrl" style="display:none"> cygne22k.sopa< /div> 
< div id="hrtfUrl" style="display:none"> ../hrtf3d512.bin< /div> 
< div id="phaseUrl" style="display:none"> ../phase3d512.bin< /div> 

In test_page.html, 4 button elements are defined in the lines from 17 to 32 and lines from 44 to 47.

In lines 57 and 58, JavaScript files are linked to the HTML.


< script src="../Sopa.min.js">< /script>
< script src="sopaTest.js">< /script>

If the directory tree of your project is not like the one in the figure above, you have to modify code adequately.

JavaScript

In the JavaScript file (sopaTest.js), the Sopa instance is constructed in the following lines (lines 22 and 23).


	var sopaElem = document.getElementById("sopaUrl");
	sopa = new Sopa(sopaElem.innerHTML);    // Constructor of a SOPA instance

LoadDatabase() is called in line 37 to start loading the HRTF databases.


	sopa.loadDatabase(hrtfStr,phaseStr);	// Load HRTF databases

The arguments 'hrtfStr' and 'phaseStr' are the locations of "hrtf3d512.bin" and "phase3d512bin," respectively

In line 38, loadSopaData() is called to start loading the SOPA file.


	sopa.loadSopaData();	// Load SOPA data

After checking if fftWinSize() is a power of 2 and databaseReady() is "true" in line 111, the "PLAY" button is enabled in line 114. When this button is clicked, setup() is called in line 71. If setup() returns "true," the reproduction of panoramic sound is started by calling Play() in line 75.

Play() is called again in line 87 to stop the reproduction.

Panning

When the listener clicks the "LEFT" button or the "RIGHT" button, setPan(anglHor) is called (lines 46 and 59).


	sopa.setPan(anglHor);

The argument ("anglHor" in this case) is the horizontal angle in degrees. The horizontal angle increases or decreases by 5 degrees each time the "LEFT" or "RIGHT" button is clicked.

Since tilt control is not implemented in this sample project, only pan of the sound can be changed.

Directionality mode

In this sample project, the listener can toggle among 3 directionality modes, "Omnidirectional," "Cardioid," and "Cardioid2." This is done by the following code in lines 36 and 97.


	sopa.setCardioid(toggle,focusHor,focusVer);

If the first argument is 0, the "Ominidirectional" mode is selected. 1 is for the "Cardioid" and 2 is for the "Cardioid2," respectively. The second and third arguments are the horizontal angle and vertical angle of the target direction in radians. In this project, both of them are fixed to 0 radian. The target direction is, therefore, the facing direction (assuming that the listener is facing to the screen) and when the "Cardioid" or "Cardioid2 " mode is selected, sounds from the rear are suppressed.

For further information, see the document.

License

SopaJS is provided under MIT license.