一直觉得网易云音乐的用户体验是很不错的,很早就注意到了里面的鲸鱼音效,如下图,就是一个环形的跟着音乐节拍跳动的特效。

gif动图可能效果不太理想,可以直接在手机上体验

身为前端凭着本能的好奇心和探索心当然会研究一番,如何在页面上实现该效果?

1.AudioContext

其实这类动效原理并不复杂,你需要一堆数据来表述每一块的高度,然后通过某种方式,让前台渲染可见即可。

如何获取音乐实时的节拍数据呢,这里用到了AudioContext

AudioContext接口表示由音频模块连接而成的音频处理图,每个模块对应一个AudioNodeAudioContext可以控制它所包含的节点的创建,以及音频处理、解码操作的执行。做任何事情之前都要先创建AudioContext对象,因为一切都发生在这个环境之中。

这一段是从developer.mozilla.org/zh-CN/docs/…摘录下来的,里面有很多方法,详细可以看具体文档,这里只介绍我们下面用到的其中几个

1.1 AudioContext.createAnalyser()

AudioContextcreateAnalyser()方法能创建一个AnalyserNode,可以用来获取音频时间和频率数据,以及实现数据可视化。

var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
复制代码

这里返回的是一个AnalyserNode对象。

AnalyserNode 赋予了节点可以提供实时频率及时间域分析的信息。它使一个 AudioNode 通过音频流不做修改的从输入到输出, 但允许你获取生成的数据, 处理它并创建音频可视化。

AnalyserNode还有很多属性

AnalyserNode.fftSize

AnalyserNode 接口的 fftSize 属性的值是一个无符号长整型的值, 表示(信号)样本的窗口大小。当执行快速傅里叶变换(Fast Fourier Transfor (FFT))时,这些(信号)样本被用来获取频域数据。

fftSize 属性的值必须是从32到32768范围内的2的非零幂; 其默认值为2048。

AnalyserNode.frequencyBinCount 只读

frequencyBinCount 的值固定为 AnalyserNode 接口中fftSize值的一半. 该属性通常用于可视化的数据值的数量.

1.2 AudioContext.createMediaElementSource()

AudioContextcreateMediaElementSource() 方法用于创建一个新的 MediaElementAudioSourceNode 对象,输入某个存在的 HTML <audio> or <video> 元素, 对应的音频即可被播放或者修改。

var audioCtx = new AudioContext();
var source = audioCtx.createMediaStreamSource(stream);
复制代码

2.实现

上面很多api可能刚开始看的时候会犯晕,不过没事,下面一步一步写成一个例子就明白了。

这里我们采用canvas来绘制频谱图,下面简单写一个布局

<canvas id='canvas' width="600" height="600"></canvas>
<audio id="audio" controls autoplay loop></audio>
复制代码

加点样式

body{background: black;
}
canvas,audio{display: block;margin: 0 auto;
}
复制代码

下面来通过音频来获取频谱数据

var audio = document.getElementById('audio');
audio.crossOrigin = 'anonymous';
audio.src='./406238.mp3';
var ctx = new AudioContext();
var analyser = ctx.createAnalyser();
var audioSrc = ctx.createMediaElementSource(audio);audioSrc.connect(analyser);
analyser.connect(ctx.destination);analyser.fftSize = 512;var array = new Uint8Array(analyser.frequencyBinCount);
console.log(array)
复制代码

打印一下这个array,是一个长度为256的数组

这就是音频的频谱数据,这个长度跟上面设置的analyser.fftSize有关,是他的一半,也就是说,设置的越大,得到的数据越多,分析的也越准确。这里只是绘制一些条形图,并不需要默认的2048那么大,所以这里设置了512。

普通的频谱图

