Vue3 实现麦克风实时音量检测

1 前言

本文基于 Vue3 + TypeScript 实现实时音量检测,其他语言可修改相应写法
在这里插入图片描述

2 功能实现

2.1 新建 vumeter.js

在 public/static 目录下新建 vumeter.js

const SMOOTHING_FACTOR = 0.8;
registerProcessor(
  'vumeter',
  class extends AudioWorkletProcessor {
    _volume;
    _updateIntervalInMS;
    _nextUpdateFrame;
    _currentTime;

    constructor() {
      super();
      this._volume = 0;
      this._updateIntervalInMS = 25;
      this._nextUpdateFrame = this._updateIntervalInMS;
      this._currentTime = 0;
      this.port.onmessage = (event) => {
        if (event.data.updateIntervalInMS) {
          this._updateIntervalInMS = event.data.updateIntervalInMS;
        }
      };
    }

    get intervalInFrames() {
      return (this._updateIntervalInMS / 1000) * sampleRate;
    }

    process(inputs) {
      const input = inputs[0];
      if (input.length > 0) {
        const samples = input[0];
        let sum = 0;
        let rms = 0;
        for (let i = 0; i < samples.length; i += 1) {
          sum += samples[i] * samples[i];
        }
        rms = Math.sqrt(sum / samples.length);
        this._volume = Math.max(rms, this._volume * SMOOTHING_FACTOR);
        this._nextUpdateFrame -= samples.length;
        if (0 > this._nextUpdateFrame) {
          this._nextUpdateFrame += this.intervalInFrames;
          if (!this._currentTime || 0.125 < currentTime - this._currentTime) {
            this._currentTime = currentTime;
            this.port.postMessage({ volume: this._volume });
          }
        }
      }

      return true;
    }
  },
);

2.2 新建 useVolume.ts

在 src/hooks 目录下新建 vumeter.js

const volume = ref(0)
let audioContext: AudioContext
let node: AudioWorkletNode
let stream: MediaStream | null = null
let source: MediaStreamAudioSourceNode | null = null

const getStaticPath = (path: string) => `${import.meta.env.VITE_PUBLIC_PATH}static/${path}`

const init = async () => {
  audioContext = new AudioContext()
  await audioContext.audioWorklet.addModule(getStaticPath('vumeter.js'))
  node = new AudioWorkletNode(audioContext, 'vumeter')
  node.port.onmessage = (event) => {
    if (event.data.volume) {
      volume.value = Math.round(event.data.volume * 200)
    }
  }
}

const disconnectAudioContext = () => {
  stream?.getTracks().forEach((track) => track.stop()) // 取消麦克风占用
  source?.disconnect() // 取消 onmessage 监听
  stream = null
  source = null
  volume.value = 0
}

const connectAudioContext = async () => {
  if (!audioContext) await init()
  navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(async (mediaStream) => {
    stream = mediaStream
    source = audioContext.createMediaStreamSource(stream)
    source.connect(node)
  })
}

export default function () {
  return {
    volume,
    connectAudioContext,
    disconnectAudioContext
  }
}

2.3 新增音量检测展示容器

<template>
  <div class="volume">
    <div>当前麦克风</div>
    <div>输入音量大小如下</div>
    <el-icon><i-ep-Microphone /></el-icon>
    <span
      v-for="i in 20"
      :key="i"
      class="volume-span"
      :style="`${Math.ceil(volume / 5) >= i ? 'background: #2559e5' : ''}`"
    ></span>
  </div>
</template>

<script setup lang="ts">
import useVolume from '@/hooks/useVolume'
const { volume, connectAudioContext, disconnectAudioContext } = useVolume()

// 开始音量检测
connectAudioContext()

// 暂停音量检测
// disconnectAudioContext()
</script>

<style lang="scss" scoped>
.volume {
  border-top: 1px solid #dcdfe6;
  border-bottom: 1px solid #dcdfe6;
  padding: 16px 0;
  text-align: center;
  font-size: 12px;
  :nth-child(2) {
    margin-bottom: 6px;
  }
  div {
    color: #909399;
  }
  .volume-span {
    display: inline-block;
    margin-left: 1px;
    width: 3px;
    height: 8px;
    background: #c6e2ff;
  }
}
</style>
### CNN卷积核的空间不变性 卷积神经网络(CNN)中的卷积操作具备空间不变性的特性,这意味着无论特征出现在输入数据的哪个位置,只要该模式存在,模型都能识别出来[^1]。具体来说,在卷积过程中使用的滤波器(即卷积核)在整个图像上滑动并执行相同的操作,这使得同一组权重能够检测到不同位置上的相似图案或边缘。 这种机制允许CNN自动学习如何捕捉平移不变性——即使目标物体在图片的不同区域移动,仍然能被正确分类。例如,如果一张照片里有一只猫位于画面左侧还是右侧并不影响最终判断其为“猫”。因此,通过共享权值的方式实现了高效而强大的表示能力。 ### 卷积核的冗余性及其影响 关于卷积核中存在的潜在冗余现象,研究表明并非所有的通道都对特定任务有用;某些过滤器可能携带重复的信息或者贡献较小。当多个卷积核捕获几乎相同的视觉模式时就会形成所谓的“冗余”。 一方面,过多不必要的参数不仅增加了计算成本还可能导致过拟合问题的发生。另一方面,适当减少这些无意义连接有助于简化架构设计、加速训练过程以及提高泛化性能。为了应对这种情况,研究者们提出了诸如剪枝(pruning)[^2]等技术来消除不重要的连接从而构建更紧凑有效的模型。 ```python import torch.nn as nn class PrunedCNN(nn.Module): def __init__(self, num_classes=10): super(PrunedCNN, self).__init__() # 假设这里已经应用了一些方法去除了部分冗余卷积核 self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3) def forward(self, x): x = F.relu(self.conv1(x)) return x ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值