如何

播放声音和音乐


如何播放声音和音乐

Babylon.js声音引擎基于 Web Audio规范。我们决定不提供音频标签或其他机制的后备。因此,要使用我们的声音引擎,您需要使用与Web Audio兼容的浏览器。尽管如此,如果你在不兼容的浏览器上使用它,它不会打破我们引擎的其余部分,它只会播放没有声音。声音引擎提供环境声音,空间声音和定向声音。它可以通过代码或加载.babylon文件来创建。它将遵循您将要看到的引擎其余部分的简单而强大的理念。支持的声音格式是浏览器中的声音格式。它通常至少是.mp3和.wav。

注意:在操场上演示的所有音乐样本都是由 David Rousset创作的

创建环境声音或音乐

以下是创建声音或音乐播放为环境(非空间化)的代码:

// Load the sound and play it automatically once ready
var music = new BABYLON.Sound("Music", "music.wav", scene, null, { loop: true, autoplay: true });
  • 第一个参数: 声音的名称。
  • 第二个参数:要加载的声音的URL。
  • 第三个参数:附加声音的场景。
  • 第四个参数:一旦声音准备好播放,功能就会被回叫,我们稍后会看到。
  • 第五个参数:提供各种选项的JSON对象,我们将详细介绍。但您已经可以理解所提供的2个选项的目标。

您可以将第一个样本测试到我们的游乐场:

https://www.babylonjs-playground.com/#PCY1J -


Handling 处理'准备播放'回调函数

使用URL 调用BABYLON.Sound()构造函数会生成两个阶段:

  1. 使用异步XHR从您的Web服务器加载.wav或.mp3文件
  2. 一旦加载,声音就会被网络音频异步解码。如果成功,它会提升您提供的回调功能。

这是一个示例代码:

var music = new BABYLON.Sound("Music", "music.wav", scene,
 function () {
  // Sound has been downloaded & decoded
  music.play();
 }
);

此代码从Web服务器加载“ music.wav ”文件,解码并使用play()函数仅在回调函数中播放一次。如果没有参数传递,播放功能会立即播放声音。您可以提供类型编号的参数以在x秒后播放声音。

在我们的操场上测试:

https://www.babylonjs-playground.com/#PCY1J#1 -


在鼠标点击或keydown上播放声音

如果您左键单击或按空格键,此示例代码会发出枪声:

var gunshot = new BABYLON.Sound("gunshot", "sounds/gunshot.wav", scene);

window.addEventListener("mousedown", function (evt) {
    // left click to fire
    if (evt.button === 0) {
        gunshot.play();
    }
});

window.addEventListener("keydown", function (evt) {
    // Press space key to fire
    if (evt.keyCode === 32) {
        gunshot.play();
    }
});

在我们的操场上测试:

https://www.babylonjs-playground.com/#PCY1J#4 -


一些基本属性

您可以通过选项对象或通过setVolume()函数设置声音的音量。您可以以相同的方式设置播放速率。

当声音已经完成,通过注册自己到打你也可以通知onended事件。

这是一个混合所有这些的简单示例代码:

var volume = 0.1;
var playbackRate = 0.5;
var gunshot = new BABYLON.Sound("Gunshot", "./gunshot-1.wav", scene, null, { playbackRate: playbackRate, volume: volume });

gunshot.onended = function () {
    if (volume < 1) {
        volume += 0.1;
        gunshot.setVolume(volume);
    }
    playbackRate += 0.1;
    gunshot.playbackRate = playbackRate;
};

首先使用playbackRate为0.5和音量为0.1 创建声音。每次你将播放声音,最后,将调用onended函数,音量和playbackRate将增加。

您可以使用音频引擎的setGlobalVolume()函数设置Babylon.js播放的所有声音的全局音量,而不是根据特定声音设置音量。

BABYLON.Engine.audioEngine.setGlobalVolume(0.5);

Playing 同时播放多个声音并同步

