当前位置: 首页 > news >正文

吉他初学者学习网站搭建系列(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中,快来试试吧😉

相关文章:

  • Android:BackStackRecord
  • error转string
  • uniapp使用vue-i18n国际化多国语言
  • 记录 | CUDA编程中使用#ifdef指令控制生成CPU和GPU代码
  • [足式机器人]Part2 Dr. CAN学习笔记-数学基础Ch0-3线性化Linearization
  • CoreDNS实战(九)-性能压测
  • IDEA连接Redis注意事项
  • Arduino项目式编程教学第三章——红外遥控灯
  • CSS单位vmin、vmax
  • 【JMeter】BeanShell了解基础知识
  • C/C++---------------LeetCode第118. 杨辉三角
  • RT-Thread Studio文件消失不见或被排除构建
  • 【唐山海德教育】职称评审需要什么条件呢?
  • 2-- 简要介绍 Kubernetes
  • 【Python】zip
  • 2017-09-12 前端日报
  • 2018一半小结一波
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • C++11: atomic 头文件
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • JSDuck 与 AngularJS 融合技巧
  • JS笔记四:作用域、变量(函数)提升
  • Laravel Telescope:优雅的应用调试工具
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • XForms - 更强大的Form
  • 多线程事务回滚
  • 事件委托的小应用
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (转)Scala的“=”符号简介
  • .Net CF下精确的计时器
  • .net 反编译_.net反编译的相关问题
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET面试题(二)
  • .NET中的十进制浮点类型,徐汇区网站设计
  • [3D基础]理解计算机3D图形学中的坐标系变换
  • [AHOI2009]中国象棋 DP,递推,组合数
  • [APUE]进程关系(下)
  • [ArcPy百科]第三节: Geometry信息中的空间参考解析
  • [DNS网络] 网页无法打开、显示不全、加载卡顿缓慢 | 解决方案
  • [Docker]三.Docker 部署nginx,以及映射端口,挂载数据卷
  • [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-controller-manager失败
  • [Git 1]基本操作与协同开发
  • [hdu 3652] B-number
  • [HUBUCTF 2022 新生赛]
  • [iOS]随机生成UUID通用唯一识别码
  • [Linux] 常用命令--版本信息/关机重启/目录/文件操作
  • [NOI 2016]优秀的拆分
  • [poj 2001]Shortest Prefixes [Trie]
  • [python]PyPI使用国内源