JavaScript / HTML5 中的音效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1933969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:58:10  来源:igfitidea点击:

Sound effects in JavaScript / HTML5

javascripthtmlhtml5-audio

提问by Stéphan Kochen

I'm using HTML5 to program games; the obstacle I've run into now is how to play sound effects.

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

The specific requirements are few in number:

具体要求很少:

  • Play and mix multiple sounds,
  • Play the same sample multiple times, possibly overlapping playbacks,
  • Interrupt playback of a sample at any point,
  • Preferably play WAV files containing (low quality) raw PCM, but I can convert these, of course.
  • 播放和混合多种声音,
  • 多次播放相同的样本,可能重叠播放,
  • 在任何时候中断样本的播放,
  • 最好播放包含(低质量)原始 PCM 的 WAV 文件,但我当然可以转换这些文件。

My first approach was to use the HTML5 <audio>element and define all sound effects in my page. Firefox plays the WAV files just peachy, but calling #playmultiple times doesn't really play the sample multiple times. From my understanding of the HTML5 spec, the <audio>element also tracks playback state, so that explains why.

我的第一种方法是使用 HTML5<audio>元素并在我的页面中定义所有声音效果。Firefox 播放 WAV 文件只是很好,但#play多次调用并不能真正多次播放样本。根据我对 HTML5 规范的理解,该<audio>元素还跟踪播放状态,因此可以解释原因。

My immediate thought was to clone the audio elements, so I created the following tiny JavaScript library to do that for me (depends on jQuery):

我的直接想法是克隆音频元素,所以我创建了以下小型 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;
      };
    });
  }
};

So now I can do Snd.boom();from the Firebug console and play snd/boom.wav, but I still can't play the same sample multiple times. It seems that the <audio>element is really more of a streaming feature rather than something to play sound effects with.

所以现在我可以Snd.boom();从 Firebug 控制台执行和 play snd/boom.wav,但我仍然无法多次播放相同的样本。似乎该<audio>元素实际上更像是一种流媒体功能,而不是播放声音效果的东西。

Is there a clever way to make this happen that I'm missing, preferably using only HTML5 and JavaScript?

有没有一种聪明的方法来实现我所缺少的,最好只使用 HTML5 和 JavaScript?

I should also mention that, my test environment is Firefox 3.5 on Ubuntu 9.10. The other browsers I've tried - Opera, Midori, Chromium, Epiphany - produced varying results. Some don't play anything, and some throw exceptions.

我还应该提到,我的测试环境是 Ubuntu 9.10 上的 Firefox 3.5。我尝试过的其他浏览器——Opera、Midori、Chromium、Epiphany——产生了不同的结果。有些什么都不玩,有些抛出异常。

回答by Kornel

HTML5 Audioobjects

HTML5Audio对象

You don't need to bother with <audio>elements. HTML 5 lets you access Audioobjectsdirectly:

你不需要理会<audio>元素。HTML 5 允许您直接访问Audio对象

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

There's no support for mixing in current version of the spec.

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

To play same sound multiple times, create multiple instances of the Audioobject. You could also set snd.currentTime=0on the object after it finishes playing.

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



Since the JS constructor doesn't support fallback <source>elements, you should use

由于 JS 构造函数不支持回退<source>元素,您应该使用

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

to test whether the browser supports Ogg Vorbis.

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



If you're writing a game or a music app (more than just a player), you'll want to use more advanced Web Audio API, which is now supported by most browsers.

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

回答by Chris Jaynes

WebAudioAPI by W3C

W3C 的WebAudioAPI

As of July 2012, the WebAudio APIis now supported in Chrome, and at least partly supported in Firefox, and is slated to be added to IOS as of version 6.

截至 2012 年 7 月,Chrome 现在支持WebAudio API,Firefox 至少部分支持,并计划从第 6 版开始添加到 IOS。

Although it is robust enough to be used programatically for basic tasks, the Audio element was never meant to provide full audio support for games, etc. It was designed to allow a single piece of media to be embedded in a page, similar to an img tag. There are a lot of issues with trying to use the Audio tag for games:

尽管它足够健壮,可以以编程方式用于基本任务,但 Audio 元素从来没有打算为游戏等提供完整的音频支持。它旨在允许将单个媒体嵌入到页面中,类似于 img标签。尝试在游戏中使用 Audio 标签有很多问题:

  • Timing slips are common with Audio elements
  • You need an Audio element for each instance of a sound
  • Load events aren't totally reliable, yet
  • No common volume controls, no fading, no filters/effects
  • 时间间隔在音频元素中很常见
  • 每个声音实例都需要一个 Audio 元素
  • 加载事件并不完全可靠,但
  • 没有常见的音量控制,没有衰落,没有过滤器/效果

I used this Getting Started With WebAudioarticle to get started with the WebAudio API. The FieldRunners WebAudio Case Studyis also a good read.

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

回答by d13

howler.js

咆哮.js

For game authoring, one of the best solutions is to use a library which solves the many problems we face when writing code for the web, such as howler.js. howler.js abstracts the great (but low-level) Web Audio APIinto an easy to use framework. It will attempt to fall back to HTML5 Audio Elementif Web Audio API is unavailable.

