Skip to content

Audio Components

Orillusion provides basic audio playback capabilities to users by encapsulating Web Audio API:

  • AudioListener - Virtual audio listener, used in conjunction PositionAudio or StaticAudio
  • StaticAudio - non-positional audio,volume level does not vary depending on the position of the monitor
  • PositionAudio - position based audio,volume varying based on the relative position of the monitor

Static Audio

Non-positional audio source,e.g. background music, global sound effects etc.

ts
import {AudioListener, StaticAudio} from '@orillusion/media-extention'

// A virtual listener, for static audios, can be any objects, take scene for example
let listener = scene.addComponent(AudioListener)

// create a static source audio object
let audioObj = new Object3D()
let staticAudio = audioObj.addComponent(StaticAudio)
// linked to the listener
staticAudio.setLisenter(listener)
// load source url
await staticAudio.load('https://cdn.orillusion.com/audio.ogg')
// play the sound/music, the volume does not vary depending on the position of the listener or source
staticAudio.play()

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { StaticAudio, AudioListener } from '@orillusion/media-extention';
import * as dat from 'dat.gui';

class Static_Audio {
    lightObj: Object3D;
    scene: Scene3D;
    camera: Object3D;
    mats: any[];
    audio: StaticAudio;
    constructor() {}

    async run() {
        Engine3D.setting.shadow.autoUpdate = true;
        Engine3D.setting.shadow.updateFrameRate = 1;
        Engine3D.setting.shadow.type = 'HARD';
        Engine3D.setting.shadow.shadowBound = 100;

        await Engine3D.init();
        this.scene = new Scene3D();
        this.scene.addComponent(AtmosphericComponent);

        this.camera = new Object3D();
        this.camera.localPosition = new Vector3(0, 20, 50);
        let mainCamera = this.camera.addComponent(Camera3D);
        this.scene.addChild(this.camera);

        mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
        let orbit = this.camera.addComponent(OrbitController);
        orbit.target = new Vector3(0, 4, 0);
        orbit.minDistance = 10;
        orbit.maxDistance = 200;

        let view = new View3D();
        view.scene = this.scene;
        view.camera = mainCamera;

        Engine3D.startRenderView(view);
        await this.initScene();
    }

    async initScene() {
        {
            let wall = new Object3D();
            let mr = wall.addComponent(MeshRenderer);
            mr.geometry = new BoxGeometry(40, 30, 1);
            let mat = new LitMaterial();
            mat.baseColor = new Color(1, 0, 0);
            mr.material = mat;
            this.scene.addChild(wall);
            wall.z = -5;
        }
        {
            let floor = new Object3D();
            let mr = floor.addComponent(MeshRenderer);
            mr.geometry = new BoxGeometry(3000, 1, 3000);
            let mat = new LitMaterial();
            mr.material = mat;
            this.scene.addChild(floor);
        }

        /******** light *******/
        {
            this.lightObj = new Object3D();
            this.lightObj.rotationX = 35;
            this.lightObj.rotationY = 110;
            this.lightObj.rotationZ = 0;
            let directLight = this.lightObj.addComponent(DirectLight);
            directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
            directLight.castShadow = true;
            directLight.intensity = 30;
            this.scene.addChild(this.lightObj);
        }
        {
            let group = new Object3D();
            let speaker = await Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf');
            speaker.localScale.set(4, 4, 4);
            speaker.rotationX = -120;
            //speaker.y = 1.5
            group.addChild(speaker);
            group.y = 2;
            this.scene.addChild(group);

            let listener = this.camera.addComponent(AudioListener);
            let audio = group.addComponent(StaticAudio);
            audio.setLisenter(listener);

            await audio.load('https://cdn.orillusion.com/audio.ogg');

            let buttons = {
                play: () => {
                    audio.play();
                },
                pause: () => {
                    audio.pause();
                },
                stop: () => {
                    audio.stop();
                },
                volume: 1
            };
            let gui = new dat.GUI();
            gui.addFolder('Orillusion');
            gui.add(buttons, 'play');
            gui.add(buttons, 'pause');
            gui.add(buttons, 'stop');
            gui.add(buttons, 'volume', 0, 1, 0.01).onChange((v) => {
                audio.setVolume(v);
            });
        }
    }
}

new Static_Audio().run();

Position Audio

Playback of audio based on 3D spatial location via PannerNode, where the direction and volume of the sound is relative to the position of the receiver and the source.

ts
import {AudioListener, PositionAudio} from '@orillusion/media-extention'

let movingObj = new Object3D()
// add a virtual listener,usually to moving objects, e.g add to camera to simulate user position in 3D sapce
let listener = movingObj.addComponent(AudioListener)

// create a position audio object
let audioObj = new Object3D()
let positionAudio = audioObj.addComponent(PositionAudio)
// set audio physical parameters, ref to PannerNode API
positionAudio.refDistance = 10;
positionAudio.maxDistance = 100;
positionAudio.setDirectionalCone( 180, 230, 0.1 ); // coneInnerAngle, coneOuterAngle, coneOuterGain
...
// display a helper to view the ocation, direction, and behavior of an audio source
positionAudio.showHelper()

