草庐IT

javascript - 在html中播放wav音频文件的移动波形

coder 2023-08-04 原文

如何在 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>

我想创建这样的波形

最佳答案

与下面相同,但随后使用了 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 而不是 canvas 元素,我花了几分钟才找出为什么图表一开始没有显示 :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>




Canvas 可视化器示例

演示: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

关于javascript - 在html中播放wav音频文件的移动波形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38727741/

有关javascript - 在html中播放wav音频文件的移动波形的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  9. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  10. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

随机推荐