記錄--關於前端的音頻可視化-Web Audio

来源:https://www.cnblogs.com/smileZAZ/archive/2023/07/22/17573829.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 最近聽音樂的時候,看到各種動效,突然好奇這些音頻數據是如何獲取並展示出來的,於是花了幾天功夫去研究相關的內容,這裡只是給大家一些代碼實例,具體要看懂、看明白,還是建議大家大家結合相關API文檔來閱讀這篇文章。 參考資料地址:Web ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

背景

最近聽音樂的時候,看到各種動效,突然好奇這些音頻數據是如何獲取並展示出來的,於是花了幾天功夫去研究相關的內容,這裡只是給大家一些代碼實例,具體要看懂、看明白,還是建議大家大家結合相關API文檔來閱讀這篇文章。

參考資料地址:Web Audio API - Web API 介面參考 | MDN (mozilla.org)

實現思路

首先畫肯定是用canvas去畫,關於音頻的相關數據(如頻率、波形)如何去獲取,需要去獲取相關audio的DOM 或通過請求處理去拿到相關的音頻數據,然後通過Web Audio API 提供相關的方法來實現。(當然還要考慮要音頻請求跨域的問題,留在最後。)

一個簡單而典型的 web audio 流程如下(取自MDN):

  1. 創建音頻上下文
  2. 在音頻上下文里創建源 — 例如 <audio>, 振蕩器,流
  3. 創建效果節點,例如混響、雙二階濾波器、平移、壓縮
  4. 為音頻選擇一個目的地,例如你的系統揚聲器
  5. 連接源到效果器,對目的地進行效果輸出

實現

一、頻率圖

實現第一種類型,首先我們需要通過fetch或xhr來獲取一個線上音頻的數據,這裡以fetch為例;

 //創建一個音頻上下文、考慮相容性問題
 let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
 //添加一個音頻源節點
 let source = audioCtx.createBufferSource();
//res.arrayBuffer是將數據轉換為arrayBuffer格式
 fetch(url).then((res) => res.arrayBuffer()).then((res) => {
        //decodeAudioData是將arrayBuffer格式數據轉換為audioBuffer
        audioCtx.decodeAudioData(res).then((buffer) => {
          // decodeAudioData解碼完成後,返回一個AudioBuffer對象
          // 繪製音頻波形圖
          draw(buffer);
          // 連接音頻源
          source.buffer = buffer;
          source.connect(audioCtx.destination);
          // 音頻數據處理完畢
        });
      });

 需要明白的是,source.connect(audioCtx.destination)是將音頻源節點鏈接到輸出設備,否則會沒聲音哦。那麼現在有了數據、我們只需要通過canvas將數據畫出來即可。

function draw(buffer) {
  // buffer.numberOfChannels返迴音頻的通道數量,1即為單聲道,2代表雙聲道。這裡我們只取一條通道的數據
  let data = [];
  let originData = buffer.getChannelData(0);
  // 存儲所有的正數據
  let positives = [];
  // 存儲所有的負數據
  let negatives = [];
  // 先每隔50條數據取1條
  for (let i = 0; i < originData.length; i += 50) {
    data.push(originData[i]);
  }
  // 再從data中每10條取一個最大值一個最小值
  for (let j = 0, len = data.length / 10; j < len; j++) {
    let temp = data.slice(j * 10, (j + 1) * 10);
    positives.push(Math.max(...temp));
    negatives.push(Math.min(...temp));
  }
  if (canvas.getContext) {
    let ctx = canvas.getContext("2d");
    canvas.width = positives.length;
    let x = 0;
    let y = 75;
    let offset = 0;
    var grd = ctx.createLinearGradient(0, 0, canvas.width, 0);
    // 為漸變添加顏色,參數1表示漸變開始和結束之間的位置(用0至1的占比表示),參數2位顏色
    grd.addColorStop(0, "yellow");
    grd.addColorStop(0.5, "red");
    grd.addColorStop(1, "blue");
    ctx.fillStyle = grd;
    ctx.beginPath();
    ctx.moveTo(x, y);
    // 橫坐標上方繪製正數據,下方繪製負數據
    // 先從左往右繪製正數據
    // x + 0.5是為瞭解決canvas 1像素線條模糊的問題
    for (let k = 0; k < positives.length; k++) {
      ctx.lineTo(x + k + 0.5, y - 50 * positives[k]);
    }

    // 再從右往左繪製負數據
    for (let l = negatives.length - 1; l >= 0; l--) {
      ctx.lineTo(x + l + 0.5, y + 50 * Math.abs(negatives[l]));
    }
    // 填充圖形
    ctx.fill();
  }
}

[參考文章](Web Audio - 繪製音頻圖譜 - 掘金 (juejin.cn))

二、實時頻率圖

