Safari — 无法在前几个之后创建振荡器

Safari — Cannot create Oscillator after the first few

我正在尝试使用 WebAudio API,但在让它与 Safari 一起正常工作时遇到了问题。我的实验适用于 Firefox 和 Chrome.

我已经编写了一个 Promisified 函数来演奏单个音符,然后尝试使用该函数演奏一系列音符。

仅在 Safari 上,它在前四个音符后失败并显示以下消息:

Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'context.createOscillator')

好的,我没有处理错误,但为什么我会得到它?它建议限制四个振荡器。

function tone(frequency,duration) {
 return new Promise(function (resolve,reject) {
  var audioContext = window.AudioContext || window.webkitAudioContext;
  var context=new audioContext;
  var oscillator = context.createOscillator();
  oscillator.frequency.value = frequency;
  oscillator.connect(context.destination);
  oscillator.type='sawtooth';
  oscillator.start(context.currentTime);
  oscillator.stop(context.currentTime+duration);
  oscillator.onended=resolve;
 });
}
document.querySelector('button#play-test').onclick=function(event) {
 tone(130.81,1)
 .then(()=>tone(146.83,1))
 .then(()=>tone(164.81,1))
 .then(()=>tone(174.61,1))
 .then(()=>tone(196.00,1))
 ;
};
<button id="play-test">Play</button>

限制是您可以同时 运行 的 AudioContext 数量。

有些浏览器有这样的限制,因为 AudioContext 需要硬件(声卡)的资源,而这个硬件有限制。

因此重构您的代码,使其不会每次都创建新的 AudioContext:

// create a single audio context
var context = new (window.AudioContext || window.webkitAudioContext)();

function tone(frequency, duration) {
  return new Promise(function(resolve, reject) {
    var oscillator = context.createOscillator();
    oscillator.frequency.value = frequency;
    oscillator.connect(context.destination);
    oscillator.type = 'sawtooth';
    oscillator.start(context.currentTime);
    oscillator.stop(context.currentTime + duration);
    oscillator.onended = resolve;
  });
}
document.querySelector('button#play-test').onclick = function(event) {
  tone(130.81, 1)
    .then(() => tone(146.83, 1))
    .then(() => tone(164.81, 1))
    .then(() => tone(174.61, 1))
    .then(() => tone(196.00, 1))
    .catch(console.error);
};
<button id="play-test">Play</button>