Гарантируется ли бесшовное воспроизведение при переупорядочении аудио узлов? - PullRequest
0 голосов
/ 07 февраля 2019

Когда я воспроизводю аудио с AudioBufferSourceNode, могу ли я добавить перед ним другие узлы (Gain или Panner или, возможно, другие узлы) без пропусков или скачков при воспроизведении ?Это упомянуто в спецификации где-то?У кого-нибудь есть такой опыт?

// Play audio
var source = context.createBufferSource();
source.buffer = someBuffer;
source.connect(context.destination);
source.start();

// Later, when source is still playing, is this safe?
source.disconnect();
source.connect(gain);
gain.connect(context.destination);

// And removing nodes is safe too?
gain.disconnect();
source.disconnect();
source.connect(context.destination);

Я знаю, что могу переставлять узлы по своему желанию, но мой вопрос касается переупорядочения во время реального воспроизведения.

1 Ответ

0 голосов
/ 08 февраля 2019

Я не проверял спецификации, но от тестирования реализации все равно различаются ...

При полном отключении Chrome и Safari приостановит воспроизведение AudioBufferSourceNode, а Firefox продолжит его работу.

const ctx = new(window.AudioContext || window.webkitAudioContext);
let source;
let connected = true;

btn.onclick = e => {
  btn.textContent = 'loading...';
  btn.disabled = true;
  fetch('https://upload.wikimedia.org/wikipedia/commons/2/23/Turdus_fuscater_-_Great_Thrush_XC243229.mp3')
    .then(r => r.arrayBuffer())
    .then(buf => ctx.decodeAudioData(buf))
    .then(audioBuf => {
      source = ctx.createBufferSource();
      source.buffer = audioBuf;
      source.onended = e => console.log('done');
      source.connect(ctx.destination);
      btn.onclick = e => {
        source.start(0);
        btn.onclick = switchConnect;
        btn.textContent = 'switch connection';
      };
      btn.textContent = 'play';
      btn.disabled = false;
    });
};

function switchConnect() {
  if (connected)
    source.disconnect();
  else
    source.connect(ctx.destination);
  connected = !connected;
}
<script src="https://cdn.jsdelivr.net/gh/mohayonao/promise-decode-audio-data@eb4b1322113b08614634559bc12e6a8163b9cf0c/build/promise-decode-audio-data.min.js"></script>
<button id="btn">fetch</button>

Теперь, даже если воспроизведение не приостанавливается, у вас могут возникнуть некоторые щелчки и щелчки.Это даже причина, по которой AudioNode.disconnect() был расширен для включения destination параметра , который позволяет нам точно настроить, от какого пункта назначения мы хотим отключиться, вместо того, чтобы отключаться отовсюду.

Таким образом, вы можете просто подключить свой узел сначала к новому назначению, а затем отключить его от предыдущего.Это должно избавить от заметных щелчков и щелчков, а также от паузы webkit в воспроизведении.

Но обратите внимание, что все браузеры по-прежнему не поддерживают эту опцию, из тех, которые я тестировал, Chrome и Firefox, Safari не делает.«т.Поскольку в неподдерживающих браузерах вызов disconnect(destination) фактически отключит его от всех его пунктов назначения, мы должны обработать оба случая в нашем коде.

let supportFineDisconnect = false;
const ctx = new(window.AudioContext || window.webkitAudioContext);
const osc = ctx.createOscillator();
const gain = ctx.createGain();

// lazy checks support for AudioNode.disconnect(destination)
try {
  osc.disconnect(osc);
} catch (e) {
  supportFineDisconnect = "maybe";
}

btn1.onclick = begin;
onchange = switchRoute;

function begin(){
  osc.connect(gain);
  gain.connect(ctx.destination);
  gain.gain.value = 1;

  osc.start(0);

  btn1.textContent = 'stop';
  btn1.onclick = e => osc.stop(0);
}

function switchRoute() {
  if (!supportFineDisconnect) { // might click
    osc.disconnect(); // disconnect from all
  }
  if (+document.querySelector('input:checked').value) {
    connectDirect();
  } else {
    connectGain();
  }
}

function connectDirect() {
  // first connect to new dest
  osc.connect(ctx.destination);
  if (supportFineDisconnect) {
    osc.disconnect(gain); // then disconnect only from gain
  }
}

function connectGain() {
  // first connect to new dest
  osc.connect(gain);
  if (supportFineDisconnect) {
    osc.disconnect(ctx.destination); // then disconnect only from main
  }
}
<button id="btn1">start playing a 440hz osc</button>
switch: <input type="radio" checked value="0" name="switch"><label>through gain</label>
<input type="radio" value="1" name="switch"><label>direct</label>

Но, конечно, это все равно не предотвратит щелчки или щелчки, вызванные другими факторами (например, изменением усиления или другими). ​​

...