JavaScript
HTML5
WebAudioAPI

[WebAudio API] iOS9で音が歪む、遅い、低い、割れる等の回避方法

More than 2 years have passed since last update.

WebAudio API で音が歪む

歪んだり歪まなかったりするしよくわかんねー!
ってなってましたが、なんか回避できたので、書いておきます。

再現方法

iOS 9.2.1 iPhone6 Plus
イヤホンを挿してない状態で SafariでWebAudioの再生してるページを開いて、Safariを再起動します。

ちなみに、Safariで音を再生するには、touchend等のユーザアクションで音を再生しないといけません。(一回再生すれば、そのAudioContextでは再生できるようになる)
あと、なぜか、iOS9からtouchstartがユーザアクションとして判定されなくなりました。

音の再生サンプル

http://goo.gl/UEpbeP

回避の方法

一回音を再生してから、サンプルレートが44100じゃない時に、AudioContextを再度生成することで回避できます。

サンプル

http://goo.gl/jWZDwD
dirtyという関数内で回避しています。

バグ回避のメインのコード


function playDummy(){
  var source = createBufferSource();
  source.buffer = context.createBuffer(1,1,context.sampleRate);
  source.connect(context.destination);
  source.start(0);
}

function checkSampleRateBug(){
  if(context.sampleRate !== 44100){
    context.close();
    context = getAudioContextInstance();
    return true;
  }
  return false;
}

function dirty(){
  playDummy();
  if(checkSampleRateBug())playDummy();
}

body.addEventListener('touchend',dirty);
body.addEventListener('mouseup',dirty);

コード全体



function getAudioContextInstance(){
  try{
    return new (
      window.AudioContext ||
      window.webkitAudioContext ||
      window.mozAudioContext
    )();
  }catch(e){
    console.error(e);
    return null;
  }
}

onload = function(){
  var body = document.body;
  var context = getAudioContextInstance();

  if(context === null){
    alert('WebAudio 未対応です');
    return;
  }

  var sampleRate = 44100;
  // 半音上下
  var rate = Math.pow(2.0, 1.0/12.0);
  var temp = rate;
  var rates = [
    rate,
    temp*=rate*rate,
    temp*=rate*rate,
    temp*=rate,
    temp*=rate*rate,
    temp*=rate*rate,
    temp*=rate*rate,
    temp*=rate,
  ];

  function playDoremifasorasido(){
    var source = createBufferSource();
    source.buffer = context.createBuffer( 1, sampleRate*1, sampleRate);
    var channel = source.buffer.getChannelData(0);

    for( var i=0; i < channel.length; i++ ){
      channel[i] = Math.sin(i/(sampleRate/440)*rate*rate*rate * Math.PI * rates[(i/(sampleRate/8)|0)%rates.length]);
    }

    source.connect(context.destination);
    source.start(0);
  }

  function createBufferSource(){
    var source = context.createBufferSource();
    source.start = source.start || source.noteOn;
    return source;
  }



  function playDummy(){
    var source = createBufferSource();
    source.buffer = context.createBuffer(1,1,context.sampleRate);
    source.connect(context.destination);
    source.start = source.start || source.noteOn;
    source.start(0);
  }

  function checkSampleRateBug(){
    if(context.sampleRate !== 44100){
      context.close();
      context = getAudioContextInstance();
      return true;
    }
    return false;
  }

  function dirty(){
    playDummy();
    if(checkSampleRateBug())playDummy();
  }

  body.addEventListener('touchend',dirty);
  body.addEventListener('mouseup',dirty);

  body.addEventListener('touchend',playDoremifasorasido);
  body.addEventListener('mouseup',playDoremifasorasido);

};


参考

http://stackoverflow.com/a/34501159