在此之前,我们先来实现一下常见的垂直频谱图,只需要用到ctx.fillRect来绘制一个个的方块就行了

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cwidth = canvas.width;
var cheight = canvas.height - 2;
var meterWidth = 5; //方块的宽度
var gap = 2; //方块的间距
var minHeight = 2;
var meterNum = cwidth / (meterWidth + gap);//根据宽度和间距计算出可以放多少个方块ctx.fillStyle = 'rgba(255,255,255,.5)';//填充function render() {var array = new Uint8Array(analyser.frequencyBinCount);analyser.getByteFrequencyData(array);var step = Math.round(array.length / meterNum);//从频谱数据中每隔step均匀取出meterNum个数据ctx.clearRect(0, 0, cwidth, cheight);for (var i = 0; i < meterNum; i++) {var value = array[i * step];ctx.fillRect(i * (meterWidth+gap) , cheight - value + capHeight, meterWidth, cheight||minHeight); //绘制}requestAnimationFrame(render);
}
render();
复制代码

如果需要渐变色的话,可以

var gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(1, '#0f00f0');
gradient.addColorStop(0.5, '#ff0ff0');
gradient.addColorStop(0, '#f00f00');
ctx.fillStyle = gradient ;//填充
复制代码

完整代码可以查看demo

环形的频谱图

如果上面的频谱图很清楚了的话,下面的环形也轻而易举了,主要用到了坐标的旋转

这里注意的是在进行translaterotate操作时需要进行ctx.save()ctx.restore(),因为操作的是坐标系,而不是元素本身,可以多尝试一下

