溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Web?Audi怎么繪制音頻圖譜

發(fā)布時間:2023-03-09 13:45:23 來源:億速云 閱讀:140 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細介紹“Web Audi怎么繪制音頻圖譜”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“Web Audi怎么繪制音頻圖譜”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

實現(xiàn)思路

先介紹下小編的整體思路吧。所謂的音頻圖譜,其實只是將聲音的響度具象化為一個波形圖,響度高對應的波形高,響度低波形也就低。所以第一步,我們可以通過xhr拿到一個音頻文件的數(shù)據(jù)。那么,第二步便是如何處理這組數(shù)據(jù),讓數(shù)據(jù)能夠比較真實的反應音頻的響度。這時候就需要前端的Web Audio Api來發(fā)揮作用了,具體如何處理,我們后面詳細說明。完成數(shù)據(jù)處理之后,最后一步就是需要根據(jù)數(shù)據(jù)繪制出波形圖,這里我們使用canvas來做波形圖的繪制。

獲取音頻文件

首先,我們利用fetch,來獲取一個線上音頻。這里,我們借用一下wavesuffer官網(wǎng)demo中用的線上音頻來做示范。

// 音頻url
let audioUrl = 'https://wavesurfer-js.org/example/media/demo.wav';
// 創(chuàng)建音頻上下文
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// 創(chuàng)建音頻源
let source = audioCtx.createBufferSource();
/* 
 * 通過fetch下載音頻,responseType設(shè)置為'arrayBuffer',我們以arrayBuffer格式接收返回的數(shù)據(jù)
*/
fetch(audioUrl, {
  method: 'GET',
  responseType: 'arraybuffer',
}).then(res => {
  return res.arrayBuffer();
}).then(data => {
  // 處理音頻數(shù)據(jù)
  initAudio(data);
});

利用Web Audio Api 處理音頻數(shù)據(jù)

拿到音頻數(shù)據(jù)之后,我們需要利用Web Audio Api,來處理音頻數(shù)據(jù),實現(xiàn)音頻的播放,暫停等操作以及我們后續(xù)的波形圖繪制。這里簡單介紹下,Web Audio Api是一組非常強大的Api,它提供了在Web中控制音頻、處理音頻的一整套有效通用的系統(tǒng)。它能夠允許開發(fā)著,控制音頻,自選音頻源、對音頻添加特效,使音頻可視化,添加空間效果,添加混響等等。而我們今天要實現(xiàn)的功能,僅僅只用到了其中幾個Api,整體流程如下:

Web?Audi怎么繪制音頻圖譜

// audio 初始化
function initAudio (data) {
  // 音頻數(shù)據(jù)解碼
  // decodeAudioData方法接收一個arrayBuffer數(shù)據(jù)作為參數(shù),這也是為什么前面fetch音頻時設(shè)置以arrayBuffer格式接收數(shù)據(jù)
  audioCtx.decodeAudioData(data).then(buffer => {
    // decodeAudioData解碼完成后,返回一個AudioBuffer對象
    // 繪制音頻波形圖
    drawWave(buffer);
    // 連接音頻源
    source.buffer = buffer;
    source.connect(audioCtx.destination);
    // 音頻數(shù)據(jù)處理完畢
    alert('音頻數(shù)據(jù)處理完畢!');
  });
}
// web audio 規(guī)范不允許音頻自動播放,需要用戶觸發(fā)頁面事件來觸發(fā)播放,這里我們增加一個播放按鈕,數(shù)據(jù)處理完畢后點擊播放
document.querySelector('#btn').onclick = () => {
  // 播放音頻
  source.start(0);
}

通過解碼后的音頻數(shù)據(jù),繪制波形圖

音頻數(shù)據(jù)通過AudioContext解碼后,返回一個AudioBuffer對象,這個對象,保存有音頻的采樣率、聲道、pcm數(shù)據(jù)等信息。通過getChannelData方法可以獲取到音頻某個聲道的pcm數(shù)據(jù)。返回的是一個Float32Array對象,數(shù)值范圍在-1到1之間。音頻數(shù)據(jù)比較龐大,每一秒鐘可能包含成千上萬的數(shù)據(jù),因此我們在做圖形繪制時,需要對數(shù)據(jù)進一步采樣。比如,這里我們采用每1000條數(shù)據(jù)中,取一個最大值(正數(shù))一個最小值(負數(shù))來繪制圖形;

// 繪制波形圖
function drawWave (buffer) {
  // buffer.numberOfChannels返回音頻的通道數(shù)量,1即為單聲道,2代表雙聲道。這里我們只取一條通道的數(shù)據(jù)
  let data = [];
  let originData = buffer.getChannelData(0);
  // 存儲所有的正數(shù)據(jù)
  let positives = [];
  // 存儲所有的負數(shù)據(jù)
  let negatives = [];
  // 先每隔100條數(shù)據(jù)取1條
  for (let i = 0; i < originData.length; i += 100) {
    data.push(originData[i]);
  }
  // 再從data中每10條取一個最大值一個最小值
  for (let j = 0, len = parseInt(data.length / 10); j < len; j++) {
    let temp = data.slice(j * 10, (j + 1) * 10);
    positives.push(Math.max.apply(null, temp));
    negatives.push(Math.min.apply(null, temp));
  }
  // 創(chuàng)建canvas上下文
  let canvas = document.querySelector('#canvas');
  if (canvas.getContext) {
    let ctx = canvas.getContext('2d');
    canvas.width = positives.length;
    let x = 0;
    let y = 100;
    let offset = 0;
    ctx.fillStyle = '#fa541c';
    ctx.beginPath();
    ctx.moveTo(x, y);
    // canvas高度200,橫坐標在canvas中點100px的位置,橫坐標上方繪制正數(shù)據(jù),下方繪制負數(shù)據(jù)
    // 先從左往右繪制正數(shù)據(jù)
    // x + 0.5是為了解決canvas 1像素線條模糊的問題
    for (let k = 0; k < positives.length; k++) {
      ctx.lineTo(x + k + 0.5, y - (100 * positives[k]));
    }
    // 再從右往左繪制負數(shù)據(jù)
    for (let l = negatives.length - 1; l >= 0; l--) {
      ctx.lineTo(x + l + 0.5, y + (100 * Math.abs(negatives[l])));
    }
    // 填充圖形
    ctx.fill();
  }
};

讀到這里,這篇“Web Audi怎么繪制音頻圖譜”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI