吉他初学者学习网站搭建系列(3)——如何实现吉他在线调音

news/2024/7/10 2:08:42 标签: 学习, 前端, vue, 实时音视频, 语音识别

文章目录

  • 背景知识
  • teoria
  • pitchy
  • tone
  • 效果

背景知识

学过初中物理就会知道,声音是由空气振动产生的。振动产生波,所以声音就是不同振幅和频率的波构成的。振幅决定了声音的响度,频率决定了声音的音高。想更进一步了解的可以访问这个网页waveforms。

学过一点基础乐理的同学就知道,标准音(A4)的频率是440Hz,也就是说,每一个音其实是由它的频率决定的。在十二平均律中,一个音的八度音(及高八度后的音)的频率是这个音的两倍。而八度音跨了12个半音,所以每个半音平均相差2的1/12次方倍。例如,A4音的频率是440Hz,那么,B4的频率就是4402^(2/12)=493.88Hz(A和B跨两个半音)。以此类推,A5的频率就是4402=880Hz。

我们知道,吉他的六根弦分别是E2、A2、D3、G3、B3和E4。这四个音的音高可以根据上述的公示推到出来。那么当我们知道了吉他空弦的频率,我们就可以根据音频判断吉他的音高是否准确。但是有什么方法可以根据音名得到频率呢?

teoria

teoria是一个轻量级且快速的 JavaScript 音乐理论库,包括爵士乐和古典音乐。它旨在为音乐软件提供直观的编程界面。通过以下方法获取音频

const E2 = teoria.note('E2');
const fq = E2.fq();
// 82.41Hz
const name = E2.toString();
// E2

解决了吉他空弦频率问题,那么,当我们拨弦后,如何根据录音得到其对应的频率呢?

pitchy

我们用到pitchy这个库。这个库可以根据音频计算出频率,采用了Philip McLeod 和Geoff Wyvill在文章A Smarter Way to Find Pitch设计的算法。用法如下

  startRecord() {
      const audioContext = new window.AudioContext();
      const analyserNode = audioContext.createAnalyser();
      navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
        // 得到音频流
        this.audioStream = stream;
        audioContext.createMediaStreamSource(stream).connect(analyserNode);
        const detector = PitchDetector.forFloat32Array(analyserNode.fftSize);
        const input = new Float32Array(detector.inputLength);
        this.updatePitch(analyserNode, detector, input, audioContext.sampleRate);
      });
  },
  updatePitch(analyserNode, detector, input, sampleRate) {
      analyserNode.getFloatTimeDomainData(input);
      // 得到音高频率和清晰度
      const [pitch, clarity] = detector.findPitch(input, sampleRate);
      // ...
      // 每200ms检测一次频率
      setTimeout(()=> this.updatePitch(analyserNode, detector, input, sampleRate), 200);
    },

得到频率后,我们可以设计一个标准判定这个音已经调准了,例如,持续2s频率与标准频率差值小于2Hz。

 updatePitch() {
 	  // ...    
      this.delta = (this.pitch - this.currentNote.fq()).toFixed(2);
      if (Math.abs(this.delta) < 2) {
        if (firstCorrectTimeStamp === 0) {
          firstCorrectTimeStamp = new Date().getTime();
        } else {
          // 进度条
          this.correctProgress = (new Date().getTime() - firstCorrectTimeStamp) / 1000 / 2 * 100;
          // 判定为已调准
          if (this.correctProgress >= 100) {
            this.correctNoteList.push(this.currentNote);
            this.stopRecord();
            return;
          }
        }
      } else {
        firstCorrectTimeStamp = 0;
        this.correctProgress = 0;
      }
      // ....
}

这里我设计了一个时钟样式的进度条,如下图,当2s时长达到,进度100%。
频率
用到了css样式的background的conic-gradient属性,可以自行了解下。
如果想再完善下,我们还可以在点击某个音时,播放这个音的音高。如何实现?

tone

这里我使用了tone这个包。Tone.js 是一个网络音频框架,用于在浏览器中创建交互式音乐。 Tone.js 的架构旨在让创建基于 Web 的音频应用程序的音乐家和音频程序员都熟悉。由于直接使用默认方式的效果并不是吉他,我这边在另一个网站找到了这几个音的mp3音频,作为输入,代码如下

playPitch(note) {
	this.sampler = new Tone.Sampler({
      urls: {
        "e2": "e2.mp3",
        "a2": "a2.mp3",
        "d3": "d3.mp3",
        "g3": "g3.mp3",
        "b3": "b3.mp3",
        "e4": "e4.mp3",
      },
      baseUrl: IP,
    }).toDestination();
	Tone.loaded().then(() => {
		this.sampler.triggerAttackRelease(note.toString(), 1);
	});
},

效果

链接:https://hougiser.gitee.io/music-score/

在这里插入图片描述
欢迎沟通😉~


http://www.niftyadmin.cn/n/5215074.html

相关文章

java stream流常用方法

filter(Predicate predicate)&#xff1a;根据指定条件过滤元素。 List<Integer> numbers Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List<Integer> evenNumbers numbers.stream().filter(n -> n % 2 0).collect(Collectors.toList()); System.out.pr…

【深度学习笔记】04 概率论基础

04 概率论基础 概率论公理联合概率条件概率贝叶斯定理边际化独立性期望和方差模拟投掷骰子的概率随投掷次数增加的变化 概率论公理 概率&#xff08;probability&#xff09;可以被认为是将集合映射到真实值的函数。 在给定的样本空间 S \mathcal{S} S中&#xff0c;事件 A \m…

Nginx 学习笔记

一、Nginx 简介 1. Nginx 是什么? Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 服务器 Nginx 可以作为一个 Web 服务器进行网站的发布,也可以作为反向代理服务器进行负载均衡的实现常见的 Web 服务器:Tomcat、Apache、Nginx、Weblog…

Linux加强篇004-Vim编辑器与Shell命令脚本

目录 前言 1. Vim文本编辑器 1.1 编写简单文档 1.2 配置主机名称 1.3 配置网卡信息 1.4 配置软件仓库 2. 编写Shell脚本 2.1 编写简单的脚本 2.2 接收用户的参数 2.3 判断用户的参数 3. 流程控制语句 3.1 if条件测试语句 3.2 for条件循环语句 3.3 while条件循环语…

Linux学习笔记-芯片性能检测

文章目录 概述Dhrystone&#xff08;单核性能测试工具&#xff09;简介&#xff1a;源码下载&#xff1a;源码编译&#xff1a;使用及输出结果 coremark&#xff08;多核性能测试工具&#xff09;简介&#xff1a;源码下载&#xff1a;源码编译&#xff1a;使用及输出结果&…

Elasticsearch集群部署,配置head监控插件

Elasticsearch是一个开源搜索引擎&#xff0c;基于Lucene搜索库构建&#xff0c;被广泛应用于全文搜索、地理位置搜索、日志处理、商业分析等领域。它采用分布式架构&#xff0c;可以处理大规模数据集和支持高并发访问。Elasticsearch提供了一个简单而强大的API&#xff0c;可以…

笔试编程--打印字符串中的单词

打印出字符串中的单词 输入 Hello, this is a sample sentence. 输出 Hello this is a sample sentence代码实现 #include <stdio.h>// 判断字符是否是字母 int isAlphabet(char ch) {return ((ch > a && ch < z) || (ch > A && ch <…

AR眼镜双目光波导/主板硬件方案

AR(增强现实)技术的发展离不开光学元件&#xff0c;而在其中&#xff0c;光波导和Micro OLED被视为AR眼镜光学方案的黄金搭档。光学元件在AR行业中扮演着核心角色&#xff0c;其成本高昂且直接影响用户体验的亮度、清晰度和大小等因素。AR眼镜的硬件成本中&#xff0c;光机部分…