JavaScript / HTML5中的声音效果


316

我正在使用HTML5对游戏进行编程;我现在遇到的障碍是如何播放音效。

具体要求数量很少:

  • 播放和混合多种声音,
  • 多次播放同一样本,可能会重复播放,
  • 随时中断样本播放,
  • 最好播放包含(低质量)原始PCM的WAV文件,但是我当然可以转换它们。

我的第一种方法是使用HTML5 <audio>元素并定义页面中的所有声音效果。Firefox只是播放桃花心的WAV文件,但#play多次调用实际上并不会多次播放示例。根据我对HTML5规范的理解,该<audio>元素还跟踪播放状态,因此可以解释原因。

我的直接想法是克隆音频元素,因此我创建了以下微型JavaScript库来为我做这件事(取决于jQuery):

var Snd = {
  init: function() {
    $("audio").each(function() {
      var src = this.getAttribute('src');
      if (src.substring(0, 4) !== "snd/") { return; }
      // Cut out the basename (strip directory and extension)
      var name = src.substring(4, src.length - 4);
      // Create the helper function, which clones the audio object and plays it
      var Constructor = function() {};
      Constructor.prototype = this;
      Snd[name] = function() {
        var clone = new Constructor();
        clone.play();
        // Return the cloned element, so the caller can interrupt the sound effect
        return clone;
      };
    });
  }
};

因此,现在我可以Snd.boom();从Firebug控制台进行播放snd/boom.wav,但是仍然不能多次播放相同的样本。似乎该<audio>元素实际上更多是流功能,而不是用来播放声音效果的东西。

有没有一种巧妙的方法可以使我想不到的事情发生,最好仅使用HTML5和JavaScript?

我还应该提到,我的测试环境是Ubuntu 9.10上的Firefox 3.5。我尝试过的其他浏览器-Opera,Midori,Chromium和Epiphany-产生了不同的结果。有些不玩任何东西,有些则抛出异常。


哈哈!我还在将旧的Macintosh游戏移植到HTML5。想要揭示您要克隆的那个吗?
带薪的书呆子

1
它是ARASHI项目,一个暴风雨副本。
斯蒂芬Kochen

“混合”声音是什么意思?
Mads Skjern

2
你完成了吗?可以看到吗?
enyo 2012年