为此,只有在您确定已准备好播放之后,才需要在所有声音上调用播放方法。然后,您需要使用准备播放回调。

var music1 = new BABYLON.Sound("Violons11", "sounds/violons11.wav", scene,
    soundReady, { loop: true });
var music2 = new BABYLON.Sound("Violons18", "sounds/violons18.wav", scene,
    soundReady, { loop: true });
var music3 = new BABYLON.Sound("Cellolong", "sounds/cellolong.wav", scene,
    soundReady, { loop: true });

var soundsReady = 0;

function soundReady() {
    soundsReady++;
    if (soundsReady === 3) {
        music1.play();
        music2.play();
        music3.play();
    }
}

在我们的操场上测试:

https://www.babylonjs-playground.com/#PCY1J#6 -


从ArrayBuffer加载声音

如果您使用自己提供的ArrayBuffer调用构造函数,则可以绕过第一个阶段(嵌入式XHR请求)。

以下是演示它的示例代码:

var gunshotFromAB;
loadArrayBufferFromURL("sounds/gunshot.wav");

function loadArrayBufferFromURL(urlToSound) {
    var request = new XMLHttpRequest();
    request.open('GET', urlToSound, true);
    request.responseType = "arraybuffer";
    request.onreadystatechange = function () {
        if (request.readyState == 4) {
            if (request.status == 200) {
                gunshotFromAB = new BABYLON.Sound("FromArrayBuffer", request.response, scene, soundReadyToBePlayed);
            }
        }
    };
    request.send(null);
}

function soundReadyToBePlayed() {
    gunshotFromAB.play();
}

在我们的操场上测试:

https://www.babylonjs-playground.com/#PCY1J#2 -


这是另一个我们从麦克风加载音频文件捕获声音的例子: https://playground.babylonjs.com/#MB5S2C#2 -


使用资产管理器加载声音

资产管理器非常有用,因为它可以处理一些很棒的功能,例如加载屏幕。

var music1, music2, music3;

// Assets manager
var assetsManager = new BABYLON.AssetsManager(scene);

var binaryTask = assetsManager.addBinaryFileTask("Violons18 task", "sounds/violons18.wav");
binaryTask.onSuccess = function (task) {
    music1 = new BABYLON.Sound("Violons18", task.data, scene, soundReady, { loop: true });
}

var binaryTask2 = assetsManager.addBinaryFileTask("Violons11 task", "sounds/violons11.wav");
binaryTask2.onSuccess = function (task) {
    music2 = new BABYLON.Sound("Violons11", task.data, scene, soundReady, { loop: true });
}

var binaryTask3 = assetsManager.addBinaryFileTask("Cello task", "sounds/cellolong.wav");
binaryTask3.onSuccess = function (task) {
    music3 = new BABYLON.Sound("Cello", task.data, scene, soundReady, { loop: true });
}

var soundsReady = 0;

function soundReady() {
    soundsReady++;
    if (soundsReady === 3) {
        music1.play();
        music2.play();
        music3.play();
    }
}

assetsManager.load();

在我们的操场上测试:

https://www.babylonjs-playground.com/#PCY1J#8 -


创建空间3D声音

要将声音转换为空间声音,您需要通过选项指定:

var music = new BABYLON.Sound("music", "music.wav",
    scene, null, { loop: true, autoplay: true, spatialSound: true });

空间声音的默认属性是:

  • distanceModel(衰减)默认使用“ 线性 ”方程。其他选项是“ 反向 ”或“ 指数 ”。
  • maxDistance设置为100。这意味着一旦听众离声音超过100个单位,音量将为0.你再也听不到声音了
  • panningModel设置为“ HRTF ”。该规范说:“ 一种更高质量的空间化算法,使用卷积测量来自人类受试者的脉冲响应。这种平移方法呈现立体声输出 “。这是使用耳机时的最佳算法。另一个可用选项是“等功率 ”。

