2

我正在尝试使用 webkitAudioContext 为 HTML5 音频创建图形均衡器类型的可视化 - Chrome 仅在这一点上。

当我尝试更改音频源(即播放不同的歌曲)时,我发现异常和不可预测的行为。我在某处读到我应该等到触发音频上的“canplay”事件后再将其连接到上下文/分析器:

var context, sourceNode, analyser, javascriptNode, audio;

var ctx = $("#songcanvas").get()[0].getContext("2d");    


function loadSong(url) { 
    if (audio!=undefined) { audio.pause(); }
    audio = new Audio();
    audio.src = url;
    audio.addEventListener("canplay", function(e) {
         setupAudioNodes();
    }, false);
}

function setupAudioNodes() {
        context = new webkitAudioContext();
        javascriptNode = context.createJavaScriptNode(2048, 1, 1);
        javascriptNode.connect(context.destination);

        analyser = context.createAnalyser();
        analyser.smoothingTimeConstant = 0.3;
        analyser.fftSize = 512;

        sourceNode = context.createMediaElementSource(audio);
        sourceNode.connect(analyser);
        analyser.connect(javascriptNode);

        sourceNode.connect(context.destination);

        javascriptNode.onaudioprocess = function() {
            var array =  new Uint8Array(analyser.frequencyBinCount);
            analyser.getByteFrequencyData(array);
            ctx.clearRect(0, 0, 1000, 325);
            ctx.fillStyle="rgba(32, 45, 21,1)";
            drawSpectrum(array);
        }
        audio.play();
}

function drawSpectrum(array) {
    for ( var i = 0; i < (array.length); i++ ){
        var value = array[i];
        ctx.fillRect(i*5,325-value,3,325);
    }
};

前三四次我更改了源,它可以工作,然后最终以“Uncaught SyntaxError:AudioContext construction 的音频资源不可用”而失败

完整的演示在这里http://jsfiddle.net/eAgQN/

4

1 回答 1

7

JavaScriptNode如果您只是要绘制频谱,我建议您不要创建一个。而是尝试使用该requestAnimationFrame方法,因为它可以节省 CPU 周期并使您更接近恒定的 60fps(如果您的窗口/选项卡在后台,则特别有用,因为包裹在 a 中的任何函数requestAnimationFrame都会等到窗口再次成为焦点,然后再触发)。

您可能收到该错误的原因是因为 A)您只能为AudioContext每个窗口创建一个,B)您应该在MediaElementSource使用完它时断开连接,以及 C)您也应该删除实际Audio元素。

这是我上面概述的更改的演示:http: //jsbin.com/acolet/1/

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext(),
    audioAnimation, sourceNode, analyser, audio,
    songs  = document.getElementById('songs'),
    canvas = document.getElementById('songcanvas'),
    WIDTH  = canvas.width,
    HEIGHT = canvas.height,
    // get the context from the canvas to draw on
    ctx = canvas.getContext('2d'),
    gradient = ctx.createLinearGradient(0, 0, 0, HEIGHT),
    bar = { width: 2, gap: 2, ratio: HEIGHT / 256 };

gradient.addColorStop(1.00,'#000000');
gradient.addColorStop(0.75,'#ff0000');
gradient.addColorStop(0.25,'#ffff00');
gradient.addColorStop(0.00,'#ffff00');
ctx.fillStyle = gradient;

songs.addEventListener('click', loadSong, false);

function loadSong(e) {
  e.preventDefault();
  var url = e.target.href;
  if (!url) return false;
  if (audio) audio.remove();
  if (sourceNode) sourceNode.disconnect();
  cancelAnimationFrame(audioAnimation);
  audio = new Audio();
  audio.src = url;
  audio.addEventListener('canplay', setupAudioNodes, false);
}

function setupAudioNodes() {
  analyser = (analyser || context.createAnalyser());
  analyser.smoothingTimeConstant = 0.8;
  analyser.fftSize = 512;

  sourceNode = context.createMediaElementSource(audio);
  sourceNode.connect(analyser);
  sourceNode.connect(context.destination);
  
  audio.play();
  drawSpectrum();
}

function drawSpectrum() {
  var freq = new Uint8Array(analyser.frequencyBinCount);
  analyser.getByteFrequencyData(freq);
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  audioAnimation = requestAnimationFrame(drawSpectrum);
  for ( var i = freq.length - 1; i >= 0 ; i-- ){
    var x = i * (bar.width + bar.gap);
    var y = HEIGHT - (freq[i] * bar.ratio);
    ctx.fillRect(x, y, bar.width, HEIGHT);
  }
}
body { font-family: sans-serif; background-color: #000; }
a { color: #fff; text-decoration: none; }
ul { padding: 20px 0; width: 100px; }
ul, canvas { float: left; }
<ul id="songs">
  <li><a class="song" href="http://upload.wikimedia.org/wikipedia/en/4/45/ACDC_-_Back_In_Black-sample.ogg">ACDC</a></li>
  <li><a class="song" href="http://upload.wikimedia.org/wikipedia/en/9/9f/Sample_of_%22Another_Day_in_Paradise%22.ogg">Phil Collins</a></li>
  <li><a class="song" href="http://upload.wikimedia.org/wikipedia/en/1/1f/%22Layla%22%2C_Derek_and_the_Dominos_song_%28sample%29.ogg">Clapton</a></li>
</ul>
<canvas id="songcanvas" width="400" height="128"></canvas>

于 2013-02-19T16:42:09.170 回答