4
可悲的是没有。我有一个不完成业余时间项目的诀窍。:(有它一个混帐回购协议,但我还没有碰过它在年:github.com/stephank/arashi-js
斯蒂芬Kochen

Answers:


448

HTML5 Audio对象

您无需理会<audio>元素。HTML 5使您可以直接访问Audio对象

var snd = new Audio("file.wav"); // buffers automatically when created
snd.play();

当前版本的规范不支持混合。

要多次播放相同的声音,请创建Audio对象的多个实例。您还可以snd.currentTime=0在对象播放完毕后对其进行设置。


由于JS构造函数不支持后备<source>元素,因此您应该使用

(new Audio()).canPlayType("audio/ogg; codecs=vorbis")

测试浏览器是否支持Ogg Vorbis。


如果您正在编写游戏或音乐应用程序(不仅仅是播放器),则需要使用更高级的Web Audio API大多数浏览器现在都支持API


18
Audio对象是自动缓冲的。它们的设计类似于Image对象,因此老式的图像预加载技术也适用于音频。
Kornel

5
这也适用于iOS。注意,尽管您需要使用某种用户操作(例如,单击按钮)来发出声音。您不能只snd.play()在window.load()上执行操作。
赫斯基

1
我仍在使用<audio>标签,因为它更易于控制。但是无论如何,感谢您的信息!
德里克·朕会功夫,

2
如果不是<audio> html5元素允许多个来源的事实,我希望使用此方法,因此,如果浏览器不支持mp3,则可以回退到ogg / wav。这将需要使用JavaScript的一些技巧才能完成。
joelmdev 2012年

2
在iOS 6上,支持自动播放:您可以在window.load()上使用简单的snd.play()来启动声音。
Pietro Polsinelli 2013年

36

W3C的WebAudio API

从2012年7月开始,Chrome现已支持WebAudio API,而Firefox至少已部分支持WebAudio API,并将于版本6起将其添加到IOS中。

尽管它足够健壮,可以通过编程方式用于基本任务,但Audio元素绝不意味着为游戏等提供完整的音频支持。它设计为允许将单个媒体嵌入页面中,类似于img。标签。尝试在游戏中使用音频标签存在很多问题:

  • 时序图在音频元素中很常见
  • 每个声音实例都需要一个Audio元素
  • 负载事件并不完全可靠
  • 没有通用的音量控制,没有褪色,没有滤镜/效果

我使用这篇“ WebAudio入门”文章来开始使用WebAudio API。该炮塔防御WebAudio案例也很好看。


这是比公认的更好的答案,因为它着重于解决问题的正确解决方案(WebAudio API),以及Audio元素不是一个好的解决方案的原因,而不是试图与Audio元素一起拼凑一个不好的解决方案
异常,发生

29

howler.js

对于游戏创作而言,最好的解决方案之一是使用一个库,该库可以解决我们在编写网络代码时遇到的许多问题,例如howler.js。howler.js将出色的(但底层的)Web Audio API抽象为易于使用的框架。如果Web音频API不可用,它将尝试回退到HTML5音频元素

var sound = new Howl({
  urls: ['sound.mp3', 'sound.ogg']
}).play();
// it also provides calls for spatial/3d audio effects (most browsers)
sound.pos3d(0.1,0.3,0.5);

wad.js

另一个很棒的库是wad.js,它对于产生合成器音频(例如音乐和效果)特别有用。例如:

var saw = new Wad({source : 'sawtooth'})
saw.play({
    volume  : 0.8,
    wait    : 0,     // Time in seconds between calling play() and actually triggering the note.
    loop    : false, // This overrides the value for loop on the constructor, if it was set. 
    pitch   : 'A4',  // A4 is 440 hertz.
    label   : 'A',   // A label that identifies this note.
    env     : {hold : 9001},
    panning : [1, -1, 10],
    filter  : {frequency : 900},
    delay   : {delayTime : .8}
})

游戏声音

与Wad.js类似的另一个库是“ Sound for Games ”,它更加注重效果的产生,同时通过相对独特的(也许更简洁的感觉)API提供了类似的功能集:

function shootSound() {
  soundEffect(
    1046.5,           //frequency
    0,                //attack
    0.3,              //decay
    "sawtooth",       //waveform
    1,                //Volume
    -0.8,             //pan
    0,                //wait before playing
    1200,             //pitch bend amount
    false,            //reverse bend
    0,                //random pitch range
    25,               //dissonance
    [0.2, 0.2, 2000], //echo array: [delay, feedback, filter]
    undefined         //reverb array: [duration, decay, reverse?]
  );
}

摘要

无论您是需要播放单个声音文件,还是需要创建自己的基于html的音乐编辑器,效果生成器或视频游戏,这些库中的每一个都值得一看。


无法评论游戏开发,但我将其用于界面中的一些次要音频反馈,并且它绝对有效。快速,轻松和简单。
Rid Iculous

确实不错的框架,在移动设备上也很好用。您必须通过touchstart触发它...但是一旦完成,它就可以立即使用:)
Philip

9

在某些情况下,您可能还想使用它来检测HTML 5音频:

http://diveintohtml5.ep.io/everything.html

HTML 5 JS检测功能

function supportsAudio()
{
    var a = document.createElement('audio'); 
    return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
}

