五线谱调式推导

  很早的时候就听说过各种诸如“X大调”、“X小调”这样的术语,但听了这么多年也没有搞明白这究竟是什么意思。
  直到最近两个月,才有大佬提示,其实各种调式升降记号都是可以由钢琴键位平移的方式得到的,这提供了一种推断调式的方法:在最常规的C大调基础上,每个音都提升一个音程,然后再看有哪些音跑到了黑键上,就可以知道有几个升号或降号了。
  尽管这个过程用手算也是很容易完成的,但考虑到自己在C++公选结课后,已经有两年多的时间没有碰过C++了。为了再次熟练这个比较重要的语言,本次推导过程将使用C++来完成。

基本思路

从C大调出发

  C大调在五线谱中,是没有任何升降号的存在的:

  而如果将键位整体右移两个半音,则可以得到两个升号的调(D大调):

  因为一个八度共有12个半音,所以这样的平移一共可以得到十二种调式。只要对C大调的键位进行12次平移,就可以得到全部的十二种调式。

调式在程序中的表示

  一个八度有12个半音,而在推导过程中需要不断地将这些键往一个方向进行平移,因此考虑到循环移位。使用12个bit分别对应一个八度中的12个半音C、C#|Db、D、D#|Eb、E、F、F#|Gb、G、G#|Ab、A、A#|Bb、B,若键位在那个半音上则置1,否则置0。每一次往高音处移位时,超出B的部分都将会回到C的位置。

  让第0位表示C,第1位表示C#……以此类推,第11位表示B,如果向左移位的话,则第11位被移动至第0位:

  例如,C大调对应的七个键位分别为C、D、E、F、G、A、B,则对应的bit序列为:101010110101。而向高音处平移两个半音到D大调,则对应向左循环移位两次,得到:101011010110,对应C#、D、E、F#、G、A、B。

  有了比较明确的思路后,就可以开始写代码了。

代码实现

初始状态:C大调

  前面已经提到,C大调的bit表示方法,而初始状态又确认为C大调,因此这个数值可以作为常量存放在头文件中:

int MODE = 0xAB5; //101010110101 <- reverse(101011010101)

位与音符的对应关系

  类似于python的字典,C++的标准库也有提供字典这个结构。该结构存放在map库中,include这个库即可用std::map进行使用(这里已经用了using std::map,所以在使用时直接写的map):

map<int, string> NOTE_MAP = {{0, "C",},{1, "C#",},{2, "D",},{3, "D#",},{4, "E",},{5, "F",},{6, "F#",},{7, "G",},{8, "G#",},{9, "A",},{10, "A#",},{11, "B",},{12, "C",},{13, "Db",},{14, "D",},{15, "Eb",},{16, "E",},{17, "F",},{18, "Gb",},{19, "G",},{20, "Ab",},{21, "A",},{22, "Bb",},{23, "B",}};

  在这里给了24个词条,主要是因为有些调式是使用降号的,对于这样的调式,应该使用降号表示法(对应字典的第13-24条)。

循环移位

  循环移位的思路非常简单,就是向左移位一次,然后将最高位移动到第一位。这里没有对第12位及以上的bit进行截断,但也没有影响,因为后续的操作不会涉及到更高位的bit:

/** brief 对调式向左(高音方向)移动一个单位** @param orgMode 原有的调式*/
void shiftMode(int &orgMode){orgMode <<= 1;orgMode = orgMode | !!((1 << 12) & orgMode);
}

打印调式信息

  调式有升号调的和降号调这两种,为了区分开来,在这里使用降号调的flag标记:dFlag,来将它们区分开来。如果有降号表示,则会在字典中查询第13-24项的词条:

/** brief 打印调式的相关信息** @param mode 调式* @param dFlag 降号表示,默认为0,即升号*/
void printModeInfo(int &mode, bool dFlag = false){for (int i = 0; i < 12; i++){int mask = (1 << i);if (mode & mask){std::cout << NOTE_MAP[i+12*dFlag] << "\t";}}std::cout << std::endl;
}

main函数

  对每一次移位的结果,都进行打印即可。由于先前已有经验,升号调和降号调是交替出现的,所以在这里就可以很容易地判断出dFlag的值是true还是false:

