前端纯手工绘制音频波形图

前言

音频波形图是音频文件的可视化展示,需要解析音频数据,然后绘制为图形;而在现代浏览器中,已经具备了这两种能力。

本文将介绍了使用js原生接口,不借助第三方库,实现音频文件的波形绘制。通过使用<canvas>元素和Web Audio API,我们将音频数据以矩形波形的形式展示在画布上。

示例地址,可以体验一下:fabricjs-demo.videocovert.online/#/AudioWave

总体思路

用户选择音频文件后,代码将解析音频数据,并在画布上以矩形条的形式显示音频波形。每个矩形条表示音频的一个采样点,通过不同的高度来反映音频信号的振幅。

完整代码实现:

js 复制代码
<template>
  <div>
    <input type="file" @change="handleFileUpload" accept="audio/*" />
    <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const canvas = ref(null);
const canvasWidth = 800;  // 画布宽度
const canvasHeight = 200; // 画布高度

let audioContext;
let dataArray;

const handleFileUpload = (event) => {
  const file = event.target.files[0];
  if (file) {
    audioContext = new (window.AudioContext || window.webkitAudioContext)();
    const reader = new FileReader();

    reader.onload = function(e) {
      audioContext.decodeAudioData(e.target.result, buffer => {
        dataArray = buffer.getChannelData(0); // 获取左声道数据
        drawRectWaveform();
      });
    };

    reader.readAsArrayBuffer(file);
  }
};

const drawRectWaveform = () => {
  const canvasContext = canvas.value.getContext('2d');

  canvasContext.clearRect(0, 0, canvasWidth, canvasHeight);

  const barWidth = 2;    // 每个矩形的宽度
  const gap = 1;         // 每个矩形之间的间隔
  const step = Math.ceil(dataArray.length / (canvasWidth / (barWidth + gap))); // 采样步长
  let x = 0;

  for (let i = 0; i < dataArray.length; i += step) {
    const v = dataArray[i] * 0.5; // 适当缩放波形高度
    const y = (canvasHeight / 2) + (v * canvasHeight / 2);
    const height = Math.abs(v * canvasHeight); // 矩形高度
    
    canvasContext.fillStyle = 'rgb(0, 0, 255)';
    canvasContext.fillRect(x, canvasHeight / 2 - height / 2, barWidth, height);
    
    x += barWidth + gap;
  }
};
</script>

<style scoped>
canvas {
  border: 1px solid #ccc;
  margin-top: 10px;
}
</style>

处理文件上传并解析音频

javascript 复制代码
const handleFileUpload = (event) => {
  const file = event.target.files[0];
  if (file) {
    audioContext = new (window.AudioContext || window.webkitAudioContext)();
    const reader = new FileReader();

    reader.onload = function(e) {
      audioContext.decodeAudioData(e.target.result, buffer => {
        dataArray = buffer.getChannelData(0); // 获取左声道数据
        drawRectWaveform();
      });
    };

    reader.readAsArrayBuffer(file);
  }
};

handleFileUpload函数在用户选择音频文件时触发。首先,它通过FileReader读取文件,并将其解码为音频数据。decodeAudioData方法将音频数据转换为音频缓冲区对象,并获取左声道数据(getChannelData(0)),存储在dataArray中。最后,调用drawRectWaveform函数绘制波形图。

AudioContext对象

AudioContext是Web Audio API的核心接口,用于管理和处理音频内容。在这个语句中,我们创建了一个新的AudioContext实例,它为后续的音频解码和处理提供了基础。

由于不同浏览器对Web Audio API的支持情况可能有所不同,代码中使用了AudioContextwebkitAudioContext的兼容性写法,以确保在更多的浏览器中正常工作。

decodeAudioData方法

decodeAudioDataAudioContext提供的一个异步方法,用于将ArrayBuffer格式的音频文件解码为AudioBuffer对象。这个解码过程将音频文件解析为包含音频数据的对象,供后续的音频处理使用。

javascript 复制代码
audioContext.decodeAudioData(e.target.result, buffer => {

上面的代码中,e.target.result包含了音频文件的ArrayBuffer数据。decodeAudioData方法将其解码为AudioBuffer对象,并在解码成功后调用回调函数。

绘制波形图

ini 复制代码
javascript
复制代码
const drawRectWaveform = () => {
  const canvasContext = canvas.value.getContext('2d');

  canvasContext.clearRect(0, 0, canvasWidth, canvasHeight);

  const barWidth = 2;    // 每个矩形的宽度
  const gap = 1;         // 每个矩形之间的间隔
  const step = Math.ceil(dataArray.length / (canvasWidth / (barWidth + gap))); // 采样步长
  let x = 0;

  for (let i = 0; i < dataArray.length; i += step) {
    const v = dataArray[i] * 0.5; // 适当缩放波形高度
    const y = (canvasHeight / 2) + (v * canvasHeight / 2);
    const height = Math.abs(v * canvasHeight); // 矩形高度
    
    canvasContext.fillStyle = 'rgb(0, 0, 0)';
    canvasContext.fillRect(x, canvasHeight / 2 - height / 2, barWidth, height);
    
    x += barWidth + gap;
  }
};

drawRectWaveform函数负责在Canvas上绘制波形。首先,它清空画布,然后计算绘制波形的步长(step),确保在画布宽度内均匀分布波形数据。接着,在每个步长处绘制一个矩形,矩形的高度表示音频信号的振幅。canvasContext.fillRect用于在指定位置绘制矩形。

相关库推荐

wavesurfer.js

GitHub项目地址: github.com/katspaugh/w...

功能强大的音频波形图库,支持多种音频格式,并且可以通过插件进行扩展。wavesurfer.js可以创建交互式的波形图,并且提供了丰富的API和事件,方便开发者进行音频操作和界面自定义。

总结

在具体的开发时,成熟的音频波形图组件库和自己实现波形图,可以根据需求做选择。

如果我们的需求比较简单,我们可以自己实现,避免引入组件库中无关的功能,导致项目体积过大;或者我们的需求比较特殊、比较定制化,我们也可以自己实现。

但是如果需求比较复杂,并且组件库能够满足,那还是选择组件库,不需要重复造轮子,在工作中,时间就是金钱!

相关推荐
我要洋人死5 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人17 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人17 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR23 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香25 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969328 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai33 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_91542 分钟前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#