如何在 javascript 中快速播放声音文件的多个副本
Posted
技术标签:
【中文标题】如何在 javascript 中快速播放声音文件的多个副本【英文标题】:How to rapidly play multiple copies of a soundfile in javascript 【发布时间】:2020-04-27 07:32:49 【问题描述】:我正在用 html+js 构建一个旋转得相当快的命运之轮。每次新的颜色飞过标记时,滚轮都会发出咔哒声。在最高速度下,这听起来几乎像机关枪,所以一个新文件在旧文件基本上完成之前就开始播放。文件本身总是一样的:click.wav
它在 Chrome 中运行良好,仅在 chrome 中。 Firefox 有一个奇怪的错误,它只播放声音,如果有任何其他音频源处于活动状态,例如在不同选项卡中播放的 youtube 视频。 Edge 和 Safari 可以确保点击到最后,然后同时播放它们。一团糟...
我使用method described here,它使用克隆<audio>
标签
我想这就是问题所在:
var sound = new Audio("sounds/click.wav");
sound.preload = 'auto';
sound.load();
function playsound()
var click=sound.cloneNode();
click.volume=1;
click.play();
这是我的旋转函数的简化版本,它每秒只调用 playsound() 函数几次:
function rotateWheel()
angle = angle + acceleration
while (angle >= 360)
angle = angle - 360
var wheel = document.getElementById("wheel")
wheel.style.transform = "rotate("+angle +"deg)"
// play the click when a new segment rotates by
if(Math.floor(angle/21) != previousSegment)
playsound()
previousSegment = Math.floor(angle/21)
【问题讨论】:
【参考方案1】:您使用了answer from here 这种方法有时会导致浏览器进程崩溃,因为您要么创建内存问题,要么用浏览器必须处理的元素填充 DOM - 所以您应该重新考虑您的方法并且正如您发现的那样,它不适用于大多数浏览器(如 safari 或 FireFox)中的大量使用
深入研究<audio>
标签规范,很明显有很多事情无法用它来完成,这并不奇怪,因为它是为媒体播放而设计的。
限制之一包括 -> 没有精细的声音时序。
因此,您必须找到另一种方法来满足您的需求,我们使用专为在线视频游戏设计的 Web Audio API。Web Audio API AudioContext 用于管理和播放所有声音。要使用 Web Audio API 产生声音,请创建一个或多个声音源并将它们连接到 AudioContext 实例(通常是扬声器)提供的声音目标。 音频缓冲区 使用 Web Audio API,音频文件只有在加载到缓冲区后才能播放。加载声音需要时间,因此动画/游戏中使用的资产应在页面加载时、游戏或关卡开始时加载,或者在玩家玩游戏时逐步加载。基本步骤强>
我们使用 XMLHttpRequest 将数据从音频文件加载到缓冲区中。 接下来,我们进行异步回调并发送实际的加载请求。 一旦声音被缓冲和解码,就可以立即触发。 每次触发时,都会创建不同的缓冲声音实例。游戏中音效的一个关键特性是可以同时存在许多音效。 因此,以“机枪”为例:想象一下,您正处于枪战中,正在使用射击机枪。 机枪每秒发射多次,造成数十种音效同时播放。这就是 Web Audio API 真正大放异彩的地方。 您的应用程序的一个简单示例:
/* global AudioContext:true,
*/
var clickingBuffer = null;
// Fix up prefixing
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
function loadClickSound(url)
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function()
context.decodeAudioData(request.response, function(buffer)
if (!buffer)
console.log('Error decoding file data: ' + url);
return;
clickingBuffer = buffer;
);
request.onerror = function()
console.log('BufferLoader: XHR error');
;
request.send();
;
function playSound(buffer, time, volume)
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
var gainNode = context.createGain(); // Create a gain node
source.connect(gainNode); // Connect the source to the gain node
gainNode.connect(context.destination); // Connect the gain node to the destination
gainNode.gain.value = volume; // Set the volume
source.start(time); // play the source at the deisred time 0=now
// You call with in your document ready
loadClickSound('sounds/click.wav');
//and this plays the sound
playSound(clickingBuffer, 0, 1);
现在您可以尝试不同的时间和音量变化,例如通过引入随机因素 如果您需要具有不同点击声音(存储在缓冲区数组中)和音量/距离变化的更复杂的解决方案,这将是一段较长的代码。
【讨论】:
太棒了!非常感谢您提供如此详细的描述和答案。这正是我所需要的。 知道如何规避这个问题吗?我的意思是实际上有一个用户交互调用了所有这些,上面的一些函数......我试图在几个地方添加 context.resume() ,但仍然收到这条消息:The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. [link](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio)
很难调试我从未见过的代码 -> 默认情况下,Web Audio API 当前不受自动播放策略的影响。 (来自链接)上下文是全局定义的吗?如果问题仍然存在,请使用相关代码发布新问题并通过评论通知我这里
嗨@Codebreaker007,我按照你的建议创建了一个jsfiddle和单独的问题,以隔离问题:***.com/questions/61608637/…。如果你能去看看就好了。以上是关于如何在 javascript 中快速播放声音文件的多个副本的主要内容,如果未能解决你的问题,请参考以下文章