var PI = Math.PI;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cwidth = canvas.width;
var cheight = canvas.height;
var cr = 230;//环形半径
var minHeight = 2;
var meterWidth = 5;
var meterNum = 180;//设置方块的数量,考虑到闭环的关系
var gradient = ctx.createLinearGradient(0, -cr, 0, -cwidth/2);
gradient.addColorStop(0, '#0f0');
gradient.addColorStop(0.5, '#ff0');
gradient.addColorStop(1, '#f00');
ctx.fillStyle = gradient;function render() {var array = new Uint8Array(analyser.frequencyBinCount);analyser.getByteFrequencyData(array);var step = Math.round(array.length / meterNum);ctx.clearRect(0, 0, cwidth, cheight);ctx.save();ctx.translate(cwidth/2,cheight/2);for (var i = 0; i < meterNum; i++) {//ctx.save();var value = array[i * step];var meterHeight = value*(cheight/2 - cr)/256||minHeight;ctx.rotate( 2*PI/meterNum );ctx.fillRect( -meterWidth/2 , -cr- meterHeight , meterWidth, meterHeight);//ctx.restore();}ctx.restore();requestAnimationFrame(render);
}
render();
复制代码

小tip

在进行旋转操作时,如果你每次旋转以后,都把坐标系还原,那么在循环的时候需要旋转30,60,90...这样

ctx.save();
ctx.rotate( 2*PI/meterNum*i );
ctx.restore();
复制代码

如果你在每次旋转以后,不还原坐标系,那么每次就是在上一次的基础上继续旋转

//ctx.save();
ctx.rotate( 2*PI/meterNum*i );
//ctx.restore();
复制代码

很显然,下面的方式更精简

完整代码可以查看demo

小节

以上就实现了环形的频谱图,是不是越来越靠近网易云音乐的鲸鱼音效了呢,中间加一个自动旋转的专辑封面就可以了~

之前写过几篇都是关于css的文章,有人可能觉得是不是不会js啊,天天捣鼓css,其实并不是这样的,各自有各自的职责范围,像界面UI之类的,本来就是样式上的事情,很多人一看看上去觉得css实现不了,马上就搬出js,效果是出来了,但体验差了一大截。


如果喜欢的文章的话,可以点赞并收藏,多多关注我的博客

利用AudioContext来实现网易云音乐的鲸鱼音效相关推荐

  1. python爬取网易云_利用python爬取网易云音乐,并把数据存入mysql

    作者:sergiojune Python爱好者社区--专栏作者 个人公众号:日常学python 专注python爬虫,数据可视化,数据分析,python前端技术 公众号:Python爱好者社区 获取本 ...

  2. 利用python爬取网易云音乐,并把数据存入mysql

    点击上方"程序人生",选择"置顶公众号" 第一时间关注程序猿(媛)身边的故事 图片源自网络 作者 sergiojune 如需转载,请联系原作者授权. 在简单学习 ...

  3. 如何利用python爬虫获取网易云音乐某个歌手简介_Python 爬虫获取网易云音乐歌手信息...

    今天就先带大家爬取网易云音乐下的歌手信息并把数据保存下来. 爬取结果 环境 语言:Python 工具:Pycharm 导包 BeautifulSoup:用来解析源码,提取需要的元素. selenium ...

  4. 仿网易云音乐鲸云音效-孤独星球

    闲来无事,打开网易云音乐,发现播放音乐时有好几款音效,属实夺人眼球,而网易云上的孤独星球音效是要vip权限才能开启的,这就让人不爽了,不想花钱那就手动撸一个出来自己边看边听歌,哇咔咔咔.由于是本人原创 ...

  5. 利用云函数实现网易云音乐自动签到、刷歌

    原理 使用腾讯云免费的[云函数服务]搭建网易云自动打卡,无需手动网页登录打卡,支持多账号,邮箱登陆,每天自动完成,不用每天去网站提交! 刷的歌都来自您的每日推荐歌单,不影响听歌风格. 部署 进入腾讯云 ...

  6. 利用selenium爬取网易云音乐歌手歌曲信息并分析

    1.网页分析 网址:https://music.163.com/#/search/m/?s=许嵩&type=1 观察网页,所有的歌曲信息都在class="srchsongst&quo ...

  7. 利用jupyter爬取网易云音乐华语歌曲信息

    1.导selenium包 from selenium import webdriver 2.进入谷歌 browser = webdriver.Chrome() 3.点击事件进入网页 browser.g ...

  8. 网易云音乐极速版,开屏无广告,免升级,无花里胡哨的功能

    网易云音乐 更新8.0增加了视频直播社区等功能, 但对于要求不多的人,实在是没用. 在此分享出极速版(官方在2019年7月推出的,后来下架了) 该版本取消了电台.视频.直播.商城.个性换肤等功能 并且 ...

  9. 利用Python爬取基于AES对称加密算法的网易云音乐用户评论数据

    本文利用Python2.7根据网易云音乐歌曲ID爬取了该歌曲的所有用户评论数据.以id是28875120的歌曲<小岁月太着急>为示例,通过Chrome的DevTools工具获取已加密评论数 ...

最新文章

  1. 在macos上基于python2.7安装PyQt5
  2. SQL函数---SQL HAVING 子句
  3. Java深拷贝与浅拷贝
  4. 用 C 语言开发一门编程语言 — 变量元素设计
  5. 06.十分钟学会表达式语言EL
  6. 今年Q3发布!小米12至尊版曝光:升级骁龙8 Plus处理器
  7. tar:归档中找不到 tar: 由于前次错误,将以上次的错误状态退出
  8. 一个Windows C++的线程池类实现
  9. python box2d模拟平抛运动_[HTML5]使用Box2dWeb模拟飞行箭矢
  10. 分享一下自己开发 kindle 电子书下载助手
  11. python实现GCD算法
  12. 杭州车牌摇号规则详细内容
  13. 树莓派系统安装和环境配置
  14. 微信小程序5-真机测试
  15. python 倒数两列_相机标定之张正友标定法数学原理详解(含python源码)
  16. VideoRender和ImageRender项目中遇到的一些cpp错误
  17. 局域网服务器怎么更改账号,怎么修改访问局域网共享用户名和密码
  18. 里程碑:SpaceX首次成功实现海上回收火箭
  19. 人脸检测颜值软件_百度AI人脸识别测颜值源码
  20. 揭秘拳头公司的游戏API: 充分发挥ZUUL的性能

热门文章

  1. 建设智慧政务平台应该具备什么内容?
  2. NLP-预训练模型-2019-NLU+NLG:BART【Bert+GPT的泛化Seq2Seq模型】【噪声破坏后的原文本喂给编码器,解码器输出原文本】【噪音方案:文本填充(文本片段用单个掩码替换)】
  3. C语言快速排序-qsort函数
  4. SAAS创建CAD模型
  5. Linux系列第二谈(开机关机、Linux中的文件、目录管理、基本属性)
  6. MATLAB找出二维数组中最接近某个数的n个数
  7. kadm5_init_with_skey
  8. 【通知】HCIE-Datacom 凌云百强榜公布
  9. 习题2-2 阶梯电价
  10. 总裁演说思维技巧:口才训练方法写日记法