【问题标题】:Play a moving waveform for wav audio file in html在 html 中播放 wav 音频文件的移动波形
【发布时间】:2016-12-08 05:44:47
【问题描述】:

如何在 HTML 中为音频文件/标签创建移动波形? 单击播放按钮时,必须播放音频 HTML 元素并生成相应的移动波形......如何实现?

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title id='title'>HTML Page setup Tutorial</title> 
        <script src='riffwave.js'></script>

        <script type="text/javascript">

    function myFunction()
    {
    var data = []; // just an array
for (var i=0; i<10000; i++) data[i] = /*Math.round(255 * Math.random())*/i; // fill data with random samples
var wave = new RIFFWAVE(data); // create the wave file
var audio = new Audio(wave.dataURI); // create the HTML5 audio element
audio.play();


    }
    </script>
    </head>
<body>

<button type="button" onclick="myFunction()">Click Me!</button>
</body>
</html>

我想创建这样的波形

【问题讨论】:

标签: javascript html audio html5-canvas html5-audio


【解决方案1】:

与以下相同,但使用 canvasjs:

演示:http://seapip.com/canvas/visualizer4/

/*
Speed has to be bigger then refresh!!!
*/

//Speed to move from right to left, also the visible amount of time on the x axis (in milliseconds)
var speed = 10000;

//Time in milliseconds to redraw chart
var refresh = 30;

//Without var to make it a global variable accessable by the html onclick attribute 
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();

// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);

//Get frequency data
var frequencyData = new Uint8Array(analyser.frequencyBinCount);

//The animation reference
var animation;

//Create chart
var dps = []; // dataPoints
var chart = new CanvasJS.Chart("chart", {
    interactivityEnabled: false,
    width: 500,
    height: 200,
    axisX: {
        title: "Time",
        valueFormatString: "mm:ss"
    },
    axisY: {
        title: "dB"
    },
    data: [{
        type: "line",
        dataPoints: dps
    }]
});
chart.render();

//On play
audioElement.onplay = function() {
    //Start drawing
    animation = setInterval(function() {
        drawWave();
    }, refresh);
};

//On pause
audioElement.onpause = function() {
    //Stop drawing
    clearInterval(animation);
};

//On ended
audioElement.onended = function() {
    //Stop drawing
    clearInterval(animation);

    //Reset time
    time = 0;

    //Reset dataPoints
    dps = [];

    //Prevent audio from looping (you can remove this if you want it to loop)
    audioElement.pause();
};

//Max dB
var max = analyser.maxDecibels;

//Min dB
var min = analyser.minDecibels;

//Time
var time = 0;

//Our drawing method
function drawWave() {

    // Copy frequency data to frequencyData array.
    analyser.getByteFrequencyData(frequencyData);

    //Total loudness of all frequencies in frequencyData
    var totalLoudness = 0;
    for(var i = 0; i < frequencyData.length; i++) {
        totalLoudness += frequencyData[i];
    }

    //Average loudness of all frequencies in frequencyData on scale from 0 to 255
    var averageLoudness = totalLoudness / frequencyData.length / 255;

    //Decibels
    var decibels = min + averageLoudness * Math.abs(min - max);

    //Increase time
    time += refresh;

    //Add to chart
    dps.push({
        x: new Date(time),
        y: decibels
    });

    //Maximum x values to draw based on speed ad refresh
    if(dps.length > speed / refresh) {
        dps.shift();
    }

    //Draw new chart
    chart.render(); 
}


<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<div id="chart"></div>
<div>
  <button onclick="audioElement.play()">Play the Audio</button>
  <button onclick="audioElement.pause()">Pause the Audio</button>
  <button onclick="audioElement.volume+=0.1">Increase Volume</button>
  <button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>

请记住,#chart 是一个 div 而不是一个画布元素,我花了几分钟才弄清楚为什么图表一开始没有显示:P




与下面相同,但从右到左绘制。 stepSize 变量设置动画速度和步长的大小,如果你想画更大的步,那么它需要移动得更快,如果你想画更小的步,它需要移动得更慢。

演示:http://seapip.com/canvas/visualizer3

//Step size (pixels per 20ms)
var stepSize = 0.5;

//Without var to make it a global variable accessable by the html onclick attribute 
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();

// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);

//Get frequency data (800 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);

//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "500px";
canvas.style.height = "100px";

//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;

