小程序音频可视化(canvas+WebAudioContext)

本文详细介绍了如何在微信小程序中使用WebAudioAPI创建音频播放器,结合AnalyserNode进行音频分析,并利用Canvas实时绘制音频频谱图的过程。开发者通过loadAudio和decodeAudioData函数获取音频数据,然后利用setInterval更新Canvas上的图形,实现了音频可视化功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图:

视频:                                                    

小程序音频可视化预览视频

先看整体原理图(虽然丑,但通俗易懂):

1、肝个音频播放器 WebAudioContext
  • 初始化音频播放器:

创建一个音频上下文:

this.audioCtx = wx.createWebAudioContext();

创建音频分析器节点:

this.analyser = this.audioCtx.createAnalyser();

设置快速傅里叶变换大小(在进行音频数据分析的时候 ,每次使用指定大小进行傅里叶变换,这个值决定了频域分析的分辨率和精确度)

this.analyser.fftSize = 512;

创建一个数组,用于存储格式化后得buffer数据(frequencyBinCount:analyser上自带的一个属性,是fftSize的一半)。

this.data.dataArray = new Uint8Array(this.analyser.frequencyBinCount);

将分析器节点连接到喇叭

this.analyser.connect(this.audioCtx.destination);
  • 请求音频的buffer数据

使用wx.request(),将responseType设置为arraybuffer。这里使用wx官方提供的方法。使用方法的时候,直接将音频的url地址传入就可以获得音频的buffer数据。(未格式化)

//获取语音的buffer数据
  loadAudio(url) {
    return new Promise((resolve) => {
      wx.request({
        url,
        responseType: "arraybuffer",
        success: (res) => {
          this.audioCtx.decodeAudioData(
            res.data,
            (buffer) => {
              console.log("返回buffer数据");
              resolve(buffer);
            },
            (err) => {
              console.error("decodeAudioData fail", err);
              reject();
            }
          );
        },
        fail: (res) => {
          console.error("request fail", res);
          reject();
        },
      });
    });
  },
  • 绑定音频源节点

请求到buffer数据后创建音频源节点source,并将其绑定到source 的buffer字段上。并且将音频源节点连接到分析器节点以及添加播放结束监听事件。

getBuffer() {
    this.loadAudio("https://s1.wzznft.com/i/2023/12/07/gwkbz2.mp3").then(
      (buffer) => {
        this.source = this.audioCtx.createBufferSource();
        this.source.connect(this.analyser);
        this.source.buffer = buffer;
          //执行缓存操作
        sourceCache.add(this.source);

        //监听音频播放完成
        this.source.onended = () => {
          sourceCache.delete(this.source);          
        };
      }
    );
  },

  注:getBuffer 这个方法需要在音频播放前被成功调用一次,因为每次播放都需要产生新的source。

音频播放器初始化完成,接下来是加入canvas,但在这之前我们还需要获取到analyser 分析器节点分析后的数据,方便绘图。

2、上 Canvas
  • 获取分析器格式化后的数据

直接:

this.analyser.getByteFrequencyData(this.data.dataArray);

这行代码将从分析器格式化后的数据存储到事先定义好的dataArray数组中。拿到格式化的数据之后,直接化身绘画大佬。

  • 定义绘制canvas的draw方法

获取分析器格式化后的数据

  先xue微肝点绘制代码:

//绘制
  draw() {
    if (!this.cvs) {
      setTimeout(() => {
        this.draw();
      }, 200);
      return;
    }

    const { width, height } = this.cvs;
    this.ctx.clearRect(0, 0, width, height);

    this.analyser.getByteFrequencyData(this.data.dataArray);//从分析器获取格式化后数据存入数组

    const len = this.data.dataArray.length / 2.5;//截取数据长度
    const barWidth = width / len; //柱形条的宽度
    this.ctx.fillStyle = "#efa";//颜色
    //绘制
    for (let i = 0; i < len; i++) {
      const data = this.data.dataArray[i];
      const barHeight = (data / 255) * height;
      const x1 = i * barWidth + width / 2;//x左侧
      const x2 = width / 2 - (i + 1) * barWidth;//x右侧
      const y = height - barHeight;
      this.ctx.fillRect(x1, y, barWidth - 2, barHeight);
      this.ctx.fillRect(x2, y, barWidth - 2, barHeight);
    }
  },

但此时canvas还无法绘制图形,我们需要根据音频的变化实时的绘制。在小程序中需要使用循环定时函数来模拟浏览器API requestAnimationFrame的效果。

上代码:

this.data.voiceTimer = setInterval(() => {
      this.draw();
   }, 16);//时间设置为16 大约60fps

最后加一点控制的按钮:

<view class="controlBox">
    <button class="btn" type="primary" bindtap="play">Play</button>
    <button class="btn" type="warn" bindtap="stop">Stop</button>
    <button class="btn" bindtap="generate">Gen</button>
</view>
play() {
    //
    this.data.voiceTimer = setInterval(() => {
      this.draw();
    }, 16);
    this.source.start();
  },
  generate() {
    this.getBuffer();
  },
  stop() {
    this.source.stop();
  },

然后,点击Gen之后,播放。

代码片段:https://developers.weixin.qq.com/s/6wcwXhmj74Nr

                                                                                                                                    From  limitCG

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我汤大王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值