和弦推导逻辑简析与实现,以及Raphael库试用

诚然,吉他有上千个和弦。世界上最厉害的吉他大师,也无法一眼辨识出所有的和弦。 更多时候,我们熟记几个基本的和弦,然后通过一定的计算法则,去推导其他的和弦。因而推导的逻辑就非常重要。

《吉他三月通》一书把这乐理洋洋洒洒说了一百多页,我想试着让事情简单一些。 最后,我们将逻辑实现成一个小程序,可以方便打印出想要推导的和弦。

音乐与数学的不同

在这之前,我们得谈点有趣的事情,它们都有共同的原因:

  • 为什么我们会觉得某首歌很“中国风”?
  • 为什么某些日本的传统音乐听起来很“诡异”?
  • 为什么钢琴要做成黑键白键,所有键都一样不行吗?

我们常用正整数:1、2、3、4、5、6、7 , 对应和弦:C、D、E、F、G、A、B, 对应音符:Do、Re、Me、Fa、So、La、Ti

每个正整数之间,都是相差1;而按频率高低排列的音符,由于历史原因,它们并不是等差数列。

实际上,4比理想的要低一点,7比理想的要高一点,其他的5个音,则基本在理想线性曲线上!

这5个跟理想比较吻合的音,就是天朝古代的五音阶:宫、商、角、徵、羽。“中国风”的歌曲,大多使用了这五个音,所以让人感到舒服和温和;而日本的传统音乐,反其道而行用了许多4与7(其实这么说也不太对,是受阴阳调式影响,但表现上大概如此),有一种幽静阴深的效果。

所以,以上问题的原因是音符的递增不完全是线性的

我们得把4和7这两个不和谐点标志出来,就出现了“半音和全音”的理论。 把3到47到1这两个不满一个跨度的叫做半音;其他相邻音符之间,都叫做全音。 而造物主的神奇之处在于:两个半音等于一个全音

音乐的世界跟数学的这点不同,会在后面逻辑推导上会给我们一点小小的麻烦。

音乐家与程序员

试想,如果程序员要完成描述音阶的数据结构,会如何设计呢?

通常,应该先规划“最小粒度”。而“半音”刚好是最合适的选择。

音乐家与程序员的处理方式如出一辙,钢琴上夹在两个白键之间的黑键,吉他相邻品丝之间,都是为了表现半音。

如果用程序描述吉他品丝的关系就是:

var scale = [2, 2, 1, 2, 2, 2, 1]; //3-4是半音,7-1也是半音,相隔1品;其他是全音,相隔2品

吉他与尺子

知道了这些,我们就好比掌握了一把尺子的刻度

在尺子上,如果一个刻度表示1cm,那么从3cm往后推两个格子,就是5cm; 把吉他想象成尺子,一个刻度表示半音,和弦之间就可以推导了。

与众不同的是,这把尺子首尾相连,更像一个循环的圈。

刻度:      2品      2品       1品       2品      2品       2品       1品       2品       2品
和弦:C  +----> D  +----> E  +----> F  +----> G  +----> A  +----> B  +----> C  +----> D  +----> ……
音符:Do +----> Re +----> Me +----> Fa +----> So +----> La +----> Ti +----> Do +----> Re +----> ……
整数:1  +----> 2  +----> 3  +----> 4  +----> 5  +----> 6  +----> 7  +----> 1  +----> 2  +----> ……

因而,一个和弦可以有多种方式弹奏。 比如C和弦,除了最基础的开放式(不需要用食指横按品丝)指法,我们还可以用A和弦的指法实现:

C = B + 1品
= A + 2品+1品
= A + 3品

所以,我们用食指横按住第3品(或者用变调夹夹第3品),然后再加上A和弦的开放式指法,就形成了一个C和弦。

同理也可以用E和弦实现:

C = B + 1品
= A + 2品+1品
= G + 2品 + 2品+1品
= F + 2品 + 2品 + 2品+1品
= E + 1品 + 2品 + 2品 + 2品+1品
= E + 8品

横按的位置就在第8品上。

其实大部分情况下,我们都是用A,E,Am,Em这四个和弦去推导其他和弦,理由是这几个和弦横按与转换比较方便,特别是在扫弦的时候。

程序实现

明确逻辑之后,就差程序实现了。但这之前,我们定了程序的最小粒度是1品,就无可避免遇到一个问题: 如果A + 2品 = B,那A + 1品 = ?

这个和弦介于A与B之间,人们把它称为升A降B,对应记法是A#Bb

至此我们可以列出,用E指法和A指法推导的所有和弦的横按位置:

var positions = {
    "E": {
        "A": 5,
        "A#": 6,
        "Bb": 6,
        "B": 7,
        "C": 8,
        "C#": 9,
        "Db": 9,
        "D": 10,
        "D#": 11,
        "Eb": 11,
        "E": 12,
        "F": 1,
        "F#": 2,
        "Gb": 2,
        "G": 3,
        "G#": 4,
        "Ab": 4
    },
    "A": {
        "A": 12,
        "A#": 1,
        "Bb": 1,
        "B": 2,
        "C": 3,
        "C#": 4,
        "Db": 4,
        "D": 5,
        "D#": 6,
        "Eb": 6,
        "E": 7,
        "F": 8,
        "F#": 9,
        "Gb": 9,
        "G": 10,
        "G#": 11,
        "Ab": 11
    }
};