//Get canvas context
var ctx = canvas.getContext("2d");

//Stroke color
ctx.strokeStyle = "#ffff00";

//Draw thicker lines due to high dpi scaling
ctx.lineWidth = 2;

//Store y values
var drawY = [canvas.height];

//The animation reference
var animation;

//On play
audioElement.onplay = function() {
    //Start drawing
    animation = setInterval(function() {
        drawWave();
    }, 20);
};

//On pause
audioElement.onpause = function() {
    //Stop drawing
    clearInterval(animation);
};

//On ended
audioElement.onended = function() {
    //Stop drawing
    clearInterval(animation);

    //Clear previous y values
    drawY = [canvas.height];

    //Prevent audio from looping (you can remove this if you want it to loop)
    audioElement.pause();
};

//Our drawing method
function drawWave() {

    // Copy frequency data to frequencyData array.
    analyser.getByteFrequencyData(frequencyData);

    //Total loudness of all frequencies in frequencyData
    var totalLoudness = 0;
    for(var i = 0; i < frequencyData.length; i++) {
        totalLoudness += frequencyData[i];
    }

    //Average loudness of all frequencies in frequencyData
    var averageLoudness = totalLoudness / frequencyData.length;

    //Scale of average loudness from (0 to 1), frequency loudness scale is (0 to 255)
    var y = averageLoudness / 255;
    //Multiply with canvas height to get scale from (0 to canvas height)
    y *= canvas.height;
    //Since a canvas y axis is inverted from a normal y axis we have to flip it to get a normal y axis value
    y = canvas.height - y;

    //Store new y value
    drawY.push(y);

    //Clear previous drawing
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    //Draw line
    for(var i = drawY.length; i > 0; i--) {

        //calculate x values
        var x1 = canvas.width - (drawY.length - i - 1) * stepSize;
        var x2 = canvas.width - (drawY.length - i) * stepSize;

        //Stop drawing y values if the x value is outside the canvas
        if(!x2) {
            break;
        }
        ctx.beginPath();
        ctx.moveTo(x1, drawY[i - 1]);
        ctx.lineTo(x2, drawY[i]);
        ctx.stroke();
    }
}


<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
  <button onclick="audioElement.play()">Play the Audio</button>
  <button onclick="audioElement.pause()">Pause the Audio</button>
  <button onclick="audioElement.volume+=0.1">Increase Volume</button>
  <button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>




这就是我认为您可能想要的,x 轴是时间,y 轴是所有频率的平均响度。请记住,chrome 等浏览器无法在后台选项卡中正确绘制图形,因为它会限制刷新间隔和音频分析器输出。

演示:http://seapip.com/canvas/visualizer2

//Without var to make it a global variable accessable by the html onclick attribute 
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();

// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);

//Get frequency data (800 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);

//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "1000px";
canvas.style.height = "100px";

//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;

//Get canvas context
var ctx = canvas.getContext("2d");

//Set stroke color to yellow
ctx.strokeStyle = "#ffff00";

//Draw twice as thick lines due to high dpi scaling
ctx.lineWidth = 2;

//Save x and y from the previous drawing
var drawX = 0;
var drawY = 0;

//Total duration (Seconds)
var duration;

//The animation reference
var animation;

//Audio is loaded
audioElement.oncanplaythrough = function() {

    //Get duration
    duration = audioElement.duration;

    //On play
    audioElement.onplay = function() {
        //Start drawing
        drawWave();
    };

    //On pause
    audioElement.onpause = function() {
        //Stop drawing
        cancelAnimationFrame(animation);
    };

    //On ended
    audioElement.onended = function() {
        //Stop drawing
        cancelAnimationFrame(animation);

        //Clear previous drawing
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        //Clear previous x and y values
        drawX = 0;
        drawY = 0;

        //Prevent audio from looping (you can remove this if you want it to loop)
        audioElement.pause();
    };
};

