Vue3.0+TSX+TS尝试绘制音乐频谱

import { defineComponent, ref, reactive, onMounted } from 'vue'
import './index.scss'
export default defineComponent({
    name: 'Music',
    setup(props:Props, context) {
        const musicConfig:State = reactive({
            src: '/src/assets/tokyo.mp3'
        })
        const isPlay:Ref<boolean> = ref(true)
        const audioRef:Ref<any> = ref(null)
        const canvasRef:Ref<any> = ref(null)
        class Audio {
            constructor(audio,fftSize) {
                this.audioCtx = new AudioContext()
                this.analyser = this.audioCtx.createAnalyser()
                this.audio = audio
                this.audio.crossOrigin = 'anonymous'
                this.audioSrc = this.audioCtx.createMediaElementSource(this.audio)
                this.analyser.fftSize = fftSize
                this.audioSrc.connect(this.analyser)
                this.analyser.connect(this.audioCtx.destination)
                this.freqArr = new Uint8Array(this.analyser.frequencyBinCount)
            }
        }
        class Canvas {
            constructor(canvas,audio,options={}) {
                this.canvas = canvas
                this.analyser = audio.analyser
                this.freqArr = audio.freqArr
                this.ctx = canvas.getContext('2d')
                //方块的宽度
                this.meterWidth = options.meterWidth || 5
                //方块的间距
                this.gap = options.gap || 2
                //方块最小高度
                this.minHeight = options.minHeight || 2
                this.cwidth = this.canvas.width
                this.cheight = this.canvas.height - 2
                this.capHeight = 0
                //根据宽度和间距计算出可以放多少个方块
                this.meterNum = this.cwidth / (this.meterWidth + this.gap)
            }
            draw() {
                let gradient = this.ctx.createLinearGradient(0, 0, 0, 300)
                gradient.addColorStop(1, '#0f00f0')
                gradient.addColorStop(0.5, '#ff0ff0')
                gradient.addColorStop(0, '#f00f00')
                this.ctx.fillStyle = gradient
            }
            render() {
                const freqArr = new Uint8Array(this.analyser.frequencyBinCount)
                this.analyser.getByteFrequencyData(freqArr)
                //从频谱数据中每隔step均匀取出meterNum个数据.
                const step = Math.round(freqArr.length / this.meterNum)
                this.ctx.clearRect(0, 0, this.cwidth, this.cheight)
                for (var i = 0; i < this.meterNum; i++) {
                    const value = freqArr[i * step]
                    //绘制
                    this.ctx.fillRect(i * (this.meterWidth + this.gap), this.cheight - value + this.capHeight, this.meterWidth, this.cheight || this.minHeight)
                }
                requestAnimationFrame(()=>{
                    this.render()
                })
            }
        }

        onMounted(() => {
            const audio = audioRef.value
            const canvas = canvasRef.value
            //音频获取频谱部分
            const audioExp = new Audio(audio,512)
            const canvasExp = new Canvas(canvas,audioExp)
            canvasExp.draw()
            canvasExp.render()
        })
        return()=>(
            <>
                <canvas id='canvas' ref={canvasRef} width="375" height="300"></canvas>
                <audio id="audio" ref={audioRef} src={musicConfig.src} autoplay controls loop></audio>
            </>
        )
    }
})

  

上一篇:(难题跳过)LeetCode 887.鸡蛋掉落


下一篇:web技术分享| AudioContext 实现音频可视化