同时,将E、A的开放和弦的指型描述出来:

chord_shapes = {
    "M E": {
        name: "Maj",
        chord: [[3, 2], [4, 3], [5, 3]],
        bars: [{from_string: 6, to_string: 1, fret: 1}]
    },
    "m E": {
        name: "m",
        chord: [[4, 3], [5, 3]],
        bars: [{from_string: 6, to_string: 1, fret: 1}]
    },
    "M A": {
        name: "Maj",
        chord: [[2, 3], [3, 3], [4, 3], [6, "x"]],
        bars: [{from_string: 5, to_string: 1, fret: 1}]
    },
    "m A": {
        name: "m",
        chord: [[2, 2], [3, 3], [4, 3], [6, "x"]],
        bars: [{from_string: 5, to_string: 1, fret: 1}]
    }
};

分别传递“和弦名”,“指法”,“类型”作为参数,画出和弦图像的接口就可以这样定义:

createChord("C", "A", "M A"); \\画出C和弦,用A指法,定义类型是大三和弦(Maj)
createChord("D", "A", "m A"); \\画出Dm和弦,用A指法,定义类型是小三和弦(Minor)

Raphael.js

理清了逻辑,那么如何画出这样的和弦图?

Dom自然是可以的,Canvas也是个好选择,因为它能省去好多定位的样式。但考虑到后续可拓展成五线谱,其包含了许多复杂的乐符,SVG是最好的选择。Raphael.js是很方便处理SVG的JS库。

Raphael.js以其兼容性(IE6+),实用性,以及良好的接口著称。 在官方的入门例子里,可看到从元素定义到事件绑定,基本我们平时处理dom没多大区别。

//创建一个画布
var paper = new Raphael("paper", 500, 500);
//画圆
var circle = paper.circle(50, 50, 40);
circle.attr({
    "stroke": "red",
    "stroke-width": 4,
    "fill": "blue"
});
circle.mousedown(function () {
    circle.attr("fill", "red");
});

其核心模块大概分为:

  • 动画 Animation
  • 元素 Element
  • 矩阵 Matrix
  • 画布 Paper
  • 事件 Eve
  • 核心 Raphael (通用函数库,比如颜色转换,贝塞尔曲线描绘等)

一个和弦图的绘制,其实只需要Paper模块的三个方法: path(和弦外框),rect(指型),text(文字说明)

具体可参考以下Demo,就不赘述了。

Demo

以下是一个Demo,将上述chord_shapes的指型补充得更完整。

并且尝试用A指型,自动生成了C调的7个常用和弦。

End.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏计算机视觉life

自识别标记(self-identifying marker) -(5) 用于相机标定的CALTag图案设计

前面介绍了CALTag的工作原理、应用领域。如果我们想在实际项目中应用自识别标记,通常需要根据项目的特点来设计不同尺寸,不同数目,不同排列的图案,那么如何设计属...

1937
来自专栏PPV课数据科学社区

数据挖掘知识脉络与资源整理(十)–箱线图

? ? 箱线图的简介 箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。在各种领域也经常...

3108
来自专栏大数据智能实战

基于stanford nlp(JAVA)实现关系抽取

关系抽取是自然语言处理和理解的重要任务之一,就是从自由文本中发现实体对(人物、地点、机构、事件)及实体之间的关系。 关系抽取一般采用三元组,(实体,关系,实体)...

2895
来自专栏智能算法

水波模拟算法

一、理论依据 水波的物理学模型便是理论依据。水波有如下特性: 扩散:水波总是从被扰动的中心向外扩散。在水波扩散过程中每个点都在得到能量后以自己为中心震动,并向四...

3649
来自专栏机器学习算法原理与实践

中文文本挖掘预处理流程总结

在对文本做数据分析时,我们一大半的时间都会花在文本预处理上,而中文和英文的预处理流程稍有不同,本文就对中文文本挖掘的预处理流程做一个总结。

1023
来自专栏阮一峰的网络日志

相似图片搜索的原理

上个月,Google把"相似图片搜索"正式放上了首页。 你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。 ? 一个对话框会出现。 ?...

4487
来自专栏MixLab科技+设计实验室

写给设计师的人工智能指南:JS框架Synaptic

上一篇写了tensorflow,发现tf对于设计师来说,其实门槛有点高.要折腾各种配置,还要gpu...其实是不利于快速入门的. Synaptic是一个用于no...

2955
来自专栏算法channel

问答记录贴 1 | 解析 NumPy 的广播(broadcasting)机制

实践出真知,相互讨论碰撞出思想的火花。【原创互助答疑群】内有的问答很精彩。于是脑子里闪现出一个想法,为什么不把整个的问答过程记录总结下来,分享给更多的小伙伴呢?...

991
来自专栏人工智能LeadAI

机器学习实战 | 数据探索(变量变换、生成)

1.1、什么是变量变换? 在数据建模中,变换是指通过函数替换变量。 例如,通过平方/立方根或对数x替换变量x是一个变换。 换句话说,变换是一个改变变量与其他变量...

3806
来自专栏封碎

当今世界最为经典的十大算法 博客分类: 经典文章转载 算法数据结构网络应用数据挖掘J#

本文转载自July CSDN博客:http://blog.csdn.net/v_JULY_v/archive/2011/03/07/6228235.aspx

892

扫码关注云+社区