可视化的音乐播放器,可戳我观看效果

了解Web-Audio-Api

基础知识

标签是HTML5的新标签,通过添加src属性实现音乐播放。

AudioContext是音频播放环境,原理与canvas的绘制环境类似,都是需要创建环境上下文,通过上下文的调用相关的创建音频节点,控制音频流播放暂停操作等操作,这一些操作都需要发生在这个环境之中。

try{

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();

}catch(e){

alert('Web Audio API is not supported in this browser');

}

AudioNode接口是一个处理音频的通用模块,它可以是音频音源模块,音频播放设备模块,也可以是中间音频处理模块。不同的音频节点的连接(通过AudioContext.connect()),以及终点连接AudioContext.destination(可以看作是连接到耳机或扬声器设备)完成后,才能输出音乐。

常见的音频节点:

AudioBufferSourceNode: 播放和处理音频数据

AnalyserNode: 显示音频时间和频率数据 (通过分析频率数据可以绘制出波形图之类的视图,可视化的主要途径)

GainNode: 音量节点,控制音频的总音量

MediaElementAudioSourceNode: 关联HTMLMediaElement,播放和处理来自和元素的音频

OscillatorNode: 一个周期性波形,只创建一个音调

...

运行模式

创建音频上下文

在上下文中,创建音频源

创建音频节点,处理音频数据并连接

输出设备

image

创建音频上下文

try{

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();

}catch(e){

alert('Web Audio API is not supported in this browser');

}

创建音频源

由于音频文件的数据是二进制(非文本),所以要设置请求头的responseType为arraybuffer,将.mp3音频文件转换成数组缓冲区ArrayBuffer

当AudioContext.decodeAudioData解码成功之后获取buffer,执行回调函数,将数据放入AudioBufferSourceNode中

方法一采用流式加载音乐文件,简单易懂,缺点是通过createMediaElementSource加载的src文件必须是同源,不允许跨域

下面步骤主要根据方法2。

方法一:通过HTMLMediaElement流式加载

let audio = document.querySelector('audio');

let audioCtx = new (window.AudioContext || window.webkitAudioContext)();

audio.addEventListener('canplay', function () {

let source = audioCtx.createMediaElementSource(audio);

source.connect(audioCtx.destination);

audio.play()

})

方法二:通过XMLHttpRequest获取资源

let xhr = new XMLHttpRequest();

xhr.open('GET', '1.mp3', true);

xhr.responseType = 'arraybuffer';

xhr.onload = function () {

audioCtx.decodeAudioData(xhr.response, function (buffer) {

getBufferSuccess(buffer)

})

}

方法三:通过input file获取

let input = document.querySelector('input');

input.addEventListener('change', function () {

if (this.files.length !== 0) {

let file = this.files[0];

let fr = new FileReader();

fr.onload = function () {

let fileRet = e.target.result;

audioCtx.decodeAudioData(fileRet, function (buffer) {

getBufferSuccess(buffer);

}, function (err) {

console.log(err)

})

}

fr.readAsArrayBuffer(file);

}

})

处理音频数据

function getBufferSuccess(buffer) {

// 创建频率分析节点

let analyser = audioCtx.createAnalyser();

// 确定频域的快速傅里叶变换大小

analyser.fftSize = 2048;

// 这个属性可以让最后一个分析帧的数据随时间使值之间的过渡更平滑。

analyser.smoothingTimeConstant = 0.6;

// 创建播放对象节点

let source = audioCtx.createBufferSource();

// 填充音频buffer数据

source.buffer = buffer;

// 创建音量节点(如果你需要用调整音量大小的话)

let gainNode = audioCtx.createGain();

// 连接节点对象

source.connect(gainNode);

gainNode.connect(analyser);

analyser.connect(audioCtx.destination);

}

获取音频频率

方法一:用js的方法获取(通过监听audioprocess事件,由于性能问题,将会被弃用,不做详细说明,感兴趣的可以了解一下)

// 此方法需要补充节点的连接