實現第二種類型,獲取實時頻率,用到的API與第一種有區別,但流程一直,都是通過一個音頻源節點通過連接達到效果。只不過在連接的中間加入了一個分析器analyser,在將分析器連接到輸出設備。

    const audio =document.querySelector('audio')
    //解決音頻跨域問題
    audio.crossOrigin ='anonymous'
    const  canvas =document.querySelector('canvas')
    const ctx=canvas.getContext("2d")
        function initCanvas(){
        //初始化canvas
            canvas.width=window.innerWidth*devicePixelRatio
            canvas.height=(window.innerHeight/2)*devicePixelRatio
        }
        initCanvas()
        //將數據提出來
        let dataArray,analyser;
        //播放事件
        audio.onplay=function(){
            //創建一個音頻上下文實例
            const audioCtx=new (window.AudioContext || window.webkitAudioContext)();
            //添加一個音頻源節點
            const source=audioCtx.createMediaElementSource(audio);
            //分析器節點
             analyser=audioCtx.createAnalyser();
            //fft分析器  越大 分析越細
            analyser.fftSize=512
            //創建一個無符號位元組的數組
             dataArray=new Uint8Array( analyser.frequencyBinCount);
            //音頻源節點 鏈接分析器
            source.connect(analyser)
            //分析器鏈接輸出設備
            analyser.connect(audioCtx.destination,)
        }
那麼接下來至於怎麼把數據畫出來,就憑大家的想法了。
            requestAnimationFrame(draw)
            //
            const {width ,height}=canvas;
            ctx.clearRect(0,0,width,height)
            //分析器節點分析出的數據到數組中
            ctx.fillStyle='#78C5F7'
           ctx.lineWidth = 2;
            ctx.beginPath();
            //getByteFrequencyData,分析當前音頻源的數據 裝到dataArray數組中去
            //獲取實時數據
            analyser.getByteFrequencyData(dataArray)
            // console.log(dataArray);
            const len =dataArray.length;
            const barWidth=width/len;
            let x=0;
            for(let i=0;i<len;i++){
                const data=dataArray[i];
                const barHeight=data/255*height;
           
                // ctx.fillRect(x,y,barWidth,height)
                
        let v = dataArray[i] / 128.0;
        let y = v * height/2;

        if(i === 0) {
            ctx.moveTo(x, y);
        } else {
            ctx.lineTo(x, y);
        }

        x += barWidth;
            }
            // ctx.lineTo(canvas.width, canvas.height/2);
            ctx.stroke();
        }
        draw();

關於請求音頻跨域問題解決方案

給獲取的audio DOM添加一條屬性即可

   audio.crossOrigin ='anonymous'

或者直接在 aduio標簽中 加入 crossorigin="anonymous"

總結

雖然現在已經有很多開源的對於音頻相關的庫,但如果真正的想要去瞭解,去學習音頻相關的東西。必須要去深入學習相關的Web Audio API,當然這裡只是用了其中兩種的方法去實現Web Audio去實現可視化,算是一個基礎入門,對於文中的createBufferSourcecreateMediaElementSourcecreateAnalyserAudioContextarrayBufferdecodeAudioData等等相關的API都需要去瞭解,在可視化方面,還有多種多樣的方式去繪製動畫,如WebGL。對音頻的處理也不只是在可視化方面。

本文轉載於:

https://juejin.cn/post/7205381513339322427

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## 一:背景 ### 1. 講故事 在 dump 分析旅程中,經常會遇到很多朋友反饋一類問題,比如: * 方法平時都執行的特別快,但有時候會特別慢,怎麼排查? * 我的方法第一次執行特別慢,能看到慢在哪裡嗎? 相信有朋友肯定說,加些日誌不就好了,大方向肯定是沒問題的,但加日誌的顆粒度會比較粗而且侵 ...
  • **前言** 小編在油管學習.NET知識,刷到一個外國小哥在用一個類似Idea的IDE開發.NET。出於好奇,小編在某谷搜索Idea支持.NET嗎?結果當然不支持,Idea主要是開發Java的IDE。幸好搜索引擎有個圖片搜索功能,於是拿圖片搜索了這個IDE,原來它的名字叫Rider,是Idea同一家 ...
  • # Unity UGUI的VerticalLayoutGroup(垂直佈局)組件的介紹及使用 ## 1. 什麼是VerticalLayoutGroup組件? VerticalLayoutGroup是Unity UGUI中的一種佈局組件,用於在垂直方向上自動排列子對象。它可以根據子對象的大小和佈局設置 ...
  • ## 引言 彙總一下所有的 .NET IL 指令,以及它們的名稱、操作碼值、堆棧轉換行為和描述。 作為反編譯IL代碼時的查詢字典。 ## IL 指令集列表 以下內容來自[微軟官方文檔](https://learn.microsoft.com/en-us/dotnet/api/system.refle ...
  • ### 一、文件、目錄許可權和所有者 簡介:用戶對一個文件或目錄具有訪問許可權,這些訪問許可權決定了誰能訪問,以及如何範圍這些文件和目錄。通過設置許可權可以限制或允許以下三種用戶訪問: - 文件的用戶所有者(屬主) - 文件的組群所有者(用戶所在組的同組用戶) - 系統中的其他用戶 在linux系統中,每一 ...
  • > ## ESP32連接MQ Sensor實現氣味反應 > > > ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/1961512734a74deb9d455b59cb1ccdab.png#pic_center) > > > | [ESP32+MQTT+MySQL實 ...
  • > 在 MySQL 中,GROUP BY用於將具有指定列中相同值的行分組在一起。這是在處理大量數據時非常有用的功能,允許對數據進行分類和聚合。 # 基本使用 ## 語法 以下是GROUP BY子句的基本語法: """ SELECT col1, col2, ..., aggregate_functio ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...