maxDistance仅在使用“ 线性 ”衰减时使用。否则,您可以使用rolloffFactor和refDistance选项调整其他模型的衰减。两者都默认设置为1,但您当然可以更改它。

例如:

var music = new BABYLON.Sound("music", "music.wav",
    scene, null, {
        loop: true, autoplay: true, spatialSound: true,
        distanceModel: "exponential", rolloffFactor: 2
    });

3D世界中声音的默认位置是(0,0,0)。要更改它,请使用setPosition()函数:

music.setPosition(new BABYLON.Vector3(100, 0, 0));

为了更好地理解,请在我们的操场上看一下这个样本:

https://www.babylonjs-playground.com/#2AH4YH -


使用键盘和鼠标移动到场景中。每个声音都由紫色球体表示。当你进入一个球体时,你会开始听到一个音乐。球体中心的声音越大,离开球体时声音越低。

将声音附加到网格上

这可能是处理场景中3D声音的最简单方法。只需创建一个BABYLON.Sound,将其附加到现有网格上即可完成!如果网格正在移动,声音将随之移动。你无事可做。

这是要使用的代码:

var music = new BABYLON.Sound("Violons", "sounds/violons11.wav", scene, null, { loop: true, autoplay: true });

// Sound will now follow the box mesh position
music.attachToMesh(box);

在声音上调用attachToMesh()函数会将其自动转换为空间3D声音。使用上面的代码,您将陷入默认的Babylon.js值:maxDistance为100 的线性衰减和“ HRTF ” 类型的平移模型。

把你的耳机放到我们的操场上:

https://www.babylonjs-playground.com/index.html?23

创建空间定向3D声音

默认情况下,空间声音是全向的。但是如果你愿意,你可以有定向声音。

注意: 方向声音仅适用于连接到网格的空间声音。

这是要使用的代码:

var music = new BABYLON.Sound("Violons", "violons11.wav", scene, null, { loop: true, autoplay: true });
music.setDirectionalCone(90, 180, 0);
music.setLocalDirectionToMesh(new BABYLON.Vector3(1, 0, 0));
music.attachToMesh(box);

setDirectionalCone有3个参数:

  • coneInnerAngle: 内锥的大小(以度为单位)
  • coneOuterAngle: 外锥的大小
  • coneOuterGain: 当您在外锥体之外时声音的音量(介于0.0和1.0之间)

锥体的外角必须高于或等于内角,否则将记录错误并且定向声音将不起作用。

setLocalDirectionToMesh()只是与您所附着的网格相关的圆锥的方向。默认情况下,它是(1,0,0)。

您可以在我们的游乐场玩这个样本,以便更好地理解输出:

https://www.babylonjs-playground.com/#1BO0YS -


进入3D场景。如果你在灰色圆锥体所定义的空间内,你应该听到音乐,如果没有,你将听不到它,因为coneOuterGain被设置为0。

创建自己的自定义衰减功能

如果要使用特定算法管理衰减(或Web Audio中的距离模型),可以使用Babylon.js自定义衰减功能绕过本机Web Audio衰减。

注意: Web Audio是“ 硬件加速 ”。这意味着它主要由设备上的专用音频芯片通过本机代码(浏览器)处理。然后,这在3D实时渲染的性能方面几乎没有任何成本。切换到自定义衰减将使用基于JavaScript的Babylon.js距离计算,并且速度会变慢。

此外,自定义衰减仅适用于空间声音(显然),但也适用于连接到Babylon.js网格的声音。也就是说,让我们现在查看代码来做到这一点。首先,您必须在选项中指定它:

// Create and load the sound async
var music = new BABYLON.Sound("Music", "music.wav", scene, null, { loop: true, autoplay: true, useCustomAttenuation: true });

您将切换到内部Babylon.js数学计算。默认的自定义衰减功能是线性的。

要创建自己的逻辑,需要这样的代码:

// Creating custom attenuation function. Near the object, volume is almost 0.
// The farest, the louder
music.setAttenuationFunction(function (currentVolume, currentDistance, maxDistance, refDistance, rolloffFactor) {
    return currentVolume * currentDistance / maxDistance;
});

