javascript - 使用 Web Audio API 的音频 react 视觉

标签 javascript html audio web-audio-api

我刚刚开始研究 Web Audio 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();

...这只是使用 Web Audio API 播放音频。不知道下一步该做什么。我查过Beat Detection Using JavaScript and the Web Audio APIMaking Audio Reactive Visuals页面,但无法真正理解任何内容。

如果我要向您展示我想在不使用 Web Audio 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

这不是我想要做的最终可视化,但首先创建音量计似乎是理解 Web Audio API 工作原理的更好主意。

关于javascript - 使用 Web Audio API 的音频 react 视觉,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32980375/

相关文章:

c# - 麦克风的输出格式是什么以保存为Wav

ios - 在后台模式下播放音频

javascript - 如何在不调用其构造函数的情况下复制对象及其原型(prototype)链?

javascript - HTML5 本地存储无法找到变量,即使 console.log 显示它

javascript - 错误: Uncaught (in promise): TypeError: Cannot read property 'customerName' of undefined

java - 通过 Java 中的 OutputStream 发送到 Firefox 的 HTML 代码无法识别

javascript - 有没有办法知道 <head> 内的外部 CSS 何时被应用,而不是等待图像加载

html - 渐进式 jpeg 与基线 jpeg

css - 将按钮定位在 Bootstrap 轮播中的链接上

java - 在Java中播放立体声?