成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

利用AudioContext來(lái)實(shí)現(xiàn)網(wǎng)易云音樂(lè)的鯨魚音效

cod7ce / 2457人閱讀

摘要:一直覺(jué)得網(wǎng)易云音樂(lè)的用戶體驗(yàn)是很不錯(cuò)的,很早就注意到了里面的鯨魚音效,如下圖,就是一個(gè)環(huán)形的跟著音樂(lè)節(jié)拍跳動(dòng)的特效。

一直覺(jué)得網(wǎng)易云音樂(lè)的用戶體驗(yàn)是很不錯(cuò)的,很早就注意到了里面的鯨魚音效,如下圖,就是一個(gè)環(huán)形的跟著音樂(lè)節(jié)拍跳動(dòng)的特效。

gif動(dòng)圖可能效果不太理想,可以直接在手機(jī)上體驗(yàn)

身為前端憑著本能的好奇心和探索心當(dāng)然會(huì)研究一番,如何在頁(yè)面上實(shí)現(xiàn)該效果?

1.AudioContext

其實(shí)這類動(dòng)效原理并不復(fù)雜,你需要一堆數(shù)據(jù)來(lái)表述每一塊的高度,然后通過(guò)某種方式,讓前臺(tái)渲染可見(jiàn)即可。

如何獲取音樂(lè)實(shí)時(shí)的節(jié)拍數(shù)據(jù)呢,這里用到了AudioContext

AudioContext接口表示由音頻模塊連接而成的音頻處理圖,每個(gè)模塊對(duì)應(yīng)一個(gè)AudioNode。AudioContext可以控制它所包含的節(jié)點(diǎn)的創(chuàng)建,以及音頻處理、解碼操作的執(zhí)行。做任何事情之前都要先創(chuàng)建AudioContext對(duì)象,因?yàn)橐磺卸及l(fā)生在這個(gè)環(huán)境之中。

這一段是從https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext摘錄下來(lái)的,里面有很多方法,詳細(xì)可以看具體文檔,這里只介紹我們下面用到的其中幾個(gè)

1.1 AudioContext.createAnalyser()

AudioContextcreateAnalyser()方法能創(chuàng)建一個(gè)AnalyserNode,可以用來(lái)獲取音頻時(shí)間和頻率數(shù)據(jù),以及實(shí)現(xiàn)數(shù)據(jù)可視化。

var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();

這里返回的是一個(gè)AnalyserNode對(duì)象。

AnalyserNode 賦予了節(jié)點(diǎn)可以提供實(shí)時(shí)頻率及時(shí)間域分析的信息。它使一個(gè) AudioNode 通過(guò)音頻流不做修改的從輸入到輸出, 但允許你獲取生成的數(shù)據(jù), 處理它并創(chuàng)建音頻可視化。

AnalyserNode還有很多屬性

AnalyserNode.fftSize

AnalyserNode 接口的 fftSize 屬性的值是一個(gè)無(wú)符號(hào)長(zhǎng)整型的值, 表示(信號(hào))樣本的窗口大小。當(dāng)執(zhí)行快速傅里葉變換(Fast Fourier Transfor (FFT))時(shí),這些(信號(hào))樣本被用來(lái)獲取頻域數(shù)據(jù)。

fftSize 屬性的值必須是從32到32768范圍內(nèi)的2的非零冪; 其默認(rèn)值為2048。

AnalyserNode.frequencyBinCount 只讀

frequencyBinCount 的值固定為 AnalyserNode 接口中fftSize值的一半. 該屬性通常用于可視化的數(shù)據(jù)值的數(shù)量.

1.2 AudioContext.createMediaElementSource()

AudioContextcreateMediaElementSource() 方法用于創(chuàng)建一個(gè)新的 MediaElementAudioSourceNode 對(duì)象,輸入某個(gè)存在的 HTML or 元素, 對(duì)應(yīng)的音頻即可被播放或者修改。

var audioCtx = new AudioContext();
var source = audioCtx.createMediaStreamSource(stream);
2.實(shí)現(xiàn)

上面很多api可能剛開始看的時(shí)候會(huì)犯暈,不過(guò)沒(méi)事,下面一步一步寫成一個(gè)例子就明白了。

這里我們采用canvas來(lái)繪制頻譜圖,下面簡(jiǎn)單寫一個(gè)布局


加點(diǎn)樣式

body{
  background: black;
}
canvas,audio{
  display: block;
  margin: 0 auto;
}

下面來(lái)通過(guò)音頻來(lái)獲取頻譜數(shù)據(jù)

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)

打印一下這個(gè)array,是一個(gè)長(zhǎng)度為256的數(shù)組

這就是音頻的頻譜數(shù)據(jù),這個(gè)長(zhǎng)度跟上面設(shè)置的analyser.fftSize有關(guān),是他的一半,也就是說(shuō),設(shè)置的越大,得到的數(shù)據(jù)越多,分析的也越準(zhǔn)確。這里只是繪制一些條形圖,并不需要默認(rèn)的2048那么大,所以這里設(shè)置了512。

