自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web Audio API 太強(qiáng)了,讓我們一起領(lǐng)略音頻之美

開發(fā) 架構(gòu)
Web Audio API 提供了一個(gè)非常高效和通用的系統(tǒng)來控制 Web 上的音頻,允許開發(fā)人員為音頻添加特殊效果、可視化音頻、添加空間效果等等。Web Audio API 讓用戶能夠在音頻上下文(AudioContext)中進(jìn)行音頻操作,具有模塊化路由的特點(diǎn)?;镜囊纛l操作是在音頻節(jié)點(diǎn)上執(zhí)行的,這些節(jié)點(diǎn)連接在一起形成一個(gè)音頻路由圖。

?在瀏覽器中,我們通常使用 audio 標(biāo)簽來播放音頻:

<audio controls>
<source src="myAudio.mp3" type="audio/mpeg">
<source src="myAudio.ogg" type="audio/ogg">
</audio>

雖然 audio? 標(biāo)簽使用起來很簡單,但也存在一些局限。比如它只控制音頻的播放、暫停、音量等。如果我們想進(jìn)一步控制音頻,比如通道合并和拆分、混響、音高和音頻幅度壓縮等。那么僅僅使用 audio 標(biāo)簽是做不到的。為了解決這個(gè)問題,我們需要使用 Web Audio API。

Web Audio API 提供了一個(gè)非常高效和通用的系統(tǒng)來控制 Web 上的音頻,允許開發(fā)人員為音頻添加特殊效果、可視化音頻、添加空間效果等等。Web Audio API 讓用戶能夠在音頻上下文(AudioContext)中進(jìn)行音頻操作,具有模塊化路由的特點(diǎn)?;镜囊纛l操作是在音頻節(jié)點(diǎn)上執(zhí)行的,這些節(jié)點(diǎn)連接在一起形成一個(gè)音頻路由圖。

接下來,我將演示如何利用 AudioContext 對象來播放音頻:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Context</title>
</head>
<body>
<input id="audioFile" type="file" accept="audio/*"/>
<script>
const inputFile = document.querySelector("#audioFile");
inputFile.onchange = function(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = evt {
const encodedBuffer = evt.currentTarget.result;
const context = new AudioContext();
context.decodeAudioData(encodedBuffer, decodedBuffer => {
const dataSource = context.createBufferSource();
dataSource.buffer = decodedBuffer;
dataSource.connect(context.destination);
dataSource.start();
})
}
}
</script>
</body>
</html>

在以上代碼中,我們使用 FileReader? API 來讀取音頻文件的數(shù)據(jù)。然后創(chuàng)建一個(gè) AudioContext? 對象并使用該對象上的 decodeAudioData? 方法解碼音頻。獲取到解碼后的數(shù)據(jù)后,我們會(huì)繼續(xù)創(chuàng)建一個(gè) AudioBufferSourceNode? 對象來存儲(chǔ)解碼后的音頻數(shù)據(jù),然后將 AudioBufferSourceNode? 對象與 context.destination? 對象連接起來,最后調(diào)用 start 方法播放音頻。

看到這里,是不是覺得使用 AudioContext? 播放音頻文件很麻煩?實(shí)際上它非常強(qiáng)大。下面我將介紹如何使用 AudioContext、AnalyserNode、Canvas 來實(shí)現(xiàn)音頻可視化的功能。

可視化音頻文件主要分為以下 3 個(gè)步驟:

  • 獲取音頻文件數(shù)據(jù);
  • 獲取音頻文件頻率數(shù)據(jù);
  • 使用 Canvas API 實(shí)現(xiàn)數(shù)據(jù)可視化。

1、獲取音頻文件數(shù)據(jù)

在以下的代碼中,我們使用 FileReader? API 來讀取音頻文件的數(shù)據(jù)。然后創(chuàng)建一個(gè) AudioContext? 對象并使用該對象上的 decodeAudioData 方法解碼音頻。當(dāng)然,你也可以從網(wǎng)絡(luò)上下載音頻文件。