感谢您的注意。我从has.js学习了这种方法,但是根据has.js源代码,我发现它在Firefox中以及在Opera中也存在一些问题。(参考文献:github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19
斯蒂芬Kochen

5

这是一种使同时播放相同声音成为可能的方法。与预加载器结合使用,一切就绪。至少可以在Firefox 17.0.1上运行,还没有进行其他测试。

// collection of sounds that are playing
var playing={};
// collection of sounds
var sounds={step:"knock.ogg",throw:"swing.ogg"};

// function that is used to play sounds
function player(x)
{
    var a,b;
    b=new Date();
    a=x+b.getTime();
    playing[a]=new Audio(sounds[x]);
    // with this we prevent playing-object from becoming a memory-monster:
    playing[a].onended=function(){delete playing[a]};
    playing[a].play();
}

将此绑定到键盘键,即可享受:

player("step");

不。我认为为每个声音播放创建一个新对象根本不是解决方案。这是一个快速而肮脏的解决方法,但这可以做得更好。
Pawel 2015年

@Pawel是的,不应将其用作播放声音的主要方法,但据我所知,该示例中的原理是唯一一次同时播放相同声音或如OP所表示的那样播放声音的唯一方法, “重叠播放”。(不需要浏览器插件。)我当前项目中的实际实现比发布的示例代码复杂得多。
F-3000

4

听起来像您想要的是多声道声音。假设您有4个频道(例如在非常古老的16位游戏中),我还没有全面了解HTML5音频功能,但是您是否只需要4个<audio>元素,并使用了循环播放下一个音效?你有尝试过吗?怎么了?如果可行:要同时播放更多声音,只需添加更多<audio>元素。

我之前没有HTML5 <audio>元素,使用来自http://flash-mp3-player.net/的一个Flash对象完成了此操作-我写了一个音乐测验(http://webdeavour.appspot.com/),当用户单击问题按钮时,用它来播放音乐片段。最初,每个问题只有一个播放器,可以将它们彼此叠加播放,因此我对其进行了更改,因此只有一个播放器,我指向的是不同的音乐片段。


使用&lt; audio&gt;是一个有趣的想法。元素作为渠道。当我在页面上放置两个元素时,可以同时播放它们。看来我正在执行的克隆操作实际上并没有达到我的期望,因为在我的原始代码中,播放两个样本也可以。只是同一样本的两倍而已。我将不得不对此进行更多试验,然后再返回结果!
斯蒂芬Kochen

是的,将其称为克隆而不是复制可能有一个微妙的原因。克隆版本可能仍与原始版本共享某些内容,从而阻止它们同时播放。
Lee Kowalkowski 09年

作为参考,至少在Firefox中,重新使用相同的<audio>元素无效。您可以设置'src'属性,但实际上不会加载其他示例。
斯蒂芬Kochen

4

看看jai(-> mirror)(javascript音频接口)站点。通过查看其来源,他们似乎在play()反复调用,并且提到它们的库可能适合在基于HTML5的游戏中使用。

您可以同时触发多个音频事件,这些事件可用于创建Javascript游戏或通过某些背景音乐进行语音播放


3

要多次播放相同的样本,不可能做这样的事情:

e.pause(); // Perhaps optional
e.currentTime = 0;
e.play();

e是音频元素)

也许我完全误解了您的问题,您是否希望声音效果同时播放多次?那么这是完全错误的。


没错,我需要同时播放同一样本多次。
斯蒂芬Kochen

是的,它多次播放相同的实例,但对于正在查看此答案的人们,只需注意,这不会引起OP措辞的“重叠播放”。
Patrick Roberts

3

这是个主意。将特定类别的声音的所有音频加载到单个单独的音频元素中,其中src数据是连续音频文件中的所有样本(可能希望之间保持一定的沉默,以便您可以以更短的超时捕获和剪切样本)出血至下一个样本的风险)。然后,寻找样本并在需要时播放。

如果您需要播放其中一个以上的声音,则可以创建一个具有相同src的附加音频元素,以便对其进行缓存。现在,您实际上有多个“轨道”。您可以使用自己喜欢的资源分配方案(如Round Robin等)利用轨道组。

您还可以指定其他选项,例如在该资源可用时将声音排队到要播放的曲目中或剪切当前正在播放的样本。



2

我建议使用SoundJS,这是我帮助开发的一个库。它使您可以编写可在任何地方使用的单一代码库,SoundJS可以根据需要选择Web音频,html音频或Flash音频。

它可以让您做所有您想做的事情:

  • 播放和混合多种声音,
  • 多次播放相同的样本,可能会重复播放
  • 随时中断样本播放
  • 播放包含的WAV文件(取决于浏览器支持)

希望能有所帮助。


那库真棒,我真的很喜欢sfx生成器。是时候对感兴趣的任何人
RozzA,2015年


1

我在编程音乐盒卡生成器时遇到了这个问题。从不同的库开始,但每次都会出现故障。普通音频实现的延迟很糟糕,没有多次播放...最终使用lowlag库+ soundmanager结束了:

http://lowlag.alienbill.com/http://www.schillmania.com/projects/soundmanager2/

您可以在此处查看实现:http : //musicbox.grit.it/

我为多个浏览器播放生成了wav + ogg文件。此音乐盒播放器可在ipad,iphone,Nexus,mac,pc等设备上响应。


这是一个不错的Musicbox应用!你有一个git仓库吗?我可能会和我们的孩子一起使用它!
icarito

0

我知道这是一个完全的hack,但是我想我应该添加我之前放在github上的这个示例开源音频库...

https://github.com/run-time/jThump

单击下面的链接后,在主行键上键入以播放蓝调即兴演奏(也可以同时键入多个键等)。

