日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

傅里叶变换音频可视化_Web Audio在音频可视化中的应用

發布時間:2024/10/14 编程问答 68 豆豆
生活随笔 收集整理的這篇文章主要介紹了 傅里叶变换音频可视化_Web Audio在音频可视化中的应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Web Audio在音頻可視化中的應用

本文有兩個關鍵詞:音頻可視化和Web Audio。前者是實踐,后者是其背后的技術支持。 Web Audio 是很大的知識點,本文會將重點放在如何獲取音頻數據這塊,對于其 API 的更多內容,可以查看 MDN。

另外,要將音頻數據轉換成可視化圖形,除了了解 Web Audio 之外,還需要對 Canvas (特指2D,下同),甚至 WebGL (可選)有一定了解。如果讀者對它們沒有任何學習基礎,可以先從以下資源入手:

什么是音頻可視化通過獲取頻率、波形和其他來自聲源的數據,將其轉換成圖形或圖像在屏幕上顯示出來,再進行交互處理。

云音樂有不少跟音頻動效相關的案例,但其中有些過于復雜,又或者太偏業務。因此這里就現找了兩個相對簡單,但有代表性的例子。

第一個是用 Canvas 實現的音頻柱形圖。

第二個是用 WebGL 實現的粒子效果。

在具體實踐中,除了這些基本圖形(矩形、圓形等)的變換,還可以把音頻和自然運動、3D 圖形結合到一起。

什么是 Web AudioWeb Audio 是 Web 端處理和分析音頻的一套 API 。它可以設置不同的音頻來源(包括節點、 ArrayBuffer 、用戶設備等),對音頻添加音效,生成可視化圖形等。

接下來重點介紹 Web Audio 在可視化中扮演的角色,見下圖。

簡單來說,就是取數據 + 映射數據兩個過程。我們先把“取數據”這個問題解決,可以按以下5步操作。

1. 創建 AudioContext

在音頻的任何操作之前,都必須先創建 AudioContext 。它的作用是關聯音頻輸入,對音頻進行解碼、控制音頻的播放暫停等基礎操作。

創建方式如下:

const AudioContext = window.AudioContext || window.webkitAudioContext;

const ctx = new AudioContext();

2. 創建 AnalyserNode

AnalyserNode 用于獲取音頻的頻率數據( FrequencyData )和時域數據( TimeDomainData )。從而實現音頻的可視化。

它只會對音頻進行讀取,而不會對音頻進行任何改變。

const analyser = ctx.createAnalyser();

analyser.fftSize = 512;

關于 fftSize ,在 MDN 上的介紹可能很難理解,說是快速傅里葉變換的一個參數。

可以從以下角度理解:

1. 它的取值是什么?

fftSize 的要求是 2 的冪次方,比如 256 、 512 等。數字越大,得到的結果越精細。

對于移動端網頁來說,本身音頻的比特率大多是 128Kbps ,沒有必要用太大的頻率數組去存儲本身就不夠精細的源數據。另外,手機屏幕的尺寸比桌面端小,因此最終展示圖形也不需要每個頻率都采到。只需要體現節奏即可,因此 512 是較為合理的值。

2. 它的作用是什么?

fftSize 決定了 frequencyData 的長度,具體為 fftSize 的一半。

至于為什么是 1 / 2,感興趣的可以看下這篇文章:Why is the FFT “mirrored”?

3. 設置 SourceNode

現在,我們需要將音頻節點,關聯到 AudioContext 上,作為整個音頻分析過程的輸入。

在 Web Audio 中,有三種類型的音頻源:MediaElementAudioSourceNode 允許將節點直接作為輸入,可做到流式播放。

AudioBufferSourceNode 通過 xhr 預先將音頻文件加載下來,再用 AudioContext 進行解碼。

MediaStreamAudioSourceNode 可以將用戶的麥克風作為輸入。即通過navigator.getUserMedia獲取用戶的音頻或視頻流后,生成音頻源。

這 3 種音頻源中,除了 MediaStreamAudioSourceNode 有它不可替代的使用場景(比如語音或視頻直播)之外。 MediaElementAudioSourceNode 和 AudioBufferSourceNode 相對更容易混用,因此這里著重介紹一下。

MediaElementAudioSourceNode

MediaElementAudioSourceNode 將標簽作為音頻源。它的 API 調用非常簡單。

// 獲取節點const audio = document.getElementById('audio');

// 通過節點創建音頻源const source = ctx.createMediaElementSource(audio);

