微信小程序实现音乐浪

该文章介绍了如何使用JS的WebAudioAPI在微信小程序中创建一个音乐律动的可视化效果。通过分析音频数据,绘制canvas条形图,实现了随着音乐播放动态变化的图形展示。当音乐停止时,图形会逐渐恢复静止状态。
摘要由CSDN通过智能技术生成

参考原文:JS | Web Audio API (下) 我的音乐浪 - 简书

需求:根据所播放音乐实现律动 

效果:

音乐浪

wxml

<div class="visualize_wrap">
    <canvas type='2d' id="audio_canvas" canvas-id="audio_canvas" style="margin: auto;"></canvas>
</div>

js

  onShow() {
        this.audioCtx = wx.createWebAudioContext()
        this.music = "https://lk-mirror.oss-cn-beijing.aliyuncs.com/f698da27eb4946fd82b3707a0d63a4a5.mp3"
        this.loadMusic(this.music)
    },
// 绘图
    drawAudio(analyser) {
        let dpr = wx.getSystemInfoSync().pixelRatio
        let c_width = this.res[0].width,
            c_height = this.res[0].height,
            canvas = this.res[0].node,
            ctx = canvas.getContext('2d')
        canvas.width = this.res[0].width * dpr
        canvas.height = this.res[0].height * dpr
        ctx.scale(dpr, 0.9)
        // 条形的参数
        let bar_width = 3,
            bar_gap = 2,
            bar_part = bar_width + bar_gap,
            bar_num = Math.round(c_width / bar_part);
        // 线条高度
        let cap_height = 2;
        // 获取的音频数据
        let bufferLength = analyser.frequencyBinCount,
            dataArray = new Uint8Array(bufferLength);
        // 每段包含的频谱宽
        let array_width = Math.round(bufferLength / bar_num);
        // 变量提前,i 表示变量, value表示音频值, isStop表示上方线条的结束
        let i, value, isStop;
        let that = this;
        // 创建数组,线条数组,判断动画结束
        let array = [];
        that.animation_id = null;
        let drawVisual = function () {
            that.analyser.getByteFrequencyData(dataArray);
            if (that.isEnd) {
                isStop = true;
                for (i = dataArray.length - 1; i >= 0; i--) {
                    dataArray[i] = 0;
                }
                // 使其静止时图为空
                for (i = array.length - 1; i >= 0; i--) {
                    isStop = isStop && (array[i] == 0);
                };
                if (isStop) {
                    that.res[0].node.cancelAnimationFrame(that.animation_id);
                    that.playAudio(that.buffer)
                    that.setData({
                        progress: 0
                    })
                    return;
                }
            }
            ctx.clearRect(0, 0, c_width, c_height)
            for (i = 0; i < bar_num; i++) {
                value = dataArray[i * array_width];
                if (array.length < bar_num) {
                    array.push(value)
                }
                if (value < array[i]) {
                    --array[i];
                    ctx.fillRect(i * bar_part, c_height - array[i], bar_width, cap_height);
                } else {
                    ctx.fillRect(i * 12, c_height - value, bar_width, cap_height);
                    array[i] = value;
                };
                ctx.fillStyle = '#f99'; //柱形图颜色
                ctx.fillRect(bar_part * i, c_height - value, bar_width, value);
            }
            that.animation_id = that.res[0].node.requestAnimationFrame(drawVisual);
        }
        that.animation_id = that.res[0].node.requestAnimationFrame(drawVisual);
    },
    playAudio(buffer,start) {
        if (typeof this.source !== 'undefined') {
            this.source.stop(0);
        }
        if (this.animationId !== null) {
            this.res[0].node.cancelAnimationFrame(this.animationId);
        }
        this.analyser = this.audioCtx.createAnalyser();
        this.source = this.audioCtx.createBufferSource();
        this.source.buffer = buffer;
        this.isEnd = false;
        this.source.connect(this.analyser);
        this.analyser.connect(this.audioCtx.destination);
        this.source.start(start ? start : 0);
        let that = this;
        this.source.onended = function () {
            if (!that.isForceStop) {
                that.isEnd = true;
            }
        };
        console.log("this.source",this.source)
        this.drawAudio(this.analyser);
    },
    loadMusic(music) {
        wx.createSelectorQuery().select('#audio_canvas').fields({
            node: true,
            size: true
        }).exec(res => {
            this.res = res
            let audioContext = this.audioCtx
            wx.showLoading({
                title: '加载音频中',
            })
            wx.request({
                url: music,
                responseType: 'arraybuffer',
                success: (res) => {
                    wx.hideLoading({})
                    let audioData = res.data
                    audioContext.decodeAudioData(audioData, (buffer) => {
                        this.playAudio(buffer)
                        this.buffer = buffer
                        this.setData({
                            startPosition: 0,
                            lastPlay: audioContext.currentTime,
                            videoDuration: buffer.duration
                        })
                        
                    }, (err) => {
                        wx.hideLoading({})
                        console.error('decodeAudioData fail', err)
                    })
                },
                fail: (err) => {
                    wx.hideLoading({})
                    console.error('request fail', err)
                }
            })
        })
    },

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值