// linked to the listener
positionAudio.setLisenter(listener)
// load the source url
await positionAudio.load('https://cdn.orillusion.com/audio.ogg')

// play the audio, volume varying based on the relative position of the listener
positionAudio.play()

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { BoxGeometry, Camera3D, DirectLight, Engine3D, LitMaterial, KelvinUtil, MeshRenderer, Object3D, Scene3D, Vector3, Color, OrbitController, View3D, AtmosphericComponent } from '@orillusion/core';
import { PositionAudio, AudioListener } from '@orillusion/media-extention';
import * as dat from 'dat.gui';

class Position_Audio {
    lightObj: Object3D;
    scene: Scene3D;
    camera: Object3D;
    mats: any[];
    audio: PositionAudio;
    private a = 40;
    private b = 80;
    private angle = 0;
    constructor() {}

    async run() {
        Engine3D.setting.shadow.autoUpdate = true;
        Engine3D.setting.shadow.updateFrameRate = 1;
        Engine3D.setting.shadow.type = 'HARD';
        Engine3D.setting.shadow.shadowBound = 100;

        await Engine3D.init({
            renderLoop: this.loop.bind(this)
        });
        console.log(1);
        this.scene = new Scene3D();
        this.scene.addComponent(AtmosphericComponent);

        this.camera = new Object3D();
        this.camera.localPosition = new Vector3(0, 20, 50);
        let mainCamera = this.camera.addComponent(Camera3D);
        this.scene.addChild(this.camera);

        mainCamera.perspective(60, Engine3D.aspect, 0.1, 20000.0);
        let orbit = this.camera.addComponent(OrbitController);
        orbit.target = new Vector3(0, 4, 0);
        orbit.minDistance = 10;
        orbit.maxDistance = 200;

        let view = new View3D();
        view.scene = this.scene;
        view.camera = mainCamera;

        Engine3D.startRenderView(view);
        await this.initScene();
    }

    async initScene() {
        {
            let wall = new Object3D();
            let mr = wall.addComponent(MeshRenderer);
            mr.geometry = new BoxGeometry(40, 30, 1);
            let mat = new LitMaterial();
            mat.baseColor = new Color(1, 0, 0);
            mr.material = mat;
            this.scene.addChild(wall);
            wall.z = -5;
        }
        {
            let floor = new Object3D();
            let mr = floor.addComponent(MeshRenderer);
            mr.geometry = new BoxGeometry(3000, 1, 3000);
            let mat = new LitMaterial();
            mr.material = mat;
            this.scene.addChild(floor);
        }

        /******** light *******/
        {
            this.lightObj = new Object3D();
            this.lightObj.rotationX = 35;
            this.lightObj.rotationY = 110;
            this.lightObj.rotationZ = 0;
            let directLight = this.lightObj.addComponent(DirectLight);
            directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
            directLight.castShadow = true;
            directLight.intensity = 30;
            this.scene.addChild(this.lightObj);
        }
        {
            let [speaker, man, music] = await Promise.all([Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/speaker/scene.gltf'), Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/glb/CesiumMan.glb'), fetch('https://cdn.orillusion.com/audio.ogg').then((res) => res.arrayBuffer())]);
            speaker.localScale.set(4, 4, 4);
            speaker.rotationX = -120;
            speaker.y = 0.5;
            let group = new Object3D();
            group.addChild(speaker);
            group.y = 2;
            this.scene.addChild(group);

            man.name = 'man';
            man.scaleX = 10;
            man.scaleY = 10;
            man.scaleZ = 10;
            man.rotationX = -90;
            man.rotationY = -90;
            man.localPosition.set(0, 0.5, 30);
            this.scene.addChild(man);

            let listener = man.addComponent(AudioListener);
            let audio = group.addComponent(PositionAudio);
            audio.setLisenter(listener);
            await audio.loadBuffer(music);
            audio.refDistance = 10;
            audio.maxDistance = 100;
            audio.setDirectionalCone(180, 230, 0.1);
            audio.showHelper();

            let buttons = {
                play: () => {
                    audio.play();
                },
                pause: () => {
                    audio.pause();
                },
                stop: () => {
                    audio.stop();
                },
                volume: 1,
                'Toggle Helper': () => {
                    audio.toggleHelper();
                }
            };
            let gui = new dat.GUI();
            gui.addFolder('Orillusion');
            gui.add(buttons, 'play');
            gui.add(buttons, 'pause');
            gui.add(buttons, 'stop');
            gui.add(buttons, 'volume', 0, 1, 0.01).onChange((v) => {
                audio.setVolume(v);
            });
            gui.add(buttons, 'Toggle Helper');
        }
    }
    loop() {
        let man = this.scene.getChildByName('man') as Object3D;
        if (man) {
            this.angle += 0.005;
            man.x = this.a * Math.cos(this.angle);
            man.z = this.b * Math.sin(this.angle) + 30;
            man.rotationY -= (0.005 * 180) / Math.PI;
        }
    }
}

new Position_Audio().run();

Released under the MIT License