ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

吉他初学者学习网站搭建系列(5)——如何做一个在线节拍器

2026/8/2 15:38:19 拓冰建站 浏览量
吉他初学者学习网站搭建系列(5)——如何做一个在线节拍器

文章目录

  • 背景
  • 实现
    • Transport
    • Loop
    • 代码
  • 在线尝试

背景

我们看吉他谱时,经常看到拍号,例如6/8。它的含义是一拍是一个八分音符,一小节有六拍。四分音符的时长是一秒,即60拍/分钟。基于这样的背景知识,我们就可以根据一些定时循环的包来实现节拍器。

实现

这边依然采用的ToneJs。我们需要认识几个类,Transport、Loop。

Transport

Transport是一个计时器类。它有两个属性值得关注:bpm和timeSignature。
bpm表示每分钟的拍子数
timeSignature表示拍号,用数组表示,例如6/8拍表达为[6, 8]。需要注意的是,这个属性最后会返回 6 / 8 * 4 = 3,默认值是4,即标准的4/4拍。

Loop

Loop是一个循环类,用于循环执行一个回调方法,我们可以在这个回调中进行语音播放,实现打节拍的效果。
需要注意的是,如果只是在每一拍都播放一次声音,我们是无法区分重音和弱音的,因此,应该写两个循环,一个专门播放重音的拍子,一个播放所有的拍子。

代码

<template><div><div style="margin: 10px"><v-text-field v-model="bpm" label="bpm"></v-text-field><v-select v-model="timeSignature" label="timeSignature" :items="timeSignatureList"></v-select><v-btn @click="start">{{ isPlaying ? '暂停' : '开始' }}</v-btn></div></div>
</template><script>
import { Oscillator, Transport, Loop } from 'tone';export default {name: 'Beat',data() {return {bpm: 0,timeSignature: '',timeSignatureList: ['2/4', '3/4', '4/4', '3/8', '6/8'],isPlaying: false,}},mounted() {this.bpm = 120;this.timeSignature = '4/4';},watch: {bpm(val) {Transport.bpm.value = val;},},beforeUnmount() {this.stop();},methods: {start() {if (this.isPlaying) {this.stop();} else {const osc1 = new Oscillator().toDestination();const osc2 = new Oscillator().toDestination();const res = this.timeSignature.split('/');Transport.timeSignature = res.map(a => Number(a)); // [6, 8] 返回 6 / 8 * 4 表示 实际拍数和标准拍数的比例// 创建一个每拍触发的事件this.loopA = new Loop((time) => {osc1.start(time).stop(time + 0.1);}, res[1] + "n").start(0);// 重音时间间隔:标准一拍的秒数 *(实际拍数 / 标准拍数) = 实际一拍的秒数this.loopB = new Loop((time) => {osc2.start(time).stop(time + 0.1);}, 60 / this.bpm * Transport.timeSignature).start(0);Transport.start();}this.isPlaying = !this.isPlaying;},stop() {Transport?.stop();this.loopA?.stop();this.loopB?.stop();}}
}
</script>

在线尝试

在这里插入图片描述

这个功能已经集成到了我的个人网站YUERGS中,快来试试吧😉