int main()
{int mapSize = NOTE_MAP.size();int shift = 0;do{printModeInfo(MODE, (((shift <= 5) && (shift % 2)) || ((shift >= 8) && !(shift % 2))) ? true : false);shiftMode(MODE);shift += 1;}while (shift < 12);return 0;
}

运行结果及结论

  运行后得到如下输出:

C    D   E   F   G   A   B
C   Db  Eb  F   Gb  Ab  Bb
C#  D   E   F#  G   A   B
C   D   Eb  F   G   Ab  Bb
C#  D#  E   F#  G#  A   B
C   D   E   F   G   A   Bb
C#  D#  F   F#  G#  A#  B
C   D   E   F#  G   A   B
C   Db  Eb  F   G   Ab  Bb
C#  D   E   F#  G#  A   B
C   D   Eb  F   G   A   Bb
C#  D#  E   F#  G#  A#  B

  此即推导得到的12种调式,注意到升号和降号的数量是关于C大调对称的,用图像表示则更为直观:

  沿着这个图像顺时针看,调式依次从C大调、降D大调、D大调……演变到B大调,最后再回到C大调。而这些大调,每一个都又有着相对应的小调,由于还没有找出规律,就不在这里描述了。

  而对于C大调向上移动6个半音的调式——升F大调,则暂时难以在输出结果中得以理解。

  而经过在overture和网上的查询,得知升F大调由六个升记号或六个降记号组成:

  并且,E#=F,因为E和F之间只差一个半音。

  由此一来,调式这个问题也就得到了一个比较清晰的解答。

完整代码

main.h

#include <map>
#include <string>using std::map;
using std::string;map<int, string> NOTE_MAP = {{0, "C",},{1, "C#",},{2, "D",},{3, "D#",},{4, "E",},{5, "F",},{6, "F#",},{7, "G",},{8, "G#",},{9, "A",},{10, "A#",},{11, "B",},{12, "C",},{13, "Db",},{14, "D",},{15, "Eb",},{16, "E",},{17, "F",},{18, "Gb",},{19, "G",},{20, "Ab",},{21, "A",},{22, "Bb",},{23, "B",}};int MODE = 0xAB5; //101010110101 <- reverse(101011010101)

main.cpp

#include <iostream>
#include <string>
#include "main.h"using std::map;
using std::string;void shiftMode(int &orgMode);
void printModeInfo(int &mode, bool dFlag);int main()
{int mapSize = NOTE_MAP.size();int shift = 0;do{printModeInfo(MODE, (((shift <= 5) && (shift % 2)) || ((shift >= 8) && !(shift % 2))) ? true : false);shiftMode(MODE);shift += 1;}while (shift < 12);return 0;
}/** brief 对调式向左(高音方向)移动一个单位** @param orgMode 原有的调式*/
void shiftMode(int &orgMode){orgMode <<= 1;orgMode = orgMode | !!((1 << 12) & orgMode);
}/** brief 打印调式的相关信息** @param mode 调式* @param dFlag 降号表示,默认为0,即升号*/
void printModeInfo(int &mode, bool dFlag = false){for (int i = 0; i < 12; i++){int mask = (1 << i);if (mode & mask){std::cout << NOTE_MAP[i+12*dFlag] << "\t";}}std::cout << std::endl;
}