let javascriptNode = audioCtx.createScriptProcessor(2048, 1, 1);

javascriptNode.connect(audioCtx.destination);

analyser.connect(javascriptNode);

this.javascriptNode.onaudioprocess = function () {

currData = new Uint8Array(analyser.frequencyBinCount);

analyser.getByteFrequencyData(currData);

}

方法二:用AnalyserNode获取

获取AnalyserNode节点里的频率长度frequencyBinCount,实例化长度为8位的整型数组,通过AnalyserNode.getByteFrequencyData将节点中的频率数据拷贝到数组中去,值的大小在0 - 256之间,数值越高表明频率越高;AnalyserNode.getByteTimeDomainData原理一样,不过获取的是频率大小,两种方法根据需求选一种即可。

function getData () {

// analyser.frequencyBinCount 可视化值的数量,是前面fftSize的一半

let currData = new Uint8Array(analyser.frequencyBinCount);

analyser.getByteFrequencyData(currData);

analyser.getByteTimeDomainData(currData);

}

输出设备

AudioBufferSourceNode.start(n) n表示开始的时间,默认为0,开始播放音频

AudioBufferSourceNode.stop(n) 音频在第n秒时间停止,若没有传值表示立即停止

其他api

AudioContext.resume() 控制音频的播放

AudioContext.suspend() 控制音频的暂停

AudioContext.currentTime 获取当前音频播放时间

AudioBufferSourceNode.buffer.duration 获取音频的播放总时长

GainNode.gain.value 控制音量大小 [0, 1]

GainNode.gain.linearRampToValueAtTime 实现音量的渐入渐出

Canvas绘制可视化效果

了解上面的api,就可以来着手绘制啦~,你想绘啥就绘啥,频繁的调用canvas的api很耗性能问题,这里讲下我在测试中提高性能的小技巧。

多分层canvas,一些不需要频繁改动的绘制,例如背景,固定的装饰绘制,可以采用另一个canvas的上下文来绘制

离屏绘制,原理是生成一个没有出现在页面的canvas,在这个缓存的canvas中绘制,而真正展示的canvas只需要通过drawImage这个api将画面绘制出来即可,参考此博文

固定好lineWidth的长度,而不是每绘制一个就设定一次lineWidth

绘制区域提前计算好,不要让canvas边绘制同时还要计算位置(canvas:好累哦~)

总而言之,少调用canvas api,可是也不要为了提高性能而抛弃你的一些天马星空的想法哦

遇到的问题

在切换歌曲中,遇到了这个报错Failed to set the 'buffer' property on 'AudioBufferSourceNode': Cannot set buffer to non-null after it has been already been set to a non-null buffer at AudioContext,大致是讲AudioBufferSourceNode的buffer属性在之前我已经设置过了,不能被重新设置新的buffer值,由于播放歌曲主要是通过其数组缓冲区ArrayBuffer来进行,可看看issue,解决办法就是当需要切换歌曲情况下,将当前的AudioBufferSourceNode销毁,重新创建上下文环境,音频节点,连接等操作。

源码在这,交互部分写得有点乱,因为当时原来只是想练练可视化,之后想到啥功能就加,所以导致代码看起来冗余繁琐,大家可以参考看看audio实现,主要在MusicPlay对象。

小白第一次发表博文,发现写博文比写一个demo还要时间长,怕写出来的东西有错误会误导大家(有错误请大家评论指出~),所以会去查很多相关资料,这个过程也是学习的过程,以后会经常写写博文滴!最后,希望大家通过这篇文章也能学会自己做这种可视化的效果,配合一些可视化库还能做出很酷炫的效果呢,一起互相学习进步吧,加油!(。・д・。)

image

