如何将音频文件转绘声波图

787 阅读3分钟

哈喽!这里是苏苏吖~,在捣鼓音频转波形图的时候,在网上找了一堆的资料都不是很如意,所以就自己捣鼓琢磨了一下,可算是捣鼓出来啦,所以回顾一下过程。

🐱 音频转波形图的实现方式有很多种,并不唯一。

原文链接:如何将音频文件转绘声波图 | 苏苏の休憩小屋 (luckysusu.top)

需求分析

简单描述一下就是需要将音频文件实时的转换成音频波形图呈现出来,我这里也没有找到什么很好的库,所以就自己参考着资料实现了一下。

效果的话,还算可以的吧。哈哈。

预览效果如下所示: audio.gif audio_exp.png

实现

下面来看看我的实现代码吧~useAudioVisualizer.js

 class AudioVisualizer {
     constructor(audioUrl, canvas) {
         this.audioUrl = audioUrl;
         this.canvas = canvas;
         this.context = new(window.AudioContext || window.webkitAudioContext)();
         this.bufferSize = 4096; // 缓冲区大小
         this.processor = this.context.createScriptProcessor(this.bufferSize, 1, 1);
         this.init();
     }
 ​
     async init() {
         try {
             const response = await fetch(this.audioUrl);
 ​
             if (!response.ok) {
                 throw new Error(`响应超时: ${response.status}`);
             }
 ​
             const arrayBuffer = await response.arrayBuffer();
             const audioBuffer = await this.context.decodeAudioData(arrayBuffer);
             this.setupProcessor(audioBuffer);
         } catch (error) {
             console.error('音频加载失败:', error);
         }
     }
 ​
     setupProcessor(audioBuffer) {
         const source = this.context.createBufferSource();
         source.buffer = audioBuffer;
 ​
         // 处理每个音频块
         this.processor.onaudioprocess = (e) => {
             this.draw(e.inputBuffer.getChannelData(0));
         };
 ​
         source.connect(this.processor);
         this.processor.connect(this.context.destination);
 ​
         // 启动 AudioContext
         if (this.context.state === 'suspended') {
             this.context.resume();
         }
 ​
         source.start();
     }
 ​
     draw(data) {
         const canvasCtx = this.canvas.getContext('2d');
         const {
             width,
             height
         } = this.canvas;
 ​
         canvasCtx.fillStyle = '#000000';
         canvasCtx.fillRect(0, 0, width, height);
 ​
         canvasCtx.lineWidth = 2;
         canvasCtx.strokeStyle = '#00ff00';
 ​
         canvasCtx.beginPath();
 ​
         const sliceWidth = width * 1.0 / data.length;
         let x = 0;
 ​
         for (let i = 0; i < data.length; i++) {
             const v = data[i] * 0.5 + 0.5; // 确保波形图垂直居中
             const y = v * height;
 ​
             if (i === 0) {
                 canvasCtx.moveTo(x, y);
             } else {
                 canvasCtx.lineTo(x, y);
             }
 ​
             x += sliceWidth;
         }
 ​
         canvasCtx.lineTo(this.canvas.width, this.canvas.height / 2);
         canvasCtx.stroke();
     }
 }
 ​
 export default AudioVisualizer;

0. 构造函数:

*   接收两个参数,`audioUrl` 表示音频文件的 URL,`canvas` 表示用于绘制波形图的 Canvas 元素。
*   创建一个 AudioContext 对象,用于处理音频相关的操作。
*   定义了缓冲区大小 `bufferSize` 和一个 `ScriptProcessorNode` 对象 `processor`,用于处理音频数据。
  1. init 方法:

    • 通过 fetch 获取音频文件。
    • 将获取到的音频文件数据转换成 arrayBuffer
    • 使用 decodeAudioData 方法将 arrayBuffer 转换为音频缓冲区(audioBuffer)。
    • 调用 setupProcessor 方法进行音频处理。
  2. setupProcessor 方法:

    • 创建一个音频源节点 source,将音频缓冲区设置为该节点的缓冲区。
    • 设置 processoronaudioprocess 事件处理器,该处理器在每个音频块处理时调用 draw 方法。
    • 将音频源节点和 processor 连接,并将 processor 连接到音频目的地(context.destination)。
    • 如果 AudioContext 的状态是 'suspended',则通过调用 resume 方法启动 AudioContext
    • 启动音频源节点。
  3. draw 方法:

    • 获取 Canvas 2D 上下文。
    • 用黑色填充整个 Canvas。
    • 设置线条样式,包括线条颜色、宽度等。
    • 遍历音频数据,通过绘制路径形成波形图。

整体流程是:加载音频文件,将其解码成音频缓冲区,通过 ScriptProcessorNode 处理音频数据,将处理后的数据传递给 draw 方法进行绘制,最终呈现为波形图

这样一来就可以实现一个音频转波形图的效果啦~

tips:咳咳,分析是我偷懒喂给chatGPT做哒,有问题的话请留言。skr~


咳咳~好啦,直截了当简单明了!可能存在不足,不过我会不断进步!Fighting!!!觉得有用的话,请慷慨留下您的赞赏吧好不好嘛,行不行嘛,你最好啦,谢谢你啦。我是苏苏,一枚二次元码农🌺。