【问题标题】:Scheduling sample playback with Web Audio API使用 Web Audio API 安排样本播放
【发布时间】:2018-11-11 02:26:36
【问题描述】:

我正在尝试构建一个使用样本而不是振荡器的鼓机,只是为了学习。但是,我无法安排声音在前两个节拍中按节奏播放。发生的情况是前两个节拍播放不同步,而其余节拍似乎按预期播放。播放振荡器而不是采样时不会出现此问题。

我阅读了两个时钟的故事以及我能找到的所有相关教程,但它们都适用于似乎没有出现此问题的振荡器。以下只是我尝试实现代码的一种方式 - 我尝试了 OOP 和各种函数式编程版本,但所有这些都出现了问题。

在本例中,我创建了名为 playSound() 和 playKick() 的函数。 playSound() 触发振荡器音符,而 playKick() 函数触发底鼓采样。尝试在 scheduler() 函数中切换两者,听听问题是如何发生的。

let audioContext = new (window.AudioContext || window.webkitAudioContext)();
var nextNotetime = audioContext.currentTime;
var startBtn = document.getElementById("startBtn");
var stopBtn = document.getElementById("stopBtn");
var timerID;
let kickBuffer;
loadKick('sounds/kick.wav');

function loadKick(url) {
  let xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function() {
    audioContext.decodeAudioData(xhr.response, decoded => {
      kickBuffer = decoded;
    });
  }
  xhr.send();
}

function playKick(time) {
  let source = audioContext.createBufferSource();
  source.connect(audioContext.destination);
  source.buffer = kickBuffer;
  source.start(time);
}

function playSound(time) {

  var osc = audioContext.createOscillator();
  osc.connect(audioContext.destination);
  osc.frequency.value = 200;
  osc.start(time);
  osc.stop(time + 0.1);

};

function scheduler() {
    while(nextNotetime < audioContext.currentTime + 0.1) {
        // switch between playSound and playKick to hear the problem
        nextNotetime += 0.5;
        playSound(nextNotetime);
        // playKick(nextNotetime);
    }
   timerID = window.setTimeout(scheduler, 0);
}

startBtn.addEventListener('click', function() {
    scheduler();
  }, false);

stopBtn.addEventListener('click', function() {
    clearTimeout(timerID);
  }, false);

if(audioContext.state === 'suspended'){
  audioContext.resume();
};

正如您所见,缓冲区在文件加载后立即被预加载,因此这不是原因的根源。任何有关如何解决此问题的建议将不胜感激。

【问题讨论】:

    标签: javascript web-audio-api


    【解决方案1】:

    工作修复。

    "use strict";
    
    
    
    var audioContext = new AudioContext(),
        futureTickTime = audioContext.currentTime,
        counter = 1,
        tempo = 120,
        secondsPerBeat = 60 / tempo,
        counterTimeValue = (secondsPerBeat / 4),
        timerID = undefined,
        isPlaying = false;
    
    
    //_____________________________________________BEGIN load sound samples
    let kickBuffer;
    loadKick('sounds/kick.mp3');
    
    function loadKick(url) {
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function() {
            audioContext.decodeAudioData(xhr.response, function(decoded) {
                kickBuffer = decoded;
            });
        }
        xhr.send();
    }
    
    function playKick(time) {
        let source = audioContext.createBufferSource();
        source.connect(audioContext.destination);
        source.buffer = kickBuffer;
        source.start(audioContext.currentTime + time);
    }
    
    
    //_____________________________________________END load sound samples
    
    
    function scheduleSound(time) {
        playKick(time)
    
    }
    
    
    function playTick() {
        console.log(counter);
        secondsPerBeat = 60 / tempo;
        counterTimeValue = (secondsPerBeat / 1);
        counter += 1;
        futureTickTime += counterTimeValue;
    }
    
    
    function scheduler() {
        if (futureTickTime < audioContext.currentTime + 0.1) {
            scheduleSound(futureTickTime - audioContext.currentTime);
    
            playTick();
        }
    
        timerID = window.setTimeout(scheduler, 0);
    }
    
    
    function play() {
        isPlaying = !isPlaying;
    
        if (isPlaying) {
            counter = 1;
            futureTickTime = audioContext.currentTime;
            scheduler();
        } else {
            window.clearTimeout(timerID);
        }
    }
    
    
    
    var playStop = document.getElementsByClassName("play-stop-button")[0];
    
    playStop.addEventListener("click",function(){
        play();
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-24
      • 2014-10-11
      • 2018-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多