惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
Y
Y Combinator Blog
博客园_首页
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
宝玉的分享
宝玉的分享
B
Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
WordPress大学
WordPress大学
L
LangChain Blog
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
C
Check Point Blog
博客园 - 聂微东
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Help Net Security

smallyu的博客

为什么买的加密货币一定要去中心化 RISC-V 虚拟机无法代替 EVM 虚拟机 Polkadot 的 Existential Deposit 机制错在哪里 利息,套利,交易策略,金融市场 LayerZero 从来不挑战比特币的地位 默认参数引起的以太坊节点运行错误 硬件钱包与资产安全 预测市场比币圈更赌场 为什么去中心化的跨链桥不可能实现 我对于 AI 时代的答案 不要投资任何隐私币 区块链技术世界的三大真理 以太坊 AA 钱包的致命问题是什么 基于 AI 语义执行的 MCP 区块链的设计 一个集成 Geth 和 CometBFT 的兼容层 我的加密货币定投策略(二) DeFi 基础: 理解 AMM 定价机制 Go 语言 GMP 调度器的原理是什么 Web3 项目分析计划 对 Psyche Network 项目的分析 continuation 教程: 理解 CPS 如何开发一个比特币符文(Runes)协议 比特币脚本开发教程 我从王垠的计算机科学视频班学到了什么 区块链技术面试题(2025年版) Rust 语言容易让新手困惑的一个“过度优化” Solana 智能合约开发教程 (1) 尝试开发一个最小 EVM 虚拟机 基于 ZK 的链上身份系统设计 一个 Web3 打赏系统的设计
HTML5 音乐可视化
2017-05-16 · via smallyu的博客

2017-05-17

下面梳理一下HTML5实现音乐可视化的流程。

搭建静态页面

静态页面的结构分三部分,header,left,right。header为语义化标签,left和right都用div来实现。

类似这样,然后把背景颜色改为黑色,字体改成白色,加上或不加边框线,给一定padding或margin,静态页面就搭建好啦。

不过重点不是页面布局。可以在左侧栏有一个曲目列表,点击切歌。这里就不那么麻烦,直接后台加载指定的歌曲。歌曲是许嵩的烟花笑,左侧栏显示部分歌词。

创建音频文件对象

AudioContext对象用于获取音频文件源。

(节点)AudioContext:包含各个AudioNode对象以及它们的联系的对象,可以理解为上下文对象。绝大多数情况下,一个document中只有一个AudioContext。

(方法)createBufferSource():创建audioBufferSourceNode对象。

可以这样写:

var ac = new window.AudioContext();    // 实例化ac为一个音频对象
var bs = ac.createBufferSource();      // 用bs来保存音频文件资源

有了音频资源,是否就可以播放音频了呢?当然不可以,因为还没有指定文件,告诉对象播放哪一个音频文件。

获取音频数据

创建bufferSource后,到了AudioBufferSourceNode这个节点。这个节点有一个属性值buffer,用来指定文件资源。这个属性值需要一个buffer类型的数据。

(节点)AudioBufferSourceNode:表示内存中的一段音频资源,其音频数据存在于AudioBuffer中(其buffer属性)。

(属性)buffer:AudioBuffer对象,表示要播放的音频资源数据。

获取buffer有两种方式,一种是ajax设置返回值类型为arraybuffer,然后解码,一种是用FileReader读取文件,获得blob值。后一种方式多用input上传文件后获得文件,再进行解析。前面一种好用一点。(留坑)

ajax的原生写法:

var url="...";
var xhr = new XMLHttpRequest();
xhr.abort();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function(){
    return xhr.response;
}
xhr.send();

onload触发的函数中xhr.response就是我们想要的值。

(方法)decodeAudioData(arrayBuffer, succ(buffer), err) :异步解码包含在arrayBuffer中的音频数据。

将arraybuffer解码:

ac.decodeAudioData(arraybuffer, function(buffer){ ... },function(err){ ... });
bs.buffer = buffer;    // 回调函数中的buffer就是想要的buffer

播放音乐

(方法)start:开始播放音频

这个时候调用start方法:

bs.start(0);

打开页面,音乐开始播放。

音量控制

(节点)GainNode:改变音频音量的对象,会改变通过它的音频数据所有的sample frame的信号强度。

(方法)createGain():创建GainNode对象。

(属性)value:可以改变音频信号的强弱,默认为1,最小值为0。

音乐播放还不行,要添加一个音量控制控件,音量控制用GainNode节点:

var gainNode = accreateGain();    // 创建GainNode对象
gainNode.connect(ac.destination);    // 将gainNode连接到AudioDestinationNode节点

这样就有了一个音量控制的对象。

gainNode.gain.value= ... ;

gain.value用于控制输入信号的强弱,也就是音量的大小。HTML中用type为range的input,把值传递给对象,就可以实时控制音量了。

得到音频解析数据

(节点)AnalyserNode:音频分析对象,他能实时的分析音频资源的频域和时域信息,但不会对音频流做任何处理。

(方法)createAnalyser():创建AnalyserNode对象。

(属性)fftsize:设置FFT(是离散傅里叶变换的快速算法,用于将一个信号变换到频域)值的大小,用于分析得到频域,为32 ~ 2048之间2的整数次倍,默认为2048,实时得到的音频频域的数据个数为fftSize的一半。

(属性)frequencyBinCount,FFT值的一半,即实时得到的音频频域的数据个数

(方法)getByteFrequencyData(Uint8Array),复制音频当前的频域数据(数量是frequencyBinCount)到Uint8Array(8位无符号整型类型化数组)中。

先创建AnalyserNode对象,然后设置fftsize的值。FFT用于数字信号的处理,会把音频文件流输入的信号变换到频域,用getByteFrequencyData()方法得到经系统处理之后的频域数据。

var analyser = ac.createAnalyser();    // 实例化对象
analyser.fftSize = 32;                 // 设置fftsize
var arr = new Uint8Array(analyser.frequencyBinCount);    // getByteFrequencyData()方法要求参数为8位无符号整型类型化数组
analyser.getByteFrequencyData(arr);    //    arr为所需频域数据

这样得到的数组arr就是用于可视化效果绘制的数据。

(方法)window.requestAnimationFrame():告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调用的回调作为参数。

一次解析只能得到一组数据,所以需要requestAnimationFrame不断解析,不断得到arr。

前端界面绘制

前端界面使用canvas绘制,实现音乐可视化的效果。

var box = document.getElementById("right");    // 获取right区域的dom
box.appendChild(canvas);                       // 创建canvas节点
var ctx = canvas.getContext("2d");             // 实例化canvas画笔

接下来就是使用for循环和ctx画矩形、圆圈,填充渐变的操作了。(留坑吧,估计不填了)

案例用到web Audio API的关系:

虚线是可以跳过的节点,直接播放音频文件。好吧有错。