对于游戏创作,最好的解决方案之一是使用一个库来解决我们在为 Web 编写代码时面临的许多问题,例如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

Another great library is wad.js, which is especially useful for producing synth audio, such as music and effects. For example:

另一个很棒的库是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}
})

Sound for Games

游戏音效

Another library similar to Wad.js is "Sound for Games", it has more focus on effects production, while providing a similar set of functionality through a relatively distinct (and perhaps more concise feeling) API:

另一个类似于 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?]
  );
}

Summary

概括

Each of these libraries are worth a look, whether you need to play back a single sound file, or perhaps create your own html-based music editor, effects generator, or video game.

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

回答by Rob

You may also want to use this to detect HTML 5 audio in some cases:

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

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

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

HTML 5 JS Detect function

HTML 5 JS 检测功能

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

回答by F-3000

Here's one method for making it possible to play even same sound simultaneously. Combine with preloader, and you're all set. This works with Firefox 17.0.1 at least, haven't tested it with anything else yet.

这是一种可以同时播放相同声音的方法。结合预加载器,一切就绪。这至少适用于 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();
}

Bind this to a keyboard key, and enjoy:

将此绑定到键盘键,并享受:

player("step");

回答by Raul Agrait

Have a look at the jai(-> mirror) (javascript audio interface) site. From looking at their source, they appear to be calling play()repeatedly, and they mention that their library might be appropriate for use in HTML5-based games.

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

You can fire multiple audio events simultaneously, which could be used for creating Javascript games, or having a voice speaking over some background music

您可以同时触发多个音频事件,这可用于创建 Javascript 游戏,或在某些背景音乐上说话

回答by Lee Kowalkowski

Sounds like what you want is multi-channel sounds. Let's suppose you have 4 channels (like on really old 16-bit games), I haven't got round to playing with the HTML5 audio feature yet, but don't you just need 4 <audio> elements, and cycle which is used to play the next sound effect? Have you tried that? What happens? If it works: To play more sounds simultaneously, just add more <audio> elements.

听起来您想要的是多声道声音。假设您有 4 个频道(就像在非常老的 16 位游戏上一样),我还没有开始玩 HTML5 音频功能,但是您是否只需要 4 个 <audio> 元素,并循环使用播放下一个音效?你试过吗?发生什么了?如果有效:要同时播放更多声音,只需添加更多 <audio> 元素。

I have done this before without the HTML5 <audio> element, using a little Flash object from http://flash-mp3-player.net/- I wrote a music quiz (http://webdeavour.appspot.com/) and used it to play clips of music when the user clicked the button for the question. Initially I had one player per question, and it was possible to play them over the top of each other, so I changed it so there was only one player, which I pointed at different music clips.

我之前在没有 HTML5 <audio> 元素的情况下使用http://flash-mp3-player.net/ 中的一个小 Flash 对象完成了这项工作- 我写了一个音乐测验(http://webdeavour.appspot.com/)和当用户单击问题按钮时,用它来播放音乐剪辑。最初我每个问题有一个播放器,并且可以将它们重叠播放,所以我改变了它,所以只有一个播放器,我指向不同的音乐片段。

回答by adamse

To play the same sample multiple times, wouldn't it be possible to do something like this:

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

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

(eis the audio element)

e是音频元素)

Perhaps I completely misunderstood your problem, do you want the sound effect to play multiple times at the same time? Then this is completely wrong.

可能我完全误解了你的问题,你想让音效同时播放多次吗?那么这是完全错误的。

回答by digitalicarus

Here's an idea. Load all of your audio for a certain class of sounds into a single individual audio element where the src data is all of your samples in a contiguous audio file (probably want some silence between so you can catch and cut the samples with a timeout with less risk of bleeding to the next sample). Then, seek to the sample and play it when needed.

这是一个想法。将某一类声音的所有音频加载到单个单独的音频元素中,其中 src 数据是连续音频文件中的所有样本(可能需要一些静音,以便您可以在超时的情况下捕捉和剪切样本,而更少流到下一个样本的风险)。然后,寻找样本并在需要时播放。

If you need more than one of these to play you can create an additional audio element with the same src so that it is cached. Now, you effectively have multiple "tracks". You can utilize groups of tracks with your favorite resource allocation scheme like Round Robin etc.

如果您需要播放多个音频元素,您可以使用相同的 src 创建一个额外的音频元素,以便缓存它。现在,您实际上拥有多个“轨道”。您可以将轨道组与您最喜欢的资源分配方案(如循环等)一起使用。

You could also specify other options like queuing sounds into a track to play when that resource becomes available or cutting a currently playing sample.

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

回答by Robert O'Callahan

http://robert.ocallahan.org/2011/11/latency-of-html5-sounds.html

http://robert.ocallahan.org/2011/11/latency-of-html5-sounds.html

http://people.mozilla.org/~roc/audio-latency-repeating.html

http://people.mozilla.org/~roc/audio-latency-repeating.html

Works OK in Firefox and Chrome for me.

对我来说在 Firefox 和 Chrome 中工作正常。

To stop a sound that you started, do var sound = document.getElementById("shot").cloneNode(true); sound.play(); and later sound.pause();

要停止您启动的声音,请执行 var sound = document.getElementById("shot").cloneNode(true); 声音播放();后来 sound.pause();