普通的頻譜圖

在此之前,我們先來(lái)實(shí)現(xiàn)一下常見(jiàn)的垂直頻譜圖,只需要用到ctx.fillRect來(lái)繪制一個(gè)個(gè)的方塊就行了

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);//根據(jù)寬度和間距計(jì)算出可以放多少個(gè)方塊

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);//從頻譜數(shù)據(jù)中每隔step均勻取出meterNum個(gè)數(shù)據(jù)
    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

環(huán)形的頻譜圖

如果上面的頻譜圖很清楚了的話,下面的環(huán)形也輕而易舉了,主要用到了坐標(biāo)的旋轉(zhuǎn)

這里注意的是在進(jìn)行translaterotate操作時(shí)需要進(jìn)行ctx.save()ctx.restore(),因?yàn)椴僮鞯氖亲鴺?biāo)系,而不是元素本身,可以多嘗試一下

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;//環(huán)形半徑
var minHeight = 2;
var meterWidth = 5;
var meterNum = 180;//設(shè)置方塊的數(shù)量,考慮到閉環(huán)的關(guān)系
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

在進(jìn)行旋轉(zhuǎn)操作時(shí),如果你每次旋轉(zhuǎn)以后,都把坐標(biāo)系還原,那么在循環(huán)的時(shí)候需要旋轉(zhuǎn)30,60,90...這樣

ctx.save();
ctx.rotate( 2*PI/meterNum*i );
ctx.restore();

如果你在每次旋轉(zhuǎn)以后,不還原坐標(biāo)系,那么每次就是在上一次的基礎(chǔ)上繼續(xù)旋轉(zhuǎn)

//ctx.save();
ctx.rotate( 2*PI/meterNum );//不需要乘i
//ctx.restore();

很顯然,下面的方式更精簡(jiǎn)

完整代碼可以查看demo

小節(jié)

以上就實(shí)現(xiàn)了環(huán)形的頻譜圖,是不是越來(lái)越靠近網(wǎng)易云音樂(lè)的鯨魚音效了呢,中間加一個(gè)自動(dòng)旋轉(zhuǎn)的專輯封面就可以了~

之前寫過(guò)幾篇都是關(guān)于css的文章,有人可能覺(jué)得是不是不會(huì)js啊,天天搗鼓css,其實(shí)并不是這樣的,各自有各自的職責(zé)范圍,像界面UI之類的,本來(lái)就是樣式上的事情,很多人一看看上去覺(jué)得css實(shí)現(xiàn)不了,馬上就搬出js,效果是出來(lái)了,但體驗(yàn)差了一大截。

如果喜歡的文章的話,可以點(diǎn)贊并收藏,多多關(guān)注我的博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108799.html

相關(guān)文章

  • WebVR教程——Web Audio開發(fā)3D音效

    摘要:輸入結(jié)點(diǎn)主要負(fù)責(zé)加載解碼音頻源,比如獲取二進(jìn)制音頻源的獲取音頻源的等處理結(jié)點(diǎn)主要對(duì)音頻數(shù)據(jù)進(jìn)行計(jì)算處理,比如處理音頻振幅的等輸出結(jié)點(diǎn)則將音頻輸出至揚(yáng)聲器或耳機(jī),便是默認(rèn)的輸出節(jié)點(diǎn)。 showImg(https://segmentfault.com/img/remote/1460000012753856); 在VR開發(fā)中,除了圖形視覺(jué)渲染,音頻處理是重要的一環(huán),好的音頻處理可以欺騙用戶的...

    youkede 評(píng)論0 收藏0
  • 努力翻譯一篇中文最友好,Web Audio API使用相關(guān)文章

    摘要:前言本文翻譯自上的利用,這是中的的一個(gè)入門教程。原文是英文,但有日本同志翻譯的日文版。這是為了提供一個(gè)基本的低音増幅效果在這個(gè)例子中可以設(shè)定過(guò)濾器的種類,周波數(shù),甚至的值。如果是過(guò)濾器的話,可以提供一個(gè)比指定周波數(shù)低的低音増幅。 前言 本文翻譯自MDN上的《Web Audio APIの利用》,這是HTML5中的Web Audio API的一個(gè)入門教程。原文是英文,但有日本同志翻譯的日文...

    caikeal 評(píng)論0 收藏0
  • 那些 audio api事 (一) AudioContext

    摘要:高動(dòng)態(tài)范圍,采用進(jìn)行內(nèi)部處理。這最大限度地減少體積驟降音頻區(qū)域之間,從而導(dǎo)致更均勻的交叉衰減,可能是在電平略有不同區(qū)域之間。低通濾波器保持較低的頻率范圍,但丟棄高頻。 引用 Getting Started with Web Audio APIhttp://www.html5rocks.com/en/tutorials/webaudio/intro/ Introduction Audio...

    沈儉 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

cod7ce

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<