你可以玩这5个参数,并用它做任何你想做的事情。只需返回一个数字即将应用于声音的音量。

在这个例子中,逻辑有点奇怪,因为音量越大,离网格越远。;-)

在我们的游乐场玩它:

https://www.babylonjs-playground.com/#1YIXEO -


此外,Firefox目前在处理正确线性衰减的Web Audio实现中存在一个错误。这可以通过使用Babylon.js默认线性自定义衰减来修复。

这是以前的示例代码,现在可以在Firefox中正常运行:

https://www.babylonjs-playground.com/#2AH4YH#2 -


操纵从.babylon文件加载的声音

目前只有我们的3DS Max导出器可以将声音直接导出到.babylon。

要访问Babylon.js .babylon文件加载器加载的声音,您需要在场景对象上使用getSoundByName()函数。

这是一个简单的示例加载.babylon场景文件嵌入一些声音:

var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas, true);
BABYLON.SceneLoader.Load("TestScene/", "testsound.babylon", engine, function (newScene) {
    newScene.executeWhenReady(function () {
        newScene.activeCamera.attachControl(canvas);

        var gunshotSound = newScene.getSoundByName("gunshot-1.wav");
        window.addEventListener("keydown", function (evt) {
            if (evt.keyCode === 32 && gunshotSound) {
                    gunshotSound.play();
            }
        });

        engine.runRenderLoop(function () {
            newScene.render();
        });
    });
}, function (progress) {
    // To do: give progress feedback to user
});

按空格键将播放枪声。

使用声轨

在几个轨道上隔离音乐和声音以更好地管理分组声音实例的音量可能很有用。它还将在未来的版本中用于在特定轨道上应用效果。

默认情况下,Babylon.js正在创建一个BABYLON.SoundTrack对象作为其主轨道。每当你创建一个新的BABYLON.Sound时,它都会为你添加到这个主轨道中。

var soundTrack = new BABYLON.SoundTrack(scene);
soundTrack.AddSound(cellolong);
soundTrack.AddSound(violons11);

使用此代码,“ cellolong ”和“ violons11 ”声音将从主Babylon.js音轨移动到此特定音轨。现在,这意味着您可以独立于主轨道更改此轨道的音量,从而更改这两个声音的音量。

所述AddSound()函数将移动从其原始容器中,以指定的新音轨的声音(在主轨道或特定轨道)。例如,使用以下代码:

var soundTrack1 = new BABYLON.SoundTrack(scene);
soundTrack1.AddSound(cellolong);
soundTrack1.AddSound(violons11);

var soundTrack2 = new BABYLON.SoundTrack(scene);
soundTrack2.AddSound(violons11);

“ violons11 ”声音最终只会出现在“ soundTrack2 ”中。

使用分析器

您可以轻松实时分析音频。

了解其工作原理的最简单代码是:

var myAnalyser = new BABYLON.Analyser(scene);
BABYLON.Engine.audioEngine.connectToAnalyser(myAnalyser);
myAnalyser.drawDebugCanvas();

这将连接到音频引擎的全局音量,并将所有一起播放的声音的频率绘制到屏幕顶部的2D画布显示中。

您可以更改调试画布的位置和大小,并在声道而不是全局音频引擎上使用分析器:

var myAnalyser = new BABYLON.Analyser(scene);
soundTrack1.connectToAnalyser(myAnalyser);
myAnalyser.DEBUGCANVASSIZE.width = 160;
myAnalyser.DEBUGCANVASSIZE.height = 100;
myAnalyser.DEBUGCANVASPOS.x = 40;
myAnalyser.DEBUGCANVASPOS.y = 30;
myAnalyser.drawDebugCanvas();

您也可以称自己为分析器功能,以创建自己的使用方法。

这是一个完整的示例:

https://www.babylonjs-playground.com/#PTV7W#1 -