Sound effects in JavaScript / HTML5
我正在使用HTML5来编写游戏;我现在遇到的障碍是如何播放声音效果。
具体要求很少:
- 播放和混合多种声音,
- 多次播放相同的样本,可能重叠播放,
- 在任何点中断播放样本,
- 最好播放包含(低质量)原始PCM的WAV文件,但我当然可以转换它们。
我的第一种方法是使用HTML5
我的直接想法是克隆音频元素,所以我创建了以下微小的JavaScript库来为我做(取决于jQuery):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; }; }); } }; |
所以现在我可以从Firebug控制台执行
是否有一种聪明的方法可以实现这一点,我很想忘记,最好只使用HTML5和JavaScript?
我还要提一下,我的测试环境是Ubuntu 9.10上的Firefox 3.5。我尝试过的其他浏览器--Opera,Midori,Chromium,Epiphany--产生了不同的结果。有些人不玩任何东西,有些人抛出异常。
HTML5
您不需要打扰
1 2 | var snd = new Audio("file.wav"); // buffers automatically when created snd.play(); |
在当前版本的规范中不支持混合。
要多次播放相同的声音,请创建
由于JS构造函数不支持fallback
1 | (new Audio()).canPlayType("audio/ogg; codecs=vorbis") |
测试浏览器是否支持Ogg Vorbis。
如果您正在编写游戏或音乐应用程序(不仅仅是一个播放器),您将需要使用更高级的Web Audio API,现在大多数浏览器都支持它。
W3C的WebAudio API
截至2012年7月,Chrome现在支持WebAudio API,并且至少部分支持Firefox,并且将从版本6开始添加到IOS。
虽然它足够强大,可以编程方式用于基本任务,但Audio元素从未打算为游戏等提供完整的音频支持。它旨在允许将单个媒体嵌入到页面中,类似于img标签。尝试将音频标记用于游戏时存在很多问题:
- 定时单对于Audio元素很常见
- 每个声音实例都需要一个Audio元素
- 负载事件尚不完全可靠
- 没有常见的音量控制,没有褪色,没有滤镜/效果
我使用WebAudio入门文章开始使用WebAudio API。 FieldRunners WebAudio案例研究也是一本很好的读物。
howler.js
对于游戏创作,最好的解决方案之一是使用一个库来解决我们在为Web编写代码时遇到的许多问题,例如howler.js。 howler.js将伟大的(但是低级的)Web Audio API抽象为易于使用的框架。如果Web Audio API不可用,它将尝试回退到HTML5音频元素。
1 2 3 4 5 | 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,它对于产生合成音频特别有用,例如音乐和效果。例如:
1 2 3 4 5 6 7 8 9 10 11 12 | 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提供类似的功能集:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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的音乐编辑器,效果生成器或视频游戏,这些库中的每一个都值得一看。
在某些情况下,您可能还希望使用它来检测HTML 5音频:
http://diveintohtml5.ep.io/everything.html
HTML 5 JS检测功能
1 2 3 4 5 | function supportsAudio() { var a = document.createElement('audio'); return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, '')); } |
这是一种可以同时播放相同声音的方法。结合预加载器,你就完成了。这至少适用于Firefox 17.0.1,尚未测试其他任何东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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(); } |
将其绑定到键盘键,然后享受:
1 | player("step"); |
听起来你想要的是多声道声音。我们假设您有4个频道(就像真正的16位游戏一样),我还没有玩到HTML5音频功能,但是你不需要4个元素,并且循环用于播放下一个音效?你试过吗?怎么了?如果有效:要同时播放更多声音,只需添加更多元素即可。
我之前没有HTML5元素,使用http://flash-mp3-player.net/中的一个小Flash对象 - 我写了一个音乐测验(http://webdeavour.appspot.com/)并用它来当用户点击问题按钮时播放音乐剪辑。最初我每个问题都有一个玩家,并且可以在彼此的顶部播放它们,所以我改变它所以只有一个玩家,我指向不同的音乐剪辑。
看看 jai strike>( - > mirror strike>)(javascript音频界面)网站。从他们的来源看,他们似乎反复调用
You can fire multiple audio events
simultaneously, which could be used
for creating Javascript games, or
having a voice speaking over some
background music
要多次播放相同的样本,是不是可以这样做:
1 2 3 | e.pause(); // Perhaps optional e.currentTime = 0; e.play(); |
(
也许我完全误解了你的问题,你想让声音效果同时播放多次吗?那是完全错误的。
这是一个想法。将特定类别声音的所有音频加载到单个音频元素中,其中src数据是连续音频文件中的所有样本(可能需要一些静音,因此您可以捕获并切断样本,并且超时较少下一个样本出血的风险)。然后,寻找样本并在需要时播放。
如果你需要不止一个这样的游戏,你可以使用相同的src创建一个额外的音频元素,以便它被缓存。现在,你实际上有多个"轨道"。您可以利用自己喜欢的资源分配方案(如Round Robin等)来利用音轨组。
您还可以指定其他选项,例如将声音排队到要在该资源可用时播放的曲目或剪切当前播放的样本。
我建议使用SoundJS,一个我帮助开发的库。它允许您编写一个可在任何地方使用的单个代码库,SoundJS会根据需要选择Web音频,html音频或flash音频。
它可以让你做你想做的所有事情:
- 播放和混合多种声音,
- 多次播放相同的样本,可能重叠播放
- 在任何时候中断播放样本
- 播放包含的WAV文件(取决于浏览器支持)
希望有所帮助。
http://robert.ocallahan.org/2011/11/latency-of-html5-sounds.html
http://people.mozilla.org/~roc/audio-latency-repeating.html
适用于我在Firefox和Chrome中正常运行。
要停止你开始的声音,请执行
var sound = document.getElementById("shot")。cloneNode(true);
sound.play();
然后
sound.pause();
我在编写音乐盒卡片生成器时遇到了这个问题。从不同的图书馆开始,但每次都有某种故障。正常音频实现的延迟是糟糕的,没有多个播放...最终使用lowlag库+ soundmanager结束:
http://lowlag.alienbill.com/
和
http://www.schillmania.com/projects/soundmanager2/
您可以在这里查看实施:
http://musicbox.grit.it/
我为多个浏览器播放生成了wav + ogg文件。这个音乐盒播放器可以在ipad,iphone,Nexus,mac,pc上运行,对我有用。
使用单个
我知道这是一个彻头彻尾的黑客,但我想我应该添加这个样本开源音频库我前一段时间放在github上...
https://github.com/run-time/jThump
单击下面的链接后,键入主页行键以播放蓝调riff(同时键入多个键等)
使用jThump库的示例>> http://davealger.com/apps/jthump/
它基本上是通过制作不可见的
这当然不是理想的,但你可以单独基于创造力+1这个解决方案(事实上它是开源的,并且可以在我尝试过的任何浏览器中使用)我希望这至少让其他人搜索一些想法。
:)
Web Audio API是这项工作的正确工具。加载声音文件并播放它有一些工作。幸运的是,有很多库可以简化工作。对声音感兴趣我还创建了一个名为musquito的库,你也可以查看它。
目前它只支持褪色的声音效果,我正在研究3D空间化等其他方面。
所选答案将适用于IE以外的所有内容。我写了一篇关于如何使它跨浏览器工作的教程= http://www.andy-howard.com/how-to-play-sounds-cross-browser-including-ie/index.html
这是我写的功能;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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页面:
1 | <bgsound id="sound"> |
最后你可以调用函数并简单地通过这里的路径:
1 | playSomeSounds("sounds/welcome.wav"); |
你总是可以尝试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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); } |
1 2 3 4 5 | <script src='https://surikov.github.io/webaudiofont/npm/dist/WebAudioFontPlayer.js'> <button onclick='badumtss();'>badumtss</button> <button onclick='uhoh();'>uhoh</button> <button onclick='applause();'>applause</button> <br/>More sounds |