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

2023-12-13 22:37:32

背景

我们看吉他谱时,经常看到拍号,例如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中,快来试试吧😉

文章来源:https://blog.csdn.net/lyandgh/article/details/134815810
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。