html
<!--
* @Author: liszter <liszter@qq.com>
* @Date: 2024-07-11 16:06:39
* @LastEditTime: 2024-07-11 18:25:36
* @LastEditors: lishutao
* @Description: 暂无
* @FilePath: \vueee\src\components\record-draw\record-draw-html\index.vue
-->
<template>
<div class="record-page">
<div class="container">
<div v-for="(item, index) of divList" :key="index" :style="{ 'transform': `scaleY(${item})` }" class="div-bar">
</div>
</div>
<div>
<button @click="() => initAudio()">开始录音</button>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
// 默认缩放比例为1
const divList = ref([
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
]);
// 定义全局变量
let audioContext;
let analyser;
let dataArray;
// 数据处理方法
/**
* @descript 描述: 因为频谱可视化给的数据是个大数组,例如 Array[2024], 肯定不能全部展示
* 因此,按照一定的规律取一部分数据。
* @params step 间隔多少个取一次
* @params number 从数组中一共取n个数据
* @params arr 目标数组
* @returns res 获取到的数组结果
* 默认限制最终的音频数据范围 1-10, 这样的话显示的动画比较明显,可配置
* @param { scaleMin } number 限制最小值 ,默认1
* @param { scaleMax } number 限制最大值 ,默认10
* @param { scale } number 最终效果放大倍数 默认1
* **/
function getDataArrayList(arr, number, scaleMin = 1, scaleMax = 10, scale = 4) {
// 最大 arr.length 间隔arr.length/ number 去一个数
// 大概是这个范围,具体为什么是128 我也纳闷。。。
const baseValue = 128
const res = [];
let step = arr.length / number;
for (let i = 0; i < number; i++) {
// 每一项的值 和 baseValue 取差
let currentVal = arr[Math.floor((arr.length / step) * i)] - baseValue
// 处理一下 要求这个值最小是1 ,最大是4
let limit = scaleMin
if (currentVal > scaleMax) {
limit = scaleMax
} else if (currentVal < scaleMax && currentVal > scaleMin) {
limit = currentVal
} else {
limit = scaleMin
}
res.push(limit * scale);
}
return res;
}
// 初始化函数
function initAudio() {
// 获取音频上下文
audioContext = new (window.AudioContext || window.webkitAudioContext)();
// 获取麦克风数据
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(function (stream) {
// 连接音频流到分析器
analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
let source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);
// 获取频谱数据
dataArray = new Uint8Array(analyser.fftSize);
// 开始绘制波形图
draw();
})
.catch(function (err) {
console.log("获取麦克风失败:" + err);
});
}
// 绘制函数
function draw() {
// 获取频谱数据
analyser.getByteTimeDomainData(dataArray);
// 处理数据
let localArr = getDataArrayList(dataArray, 32)
localArr.forEach((item, index) => {
divList.value[index] = item
})
setTimeout(() => {
draw()
}, 16.7 * 5)
}
</script>
<style scoped>
.record-page {
display: flex;
}
.container {
border: solid 1px #e3e3e3;
display: flex;
align-items: center;
padding: 20px;
}
.container>div {
width: 2px;
margin-left: 5px;
background-color: #008cff;
height: 1px;
transition: all 0.16s ease;
}
</style>
实现的效果嘛, 就是你说话期间,这一些柱子会跟着跳动。
逻辑参考代码,大概就这样。 其他波形图也能绘制,你若没想法,来评论区交流。