使用jThump库的示例>> http://davealger.com/apps/jthump/

它基本上是通过制作不可见的<iframe>元素来加载可在onReady()上播放声音的页面来工作的。

这当然不是理想的选择,但是您可以仅基于创造力(并且它是开源的,并且可以在我尝试过的任何浏览器中使用)就可以对该解决方案+1,我希望这至少可以使其他人搜索到一些想法。

:)


为什么有人对此投下反对票?对我来说似乎是一个可行的选择。
jtrick 2014年

这是一个非常hacky的解决方案,但是我已经使用此库制作了一个示例html 5 canvas游戏,因此它仍然可以正常工作...使用此库的游戏在这里 -beepbox.net
DaveAlger 2014年

0

所选答案将适用于除IE之外的所有内容。我写了一个关于如何使其在跨浏览器中工作的教程= http://www.andy-howard.com/how-to-play-sounds-cross-browser-includes-ie/index.html

这是我写的函数;

function playSomeSounds(soundPath)
 {

 var trident = !!navigator.userAgent.match(/Trident\/7.0/);
 var net = !!navigator.userAgent.match(/.NET4.0E/);
 var IE11 = trident && net
 var IEold = ( navigator.userAgent.match(/MSIE/i) ? true : false );
 if(IE11 || IEold){
 document.all.sound.src = soundPath;
 }
 else
 {
 var snd = new Audio(soundPath); // buffers automatically when created
 snd.play();
 }
 };

您还需要将以下标记添加到html页面:

<bgsound id="sound">

最后,您可以调用该函数并在此处简单地通过路径:

playSomeSounds("sounds/welcome.wav");

0

您可以随时尝试AudioContext获得有限的支持,但这是Web音频api工作草案的一部分。如果您计划将来发布某些内容,那可能是值得的。而且,如果您只为chrome和Firefox编程,那您就很成功了。


0

var AudioContextFunc = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContextFunc();
var player=new WebAudioFontPlayer();
var instrumVox,instrumApplause;
var drumClap,drumLowTom,drumHighTom,drumSnare,drumKick,drumCrash;
loadDrum(21,function(s){drumClap=s;});
loadDrum(30,function(s){drumLowTom=s;});
loadDrum(50,function(s){drumHighTom=s;});
loadDrum(15,function(s){drumSnare=s;});
loadDrum(5,function(s){drumKick=s;});
loadDrum(70,function(s){drumCrash=s;});
loadInstrument(594,function(s){instrumVox=s;});
loadInstrument(1367,function(s){instrumApplause=s;});
function loadDrum(n,callback){
  var info=player.loader.drumInfo(n);
  player.loader.startLoad(audioContext, info.url, info.variable);
  player.loader.waitLoad(function () {callback(window[info.variable])});
}
function loadInstrument(n,callback){
  var info=player.loader.instrumentInfo(n);
  player.loader.startLoad(audioContext, info.url, info.variable);
  player.loader.waitLoad(function () {callback(window[info.variable])});
}
function uhoh(){
  var when=audioContext.currentTime;
  var b=0.1;
  player.queueWaveTable(audioContext, audioContext.destination, instrumVox, when+b*0, 60, b*1);
  player.queueWaveTable(audioContext, audioContext.destination, instrumVox, when+b*3, 56, b*4);
}
function applause(){
  player.queueWaveTable(audioContext, audioContext.destination, instrumApplause, audioContext.currentTime, 54, 3);
}
function badumtss(){
  var when=audioContext.currentTime;
  var b=0.11;
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*0, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumLowTom, when+b*0, drumLowTom.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*1, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumHighTom, when+b*1, drumHighTom.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*3, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumKick, when+b*3, drumKick.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumCrash, when+b*3, drumCrash.zones[0].keyRangeLow, 3.5);
}
<script src='https://surikov.github.io/webaudiofont/npm/dist/WebAudioFontPlayer.js'></script>
<button onclick='badumtss();'>badumtss</button>
<button onclick='uhoh();'>uhoh</button>
<button onclick='applause();'>applause</button>
<br/><a href='https://github.com/surikov/webaudiofont'>More sounds</a>


0

Web Audio API是完成这项工作的正确工具。加载声音文件并播放它几乎不需要做任何工作。幸运的是,那里有很多可以简化工作的库。对声音感兴趣,我还创建了一个名为musquito的库,您也可以查看该库。

目前,它仅支持衰落的声音效果,而我正在研究3D空间化等其他方面。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.