前言
音频波形图是音频文件的可视化展示,需要解析音频数据,然后绘制为图形;而在现代浏览器中,已经具备了这两种能力。
本文将介绍了使用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的支持情况可能有所不同,代码中使用了AudioContext
和webkitAudioContext
的兼容性写法,以确保在更多的浏览器中正常工作。
decodeAudioData
方法
decodeAudioData
是AudioContext
提供的一个异步方法,用于将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和事件,方便开发者进行音频操作和界面自定义。
总结
在具体的开发时,成熟的音频波形图组件库和自己实现波形图,可以根据需求做选择。
如果我们的需求比较简单,我们可以自己实现,避免引入组件库中无关的功能,导致项目体积过大;或者我们的需求比较特殊、比较定制化,我们也可以自己实现。
但是如果需求比较复杂,并且组件库能够满足,那还是选择组件库,不需要重复造轮子,在工作中,时间就是金钱!