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>
</>
)
}
})