WebAudio API で音が歪む
歪んだり歪まなかったりするしよくわかんねー!
ってなってましたが、なんか回避できたので、書いておきます。
再現方法
iOS 9.2.1 iPhone6 Plus
イヤホンを挿してない状態で SafariでWebAudioの再生してるページを開いて、Safariを再起動します。
ちなみに、Safariで音を再生するには、touchend等のユーザアクションで音を再生しないといけません。(一回再生すれば、そのAudioContextでは再生できるようになる)
あと、なぜか、iOS9からtouchstartがユーザアクションとして判定されなくなりました。
音の再生サンプル
回避の方法
一回音を再生してから、サンプルレートが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);
};
参考