Используйте часы Web Audio API для выполнения обратных вызовов или событий

Недавно я начал работать над фреймворком, который будет интенсивно использовать API Web Audio. Он предназначен для использования в качестве звукового движка для браузерных игр и интерактивных веб-сайтов.

Для некоторых функций мне нужно убедиться, что я могу выполнять обратные вызовы и генерировать события именно тогда, когда запланировано воспроизведение аудиофайлов. Я написал 3 типа часовых механизмов для экспериментов, но так как setTimeout() а также setInterval() не совсем точны, я действительно хотел работать с часами Web Audio API. Я нашел хитрый способ добиться этого, но мне нужно ваше мнение по этому поводу, потому что я не знаю, является ли это очень хорошей идеей или есть намного лучшие решения.

Хитрость, которую я использую сейчас, состоит в том, чтобы воспроизвести тихий файл WAV всего с 1 образцом и прикрепить обратные вызовы к onended. Пока это работает довольно хорошо. Отклонение составляет около 0-5 мс в Chrome и 0-10 мс в Firefox. С помощью setTimeout() приводил к отклонениям от 30 до 50 мс, а при использовании настраиваемого самокорректирующегося setInterval отклонения были очень непредсказуемыми.

Код:

// Init hacky hacky clock in class Clock
schedule (startTime, callback = () => {}) {
  let silence = this.Experience.AudioEngine.playSound(this.silence, startTime);
  silence.onended = () => {
    startTime *= 1000;
    let callbackTime = this.Experience.AudioEngine.getCurrentTime() * 1000,
        deviation = callbackTime-startTime;
    this.totalDeviation += deviation;

    console.log(`Starttime: ${startTime}ms, callbacktime: ${callbackTime}ms, deviation: ${deviation}ms`);
    callback();
  };
}

Пример того, где я использую это:

startMetronome (bpm, timeSignature = '4/4', measuresAmount) {
  let timeSignatureSplit = timeSignature.split('/'),
      beatsAmountPerMeasure = timeSignatureSplit[0],
      noteValue = timeSignatureSplit[1],
      noteValueTime = (60/bpm) * (4/noteValue),
      beatsAmount = measuresAmount * beatsAmountPerMeasure,
      startTime = null,
      time = 0;

  this.Experience.AudioEngine.waitUntilPreloadingFinished(this.Experience.Clock.silence, () => {
    for (let beats = 0; beats < beatsAmount; beats++) {
      if (beats == 0) startTime = this.Experience.AudioEngine.getCurrentTime(); // gets current time from AudioContext

      time = startTime + beats * noteValueTime;
      this.Experience.Clock.schedule(time, () => {
        // Callback
      }, clockType);
    }

    // Print Clock scheduling test results
    this.Experience.Clock.schedule(time+0.1, () => {
      console.log(`Total deviation over ${measuresAmount} measures at ${bpm}bpm ${timeSignature}: ${this.Experience.Clock.totalDeviation}ms`);
    });
  });
}

Я открыт для предложений. Если вы знаете лучший способ, пожалуйста, дайте мне знать! Кроме того, так как это просто фрагменты кода, которые являются частью классов с множеством методов, дайте мне знать, если есть неясности.

Спасибо!

0 ответов

Другие вопросы по тегам