// 將音頻源關聯到分析器source.connect(analyser);

// 將分析器關聯到輸出設備(耳機、揚聲器)analyser.connect(ctx.destination);

AudioBufferSourceNode

有一種情況是,在安卓端,測試了在Chrome/69(不含)以下的版本,用 MediaElementAudioSourceNode 時,獲取到的 frequencyData 是全為 0 的數組。

因此,想要兼容這類機器,就需要換一種預加載的方式,即使用 AudioBufferSourceNode ,加載方式如下:

// 創建一個xhrvar xhr = new XMLHttpRequest();

xhr.open('GET', '/path/to/audio.mp3', true);

// 設置響應類型為 arraybufferxhr.responseType = 'arraybuffer';

xhr.onload = function() {

var source = ctx.createBufferSource();

// 對響應內容進行解碼 ctx.decodeAudioData(xhr.response, function(buffer) {

// 將解碼后得到的值賦給buffer source.buffer = buffer;

// 完成。將source綁定到ctx。也可以連接AnalyserNode source.connect(ctx.destination);

});

};

xhr.send();

如果將 AnalyserNode 類比中間件,會不會好理解一些?

可以對比一下常規的播放,和 Web Audio 中的播放流程:

4. 播放音頻

對于節點,即使用 MediaElementAudioSourceNode 的話,播放相對比較熟悉:

audio.play();

但如果是 AudioBufferSourceNode ,它不存在 play 方法,而是:

// 創建AudioBufferSourceNodeconst source = ctx.createBufferSource();

// buffer是通過xhr獲取的音頻文件source.buffer = buffer;

// 調用start方法進行播放source.start(0);

5. 獲取 frequencyData

到此,我們已經將音頻輸入關聯到一個 AnalyserNode ,并且開始播放音頻。對于 Web Audio 這部分來說,它只剩最后一個任務:獲取頻率數據。

關于頻率, Web Audio 提供了兩個相關的 API,分別是:analyser.getByteFrequencyData

analyser.getFloatFrequencyData

兩者都是返回 TypedArray ,唯一的區別是精度不同。

getByteFrequencyData 返回的是 0 - 255 的 Uint8Array 。而 getFloatFrequencyData 返回的是 0 - 22050 的 Float32Array 。

相比較而言,如果項目中對性能的要求高于精度,那建議使用 getByteFrequencyData 。下圖展示了一個具體例子:

關于數組的長度( 256 ),在上文已經解釋過,它是 fftSize 的一半。

現在,我們來看下如何獲取頻率數組:

const bufferLength = analyser.frequencyBinCount;

const dataArray = new Uint8Array(bufferLength);

analyser.getByteFrequencyData(dataArray);

需要注意的是, getByteFrequencyData 是對已有的數組元素進行賦值,而不是創建后返回新的數組。

它的好處是,在代碼中只會有一個 dataArray 的引用,不用通過函數調用和參數傳遞的方式來重新取值。

可視化的兩種實現方案

在了解 Web Audio 之后,已經能用 getByteFrequencyData 取到一個 Uint8Array 的數組,暫時命名為 dataArray 。

從原理上講,可視化所依賴的數據可以是音頻,也可以是溫度變化,甚至可以是隨機數。所以,接下來的內容,我們只需要關心如何將 dataArray 映射為圖形數據,不用再考慮 Web Audio 的操作。

(為了簡化 Canvas 和 WebGL 的描述,下文提到 Canvas 特指 Canvas 2D。)

1. Canvas 方案

Canvas 本身是一個序列幀的播放。它在每一幀中,都要先清空 Canvas ,再重新繪制。

以下是從示例代碼中摘取的一段:

function renderFrame() {

requestAnimationFrame(renderFrame);

// 更新頻率數據 analyser.getByteFrequencyData(dataArray);

// bufferLength表示柱形圖中矩形的個數 for (var i = 0, x = 0; i < bufferLength; i++) {

// 根據頻率映射一個矩形高度 barHeight = dataArray[i];

// 根據每個矩形高度映射一個背景色 var r = barHeight + 25 * (i / bufferLength);

var g = 250 * (i / bufferLength);

var b = 50;

// 繪制一個矩形,并填充背景色 ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";

ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);

x += barWidth + 1;

}

}

renderFrame();

對于可視化來說,核心邏輯在于:如何把頻率數據映射成圖形參數。在上例中,只是簡單地改變了柱形圖中每一個矩形的高度和顏色。

