使用网络音频的音频反应视觉 API

Audio reactive visual using Web Audio API

我刚开始研究网络音频 API,我正在尝试与音频进行视觉同步。当音频音量(节拍?)增加时,我想在屏幕上闪烁白色。到目前为止我做了什么:

var mp3     = "08 - No More Sorrow.mp3";
var context = new AudioContext();
var request = new XMLHttpRequest();
request.open('GET', mp3, true);
request.responseType = "arraybuffer";
request.onload = function () {
    context.decodeAudioData(request.response, function (buffer) {
        var sourceBuffer = context.createBufferSource();
        sourceBuffer.buffer = buffer;
        sourceBuffer.connect(context.destination);
        sourceBuffer.start(context.currentTime);
    });
};
request.send();

...这只是使用网络音频 API 播放音频。不知道下一步该做什么。我已经检查了 Beat Detection Using JavaScript and the Web Audio API and Making Audio Reactive Visuals 页,但什么都看不懂。

如果我要向您展示我想在不使用网络音频的情况下做什么 API,它会是这样的:

Array.prototype.pushIfExists = function(item) {
  if (item) {
    this.push(item);
  }
}

function random(min, max) {
  var min = min || 0;
  var max = max || 100;
  var num = Math.floor(Math.random() * max);
  while (num < min) {
    num = Math.floor(Math.random() * max);
  }
  return num;
}

function avarage(array) {
  var sum = 0;
  var avarage = 0;
  for (var i = 0; i < array.length; i++) {
    sum += array[i];
  }
  avarage = sum / array.length;
  return avarage;
}

var beats = [];
var delay = 500;
var delayIncrement = 200;
var threshold = 50;
var thresholdLimit = 100;
var beatAvarageRange = 5;
var flashDuration = 100;

for (var i = 0; i < 100; i++) {
  beats.push(random(0, thresholdLimit));
}

for (var i = 0; i < beats.length; i++) {
  (function(i) {
    setTimeout(function() {
      var recentBeats = [];
      for (var j = 1; j < beatAvarageRange + 1; j++) {
        recentBeats.pushIfExists(beats[i - j]);
      }
      threshold = avarage(recentBeats);
      if (beats[i] > threshold) {
        document.body.style.backgroundColor = "white";
        setTimeout(function() {
          document.body.style.backgroundColor = "black";
        }, flashDuration);
      }
    }, delay);
    delay += delayIncrement;
  })(i);
}
body {
  background-color: black;
}

我进行了更多挖掘并找到了解决方案。使用 Exploring the HTML5 Web Audio: visualizing sound | Smartjava.org 页面中的解释,我得出以下结论:

var volumeBars = {
    mono : document.getElementById("monoFill")
};

document.getElementById("open-file").onchange = function (evt) {
    var file = evt.target.files[0];
    var reader = new FileReader();
    reader.onload = function(e) {
        playSound(e.target.result);
    }
    reader.readAsArrayBuffer(file);
}

var context = new AudioContext();

function playSound(arraybuffer) {
    context.close();
    context = new AudioContext();

    var source = context.createBufferSource();
    context.decodeAudioData(arraybuffer, function (buffer) {
        source.buffer = buffer;
    });

    var analyser = context.createAnalyser();
    analyser.smoothingTimeConstant = 0.3;
    analyser.fftSize = 1024;

    jsNode = context.createScriptProcessor(2048, 1, 1);
    jsNode.onaudioprocess = function() {
        var array = new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        volumeBars.mono.style.height = Math.average(array) * 2 + "px";
        volumeBars.mono.innerHTML = Math.floor(Math.average(array));
    }

    source.connect(analyser);
    source.connect(context.destination);
    jsNode.connect(context.destination);
    analyser.connect(jsNode);

    source.start();
}

Math.average = function(arguments) {
    var numbers;
    if (arguments[0] instanceof Array) {
        numbers = arguments[0];
    }
    else if (typeof arguments[0] == "number") {
        numbers = arguments;
    }
    var sum = 0;
    var average = 0;
    for (var i = 0; i < numbers.length; i++) {
        sum += numbers[i];
    }
    average = sum / numbers.length;
    return average;
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body {
    background-color: gainsboro;
}
#container {
    height: 340px;
}
.bar {
    width: 50px;
    height: 100%;
    position: relative;
    float: left;
    margin: 20px;
    height: calc(100% - 40px);
}
.fill {
    background: LawnGreen;
    height: 20px;
    width: 100%;
    box-shadow: 0 0 3px rgba(0,0,0,.25),
        inset 1px 1px 1px rgba(255,255,255,.75),
        inset -1px -1px 1px rgba(0,0,0,.4);
    position: absolute;
    bottom: 0;
    padding: 5px;
    color: rgba(0,0,0,.75);
}
input {
    margin: 20px;
}
<div id="container">
 <div class="bar" id="mono">
  <div class="fill" id="monoFill"></div>
 </div>
</div>

<input type="file" id="open-file" accept="audio/*" />

Web Audio API - Volume Meter - JSFiddle

这不是我要尝试做的最终可视化,但首先创建一个音量计似乎是理解网络音频 API 工作原理的更好主意。