html音乐播放器换歌,web-audio-api可视化音乐播放器,实现暂停切换歌曲功能,粉色系专场~...相关推荐

  1. Web Audio API与WebSocket播放实时音频

    WebSocket客户端与Web Audio API示例 <!DOCTYPE html> <html><head><meta charset="ut ...

  2. html 音乐切换不暂停,web-audio-api可视化音乐播放器,实现暂停切换歌曲功能,粉色系专场~...

    可视化的音乐播放器,可戳我观看效果 了解Web-Audio-Api 基础知识 标签是HTML5的新标签,通过添加src属性实现音乐播放. AudioContext是音频播放环境,原理与canvas的绘 ...

  3. web audio api 实现音频播放

    最近被选中做音视频,挺幸运的吧,一直在接触新的项目,每次都能被分到新的项目组,干好多费头发的事情

  4. HTML 利用 Web Audio API 进行音频可视化

    利用Web Audio API 进行音乐可视化 1.什么是 Web Audio API: 官方:Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统,允许开发者来自选音频源,对 ...

  5. Web Audio API实现简单变声效果

    前言 想在网页中实现实时音频变声效果该如何实现呢,之前遇到这种处理音视频的需求,可能会想到需要借助C代码实现.但是现在随着浏览器性能的提升.web API的丰富,通过浏览器原生的API也可以操作音频数 ...

  6. Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo

    1.Web Audio API 介绍 Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各 ...

  7. 利用Web Audio API将振动数据转化为音频数据并播放

    年初在公司做了一个需求:传感器采集到了机器的振动数据,要在网页中利用这个数据播放出振动的声音. 之前只了解过HTML中的<audio>元素可以通过src属性指定音频文件路径来播放音频,现在 ...

  8. html audio重新播放,javascript – Web Audio API:如何重新开始播放声音?

    我在Chrome中编写了一个基本脚本,它使用新的Web Audio Api加载3个声音文件(通过 XMLHTTPRequest),并逐个播放它们.我为每个声音提供了一个单独的按钮,允许用户启动和停止每 ...

  9. web audio api_带有Web Audio API的动态声音

    web audio api This article is part of a web dev series from Microsoft. Thank you for supporting the ...

最新文章

  1. Mysql DBA 高级运维学习之路-mysql数据库入门知识
  2. Bootstrap系列 -- 6. 列表
  3. 2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,
  4. 学习HTML5 canvas遇到的问题
  5. 常用内存分配函数的说明
  6. 【飞秋】微软简化Visual Studio 非程序员也能开发软件
  7. 开发经验漫谈 -- Git在开发流程中的运用
  8. Java 蓝桥杯 高精度加法
  9. mycat分布式mysql中间件(自增主键)
  10. linux包含绝对路径头文件,linux-kernel - 访问用户空间内存访问函数(如access_ok(),get_from_user())需要包含的头文件的确切路径。 - 堆栈内存溢出...
  11. PS滤镜插件工具箱Mac版:Nik Collection 4
  12. 数字电子技术期末考试思维导图
  13. LINUX PPP拨号永久在线保障机制
  14. 骑士游历问题——至少需要多少步
  15. 虽焦虑迷惘,仍选择自由职业,只因……
  16. 关于Flex布局属性详解
  17. 紫杉醇人血清白蛋白纳米粒PTX-HSA|阿霉素卵清白蛋白纳米粒DOX-OVA|顺铂小鼠血清白蛋白纳米粒CDDP-MSA(试剂)
  18. 3万字长文带你轻松入门视觉Transformer
  19. 远程入侵原装乘用车(中)
  20. Struts2的 两个蝴蝶飞 你好 (一)

热门文章

  1. 百度资深架构师总结微服务化的不同阶段 Kubernetes 的不同玩法
  2. 高速缓存Cache详解(西电考研向)
  3. 小六六平时的开发小技巧一(公共属性填充))
  4. BLUEMOON记录
  5. 【标准全文】GB 38031-2020 电动汽车用动力蓄电池安全要求
  6. 从《七里香》到GCC as汇编语言
  7. Ubuntu下GPU显存无法释放和多卡训练时候的一些总结
  8. mysql去重合并字符串_Mysql将近两个月的记录合并为一行显示
  9. 2022华数杯B题论文思路分析+完整代码(水下机器人组装计划)
  10. xfplay(先锋影音) v8.9.6 官方版​