Canvas 提供了豐富的繪制API,僅從 2D 的角度考慮,它也能實現很多酷炫的效果。類比 DOM 來說,如果只是

的組合就能做出豐富多彩的頁面,那么 Canvas 一樣可以。

2. WebGL 方案

Canvas 是 CPU 計算,對于 for 循環計算 10000 次,而且每一幀都要重復計算, CPU 是負載不了的。所以我們很少看到用 Canvas 2D 去實現粒子效果。取而代之的,是使用 WebGL ,借助 GPU 的計算能力。

在 WebGL 中,有一個概念相對比較陌生——著色器。它是運行在 GPU 中負責渲染算法的一類總稱。它使用 GLSL( OpenGL Shading Language )編寫,簡單來說是一種類 C 風格的語言。以下是簡單的示例:

void main()

{

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

關于著色器更詳細的介紹,可以查看這篇文章。

WebGL 的原生 API 是非常復雜的,因此我們使用Three.js作為基礎庫,它會讓業務邏輯的編寫變得簡單。

先來看下整個開發流程中做的事情,如下圖:

在這個過程中, uniforms 的類型是簡單 Object ,我們會將音頻數組作為 uniforms 的一個屬性,傳到著色器中。至于著色器做的事情,可以簡單理解為,它將 uniforms 中定義的一系列屬性,映射為屏幕上的頂點和顏色。

頂點著色器和片元著色器的編寫往往不需要前端開發參與,對于學過 Unity3D 等技術的游戲同學可能會熟悉一些。讀者可以到 ShaderToy 上尋找現成的著色器。

然后介紹以下3個 Three.js 中的類:

1. THREE.Geometry

可以理解為形狀。也就是說,最后展示的物體是球體、還是長方體、還是其他不規則的形狀,是由這個類決定的。

因此,你需要給它傳入一些頂點的坐標。比如三角形,有3個頂點,則傳入3個頂點坐標。

當然, Three.js 內置了很多常用的形狀,比如 BoxGeometry 、 CircleGeometry 等。

2. THREE.ShaderMaterial

可以理解為顏色。還是以三角形為例,一個三角形可以是黑色、白色、漸變色等,這些顏色是由 ShaderMaterial 決定的。

ShaderMaterial 是 Material 的一種,它由頂點著色器和片元著色器進行定義。

3. THREE.Mesh

定義好物體的形狀和顏色后,需要把它們組合在一起,稱作 Mesh (網格)。有了 Mesh 之后,便可以將它添加到畫布中。然后就是常規的 requestAnimationFrame 的流程。

同樣的,我們摘取了示例中比較關鍵的代碼,并做了標注。

i. 創建 Geometry (這是從 THREE.BufferGeometry 繼承的類):

var geometry = ParticleBufferGeometry({

// TODO 一些參數});

ii. 定義 uniforms :

var uniforms = {

dataArray: {

value: null,

type: 't' // 對應THREE.DataTexture },

// TODO 其他屬性};

iii. 創建 ShaderMaterial :

var material = new THREE.ShaderMaterial({

uniforms: uniforms,

vertexShader: '', // TODO 傳入頂點著色器 fragmentShader: '', // TODO 傳入片元著色器 // TODO 其他參數});

iv. 創建 Mesh :

var mesh = new THREE.Mesh(geometry, material);

v. 創建 Three.js 中一些必須的渲染對象,包括場景和攝像頭:

var scene, camera, renderer;

renderer = new THREE.WebGLRenderer({

antialias: true,

alpha: true

});

camera = new THREE.PerspectiveCamera(45, 1, .1, 1e3);

scene = new THREE.Scene();

vi. 常規的渲染邏輯:

function animate() {

requestAnimationFrame(animate);

// TODO 此處可以觸發事件,用于更新頻率數據

renderer.render(scene, camera);

}

小結

本文首先介紹了如何通過 Web Audio 的相關 API 獲取音頻的頻率數據。

然后介紹了 Canvas 和 WebGL 兩種可視化方案,將頻率數據映射為圖形數據的一些常用方式。

另外,云音樂客戶端上線鯨云動效已經有一段時間,看過本文之后,有沒有同學想嘗試實現一個自己的音頻動效呢?

最后附上文中提到的兩段 codepen 示例:本文發布自 網易云音樂前端團隊,文章未經授權禁止任何形式的轉載。我們一直在招人,如果你恰好準備換工作,又恰好喜歡云音樂,那就 加入我們!

總結

以上是生活随笔為你收集整理的傅里叶变换音频可视化_Web Audio在音频可视化中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。