//Our drawing method
function drawWave() {

    //Current time (seconds)
    var currentTime = audioElement.currentTime;

    // Copy frequency data to frequencyData array.
    analyser.getByteFrequencyData(frequencyData);

    //Total loudness of all frequencies in frequencyData
    var totalLoudness = 0;
    for(var i = 0; i < frequencyData.length; i++) {
        totalLoudness += frequencyData[i];
    }

    //Average loudness of all frequencies in frequencyData
    var averageLoudness = totalLoudness / frequencyData.length;

    //Get the previous x axis value
    var previousDrawX = drawX;

    //Scale of progress in song (from 0 to 1)
    drawX =  currentTime / duration;
    //Multiply with canvas width to get x axis value
    drawX *= canvas.width;

    //Get the previous y axis value
    var previousDrawY = drawY;

    //Scale of average loudness from (0 to 1), frequency loudness scale is (0 to 255)
    drawY = averageLoudness / 255;
    //Multiply with canvas height to get scale from (0 to canvas height)
    drawY *= canvas.height;
    //Since a canvas y axis is inverted from a normal y axis we have to flip it to get a normal y axis value
    drawY = canvas.height - drawY;

    //Draw line
    ctx.beginPath();
    ctx.moveTo(previousDrawX, previousDrawY);
    ctx.lineTo(drawX, drawY);
    ctx.stroke();

    //Animate
    animation = requestAnimationFrame(drawWave);
}


<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
  <button onclick="audioElement.play()">Play the Audio</button>
  <button onclick="audioElement.pause()">Pause the Audio</button>
  <button onclick="audioElement.volume+=0.1">Increase Volume</button>
  <button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>




画布可视化示例

演示:http://seapip.com/canvas/visualizer/

//Without var to make it a global variable accessable by the html onclick attribute 
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();

// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);

//Get frequency data (400 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);

//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "500px";
canvas.style.height = "100px";

//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;

//Get canvas context
var ctx = canvas.getContext("2d");

//Set stroke color
ctx.strokeStyle = "#ffff00"

//Draw twice as thick lines due to high dpi scaling
ctx.lineWidth = 2;

//Animation reference
var animation;

//On play
audioElement.onplay = funtion() {
    drawWave();
};

//On pause
audioElement.onpause = funtion() {
    cancelAnimationFrame(animation);
};

//On ended
audioElement.onended = funtion() {
    cancelAnimationFrame(animation);
};

//Our drawing method
function drawWave() {
    // Copy frequency data to frequencyData array.
    analyser.getByteFrequencyData(frequencyData);

    //Draw the wave
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for(var i = 1; i < frequencyData.length; i++) {
        var x1 = canvas.width / (frequencyData.length - 1) * (i - 1);
        var x2 = canvas.width / (frequencyData.length - 1) * i;
        var y1 = canvas.height - frequencyData[i - 1] / 255 * canvas.height;
        var y2 = canvas.height - frequencyData[i] / 255 * canvas.height;
        if(x1 && y1 && x2 && y2) {
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }
    }

    //Animate
    animation = requestAnimationFrame(drawWave);
}


<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
  <button onclick="document.getElementById('audioElement').play()">Play the Audio</button>
  <button onclick="document.getElementById('audioElement').pause()">Pause the Audio</button>
  <button onclick="document.getElementById('audioElement').volume+=0.1">Increase Volume</button>
  <button onclick="document.getElementById('audioElement').volume-=0.1">Decrease Volume</button>
</div>




关于音频可视化的插件和教程:

https://wavesurfer-js.org/

http://waveformjs.org/#weird

https://www.bignerdranch.com/blog/music-visualization-with-d3-js/

https://github.com/wayou/HTML5_Audio_Visualizer

https://www.patrick-wied.at/blog/how-to-create-audio-visualizations-with-javascript-html

https://p5js.org/examples/examples/Sound_Frequency_Spectrum.php

【讨论】:

  • 我在答案之上添加了代码,显示了如何从左到右绘制波浪的代码。我使用了动画帧并删除了 settimeout,因为它不需要。要从右到左绘制波浪,我们需要存储先前的绘制步骤并在每个动作上重新绘制整个波浪,这有点复杂,但如果你愿意,我可以将它添加到答案中。如果您对我刚刚添加的答案之上的代码有任何疑问,请告诉我。
  • 我更新了答案,只显示没有依赖关系的画布示例。我将添加另一个示例,显示如何修改从左到右的绘图画布以从右到左绘制,就像在您的 canvasjs 示例中一样。
  • 没问题。如果您想知道它的含义,stepSize 变量是为 20 毫秒的音乐绘制的宽度像素数量。
  • 快搞定了,之前没用过canvasjs,所以花了一些时间才弄明白。
  • 添加了一个使用 canvasjs 的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-21
  • 1970-01-01
  • 2013-12-24
相关资源
最近更新 更多