inputFile.onchange = function(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = evt=>{
const encodedBuffer = evt.currentTarget.result;
const context = new AudioContext();
context.decodeAudioData(encodedBuffer, decodedBuffer=>{
const dataSource = context.createBufferSource();
dataSource.buffer = decodedBuffer;
analyser = createAnalyser(context, dataSource);
bufferLength = analyser.frequencyBinCount;
frequencyData = new Uint8Array(bufferLength);
dataSource.start();
drawBar();
}
)
}

2、獲取音頻文件頻率數(shù)據(jù)

要獲取頻率數(shù)據(jù),我們需要利用 AnalyserNode 接口,該接口提供實(shí)時(shí)頻率和時(shí)域分析信息。

const analyser = audioCtx.createAnalyser();
analyser.fftSize = 512;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
analyser.getByteFrequencyData(dataArray);

AnalyserNode 對象上的 getByteFrequencyData()? 方法會(huì)將當(dāng)前頻率數(shù)據(jù)復(fù)制到傳入的 Uint8Array 對象。

3、使用 Canvas API 實(shí)現(xiàn)數(shù)據(jù)可視化

獲取頻率數(shù)據(jù)后,我們就可以使用 Canvas API 實(shí)現(xiàn)數(shù)據(jù)可視化,比如使用 CanvasRenderingContext2D 接口中的 fillRect 方法,對數(shù)據(jù)進(jìn)行可視化。

function drawBar() {
requestAnimationFrame(drawBar);
analyser.getByteFrequencyData(frequencyData);
canvasContext.clearRect(0, 0, canvasWidth, canvasHeight);
let barHeight, barWidth, r, g, b;
for (let i = 0, x = 0; i < bufferLength; i++) {
barHeight = frequencyData[i];
barWidth = canvasWidth / bufferLength * 2;
r = barHeight + 25 * (i / bufferLength);
g = 250 * (i / bufferLength);
b = 50;
canvasContext.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
canvasContext.fillRect(x, canvasHeight - barHeight, barWidth, barHeight);
x += barWidth + 2;
}
}

分析完上面的處理流程,我們來看一下完整的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Visualizations with Web Audio API</title>
</head>
<body>
<input id="audioFile" type="file" accept="audio/*"/>
<canvas id="canvas"></canvas>
<script>
const canvas = document.querySelector("#canvas");
const inputFile = document.querySelector("#audioFile");

const canvasWidth = window.innerWidth;
const canvasHeight = window.innerHeight;
const canvasContext = canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
let frequencyData = [], bufferLength = 0, analyser;

inputFile.onchange = function(event) {
const file = event.target.files[0];

const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = evt=>{
const encodedBuffer = evt.currentTarget.result;
const context = new AudioContext();
context.decodeAudioData(encodedBuffer, decodedBuffer=>{
const dataSource = context.createBufferSource();
dataSource.buffer = decodedBuffer;
analyser = createAnalyser(context, dataSource);
bufferLength = analyser.frequencyBinCount;
frequencyData = new Uint8Array(bufferLength);
dataSource.start();
drawBar();
}
)
}

function createAnalyser(context, dataSource) {
const analyser = context.createAnalyser();
analyser.fftSize = 512;
dataSource.connect(analyser);
analyser.connect(context.destination);
return analyser;
}

function drawBar() {
requestAnimationFrame(drawBar);
analyser.getByteFrequencyData(frequencyData);
canvasContext.clearRect(0, 0, canvasWidth, canvasHeight);
let barHeight, barWidth, r, g, b;
for (let i = 0, x = 0; i < bufferLength; i++) {
barHeight = frequencyData[i];
barWidth = canvasWidth / bufferLength * 2;
r = barHeight + 25 * (i / bufferLength);
g = 250 * (i / bufferLength);
b = 50;
canvasContext.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
canvasContext.fillRect(x, canvasHeight - barHeight, barWidth, barHeight);
x += barWidth + 2;
}
}
}
</script>
</body>
</html>

瀏覽器打開包含上述代碼的網(wǎng)頁,然后選擇一個(gè)音頻文件后,你就可以看到類似的圖形。

圖片

事實(shí)上,我們有了頻率數(shù)據(jù)之后,我們還可以使用 Canvas API 繪制其他漂亮的圖形。

圖片

圖片

以上圖形是使用 Github 上的第三方庫 vudio.js 生成的。

https://github.com/alex2wong/vudio.js

責(zé)任編輯:武曉燕 來源: 全棧修仙之路
相關(guān)推薦

2021-12-29 08:27:05

ByteBuffer磁盤服務(wù)器

2021-08-27 07:06:10

IOJava抽象

2022-03-08 17:52:58

TCP格式IP

2022-03-31 18:59:43

數(shù)據(jù)庫InnoDBMySQL

2022-02-14 07:03:31

網(wǎng)站安全MFA

2022-06-26 09:40:55

Django框架服務(wù)

2016-09-06 10:39:30

Dell Techno

2022-02-14 10:16:22

Axios接口HTTP

2021-11-29 07:24:08

ACID事務(wù)大數(shù)據(jù)

2021-07-15 07:23:28

Singlefligh設(shè)計(jì)

2021-11-26 07:00:05

反轉(zhuǎn)整數(shù)數(shù)字

2023-08-14 08:38:26

反射reflect結(jié)構(gòu)體

2012-04-14 20:47:45

Android

2021-12-16 12:01:21

區(qū)塊鏈Libra貨幣

2021-07-31 11:40:55

Openresty開源

2022-07-10 23:15:46

Go語言內(nèi)存

2023-08-02 08:35:54

文件操作數(shù)據(jù)源

2022-08-01 07:57:03

數(shù)組操作內(nèi)存

2021-03-18 00:04:13

C# 類型數(shù)據(jù)

2021-02-23 09:21:29

代碼效率C++
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)