【日常篇】002_五线谱调式推导相关推荐

  1. 适用于程序员的钢琴、五线谱入门教程

    适用于程序员的钢琴教程 全集分为五集: 这是由山东琴律信息科技有限公司制作的'钢琴五线谱入门教程' 全集分为五集: 钢琴(带你认识钢琴,琴键,调式等) 音高(把五线谱中的音高部分单独拿出来讲) 音值( ...

  2. 写给理工科人看的乐理(三)五线谱进阶与和声理论

    写给理工科人看的乐理(三)五线谱进阶与和声理论 关键字:成人学乐理 乐理基础 乐理入门 上一讲我们学习了表示音符相对音高的十二平均律系统和表示绝对音高的五线谱系统,这一讲将对我们已经学到的这些知识做进 ...

  3. 从零开始学五线谱_从零开始学简谱(快速入门)

    目录 第一章 乐音基本常识 第一节 实践中能应用的乐音 第二节 乐音的特性 一.乐音的高低 二.乐音的长短 三.乐音的强弱 四.乐音的音色 音乐小常识(乐音的分音列) 第三节 乐音高低划分的基本单位 ...

  4. 【音乐入门】写给理工科人看的乐理(三)五线谱进阶与和声理论

    关键字:成人学乐理 乐理基础 乐理入门 上一讲我们学习了表示音符相对音高的十二平均律系统和表示绝对音高的五线谱系统,这一讲将对我们已经学到的这些知识做进一步展开,并对和声理论做简单的介绍.和上一讲一样 ...

  5. 从零开始学五线谱_从零开始:学习五线谱和乐理知识.pdf

    目 录 封面 扉页 版权 使用说明 Part 1 音的概况 音 音的产生 音的性质 乐音与噪音 音级 基本音级 变化音级 练一练 弹奏F大调变化音级 练一练 弹奏G大调变化音级 练一练 弹奏D大调变化 ...

  6. 乐理小课堂——自然/和声/旋律小调的调式音阶

    上次我们介绍完了<自然/和声/旋律大调的调式音阶>,这一次我们就继续用Overture这款专业的打谱软件来教大家如何分辨自然/和声/旋律小调的调式音阶. 我们先来看一下自然/旋律/和声小调 ...

  7. Overture乐理调式音阶小课堂

    这一次我们用Overture这款专业的打谱软件来教大家分辨自然/和声/旋律小调的调式音阶. 我们先来看一下自然/旋律/和声小调的音阶在Overture五线谱上的展示 再来了解一下这三个小调的含义 小调 ...

  8. python基础之生成器,生成器函数,列表推导式

    内容梗概: 1. 生成器和生成器函数. 2. 列表推导式. 1.生成器函数1.1 生成器函数. 就是把return换成yield def gen():print("爽歪歪")yie ...

  9. python 列表推导式

    自学python,总结一下,云储存 1,举个普通例子 # 列表推导式置于一对方括号之中[x**2 for x in range(10)] #计算range(10)中每个数的平方,推导出新列表 # 得到 ...

  10. (各种均衡算法在MIMO中的应用对比试验)最小均方误差(MMSE)原理推导以及在MIMO系统中对性能的改善。

    文档和程序地址:下载地址 各种均衡算法在MIMO中的应用对比试验,内附原理推导,对比实验说明和结果等.包括MMSE,ZF,ZF-SIC等.代码附有原理推导小论文.仅供参考

最新文章

  1. python-装饰器实现pv-uv
  2. javadoc: 错误 - 格式错误的语言环境名称_ONLYOFFICE 5.6.0 : 这是一个错误修正版本,改进了德语、法语、意大利语、葡萄牙语和俄语的翻译等...
  3. 命令行切换到conda环境_Anaconda命令行常用操作
  4. noi 2009 二叉查找树 动态规划
  5. app开发第二次总结
  6. C++之类和对象的关系
  7. 微软拒绝修复滥用 MSTSC 的安全绕过缺陷
  8. 细说ASP.NET Cache及其高级用法
  9. Servlet教程第7讲笔记
  10. windows 2000 密钥
  11. 彻底了解DVD:从入门到精通
  12. 西门子博途TIA PORTAL硬件目录中无法找到CPU的固件版本时,如何下载项目数据?
  13. 无需工具qlv转mp4格式最新,下载好的qlv文件怎么转换成mp4?腾讯视频怎么下载mp4格式?怎么把腾讯视频转换成mp4格式?
  14. 从零开始写项目第三篇【在线聊天和个人收藏夹】
  15. Linux学习笔记-随即更新-慢速学习
  16. 计算机 存储体 存储单元 存储元 存储字 存储字长的联系
  17. Focal Trio 6 Be 3分频监听音箱评测
  18. kube-proxy模式之iptables
  19. I2C通讯过程中SDA被一直拉低
  20. 核心期刊《中国兽医学报》

热门文章

  1. library/adodb/adodb.inc.php,ADOdb Library for PHP
  2. python 安居客 爬虫_Python爬虫安居客房价信息(并利用百度地图API查询坐标)
  3. 大公司比较习惯问及的97道问题附答案
  4. 什么是Csrss.exe进程?此进程有何作用?
  5. linux系统装psp,如何在Linux中玩PSP游戏
  6. 数据库(员工信息表)
  7. 英语学习/词典app行业top5简要分析
  8. 旧电脑装什么系统最快_旧电脑装什么系统好 老旧电脑适合装什么操作系统
  9. 使用Ventoy制作启动盘
  10. 可视化:这十个数据可视化工具软件平台你必须知道