API Web Audio l oop синхронизируется с SVG-анимацией - PullRequest
0 голосов
/ 30 января 2020

У меня есть простой 4-секундный аудиоклип, который щелкает один раз в секунду. У меня есть изображение SVG с 4 кружками. Я хотел бы иметь возможность l oop аудио на неопределенный срок и иметь возможность показывать / скрывать круги каждую секунду синхронно c с аудио. Итак ...

0 seconds, show just the red circle
1 second, show just the green circle
2 seconds, show just the yellow circle
3 seconds, show just the blue circle  (audio loops to the beggining, time is reset to 0) 
0 seconds, show just the red circle
etc...

Все работает, за исключением того, что я не знаю, как зафиксировать время l oop. (См. Ниже в javascript, где написано «прослушиватель некоторых событий ()»). Есть идеи?

<button id='go'>Go</button>      
<button id='stop'>Stop</button>      
<br/><br/> 
<svg width='500' height='100'>
<rect width="250" height="100" style="fill:Tan;stroke-width:3;stroke:rgb(0,0,0)" />
  <g id='circle1'><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></g> 
  <g id='circle2'><circle cx="100" cy="50" r="40" stroke="black" stroke-width="3" fill="green" /></g> 
  <g id='circle3'><circle cx="150" cy="50" r="40" stroke="black" stroke-width="3" fill="yellow" /></g> 
  <g id='circle4'><circle cx="200" cy="50" r="40" stroke="black" stroke-width="3" fill="blue" /></g> 
</svg>  
var actx = new (AudioContext || webkitAudioContext)(),
    src = "https://smantei.s3-us-west-2.amazonaws.com/Click.wav",
    audioData, srcNode;  

fetch(src, {mode: "cors"}).then(function(resp) {return resp.arrayBuffer()}).then(decode);

function decode(buffer) {
  actx.decodeAudioData(buffer, playLoop);
}

function playLoop(abuffer) {
  if (!audioData) audioData = abuffer;  
  srcNode = actx.createBufferSource();  
  srcNode.buffer = abuffer;             
  srcNode.connect(actx.destination);    
  srcNode.loop = true;                  
  srcNode.start();                      
}

document.querySelector("#go").onclick = function() {
  playLoop(audioData);  
};

document.querySelector("#stop").onclick = function() {
  srcNode.stop();
};

/*
some event listener() {
  if (time >= 0 && time < 1.0) {
    document.querySelector("#circle1").style.display = 'block';
    document.querySelector("#circle2").style.display = 'none';
    document.querySelector("#circle3").style.display = 'none';
    document.querySelector("#circle4").style.display = 'none';
  }
  if (time >= 1.0 && time < 2.0) {
    document.querySelector("#circle1").style.display = 'none';
    document.querySelector("#circle2").style.display = 'block';
    document.querySelector("#circle3").style.display = 'none';
    document.querySelector("#circle4").style.display = 'none';
  }
  if (time >= 2.0 && time < 3.0) {
    document.querySelector("#circle1").style.display = 'none';
    document.querySelector("#circle2").style.display = 'none';
    document.querySelector("#circle3").style.display = 'block';
    document.querySelector("#circle4").style.display = 'none';
  }
  if (time >= 3.0 && time < 4.0) {
    document.querySelector("#circle1").style.display = 'none';
    document.querySelector("#circle2").style.display = 'none';
    document.querySelector("#circle3").style.display = 'none';
    document.querySelector("#circle4").style.display = 'block';
  }  
}
*/

1 Ответ

1 голос
/ 30 января 2020

Поскольку вы зацикливаете аудиоклип, нет доступных для использования событий. Однако, если вы использовали 4 отдельных 1-se c клипа, вы можете запланировать запуск каждого из них каждую секунду. Затем вы получите извлеченное событие из каждого клипа, который можно использовать для управления вашей SVG-анимацией.

Однако это означает, что вам придется выполнять свой собственный цикл аудио, постоянно планируя новые клипы каждые 4 се * 1012. *. Будьте уверены, что график следующего раунда до окончания текущего раунда и не используйте onended событие, чтобы запланировать следующий клип. Это будет постепенно дрейфовать со временем, но, возможно, это приемлемо для вашего приложения.

Очень грубый набросок того, как это может работать. Полностью не проверено, но я надеюсь, что это дает основную идею c:

// Clip is the 4 sec audio clip.
// context is the audioContext
clip = new Array(4);
// Create 4 clips using the same buffer
for (let k = 0; k < clip.length; ++k) {
  clip[k] = new AudioBufferSourceNode(context, {buffer: clip};
  clip[0].connect(context.destiantion);
}

let now = context.currentTime;
// Play out each 1 sec part of the clip consecutively, playing out
// the whole buffer 1 sec at a time.
clip[0].start(now, 0, 1);
clip[1].start(now + 1, 1, 1);
clip[2].start(now + 2, 2, 1);
clip[3].start(now + 3, 3, 1);

clip[0].onended = () => {
  // SVG when first clip ends
};
clip[1].onended = () => {
  // SVG when second clip ends
};
clip[2].onended = () => {
  // SVG when third clip ends
};
clip[3].onended = () => {
  // SVG when fourth clip ends
};

Это базовая c структура. Вам нужно изменить его на l oop. Таким образом, возможно, когда третий клип заканчивается, создайте новый клип [0], чтобы снова клип [2], с новым временем начала, Когда четвертый клип закончится, создайте новый клип [3]. Также обязательно добавьте добавленные события для каждого из этих новых клипов.

Существуют и другие способы, но это довольно просто и делает анимацию всегда синхронизированной со звуком c (с некоторой задержкой из-за обработка событий).

...