likes
comments
collection
share

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

作者站长头像
站长
· 阅读数 20

基础乐理知识

简谱阅读入门

下面以《上学歌》为例讲解简谱的阅读方式和相关的乐理知识。

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

上图只有高音部分,因此还需要参考链接1补充低音部分。

左上角的分数是拍号(节拍符号),分母表示多少个音节为一拍,分子表示一小节多少拍。

左上角的🎶 = 112表示一分钟112拍,对应代码里的bpm(beats per minute)。据此可以计算出每个音符的演奏时间,不过实际演奏中并不需要这么做。

左上角的1 = C表示这首歌的调式为C自然大调。调式确定了歌曲的音域范围。在钢琴键盘中,音名C3被称为中央C,因为它位于钢琴键盘的中间。C自然大调的含义就是升0个八度的唱名do对应C3,由此可推出升1个八度的唱名do对应C4,降1个八度的唱名do对应C2。同理,1 = D为D自然大调,升0个八度的唱名do对应D3do up对应#D3re对应E等。

例如,《上学歌》为C自然大调,bpm = 112,4音节一拍,一小节2拍。

上面提到了#D3,这是什么音名?首先我们需要引入半音和全音的概念。在钢琴白键中E, FB, C没有黑键隔开,是半音关系;其他的都有黑键隔开,是全音关系。理解半音和全音的概念后,就可以讲黑键的音名了。#D3就是D3右侧的黑键,称为升D3。因为它也在E3的左侧,所以也可以称为降E3,记为b E3。例如,在《菊次郎的夏天》简谱(其简谱图在下文《菊次郎的夏天Demo》一节)第十一节有一个音#4,它表示fa up

上面还提到了“八度”,那什么是八度?音程是两个音之间的距离,单位是“度”。在钢琴键盘上,有多少白键就是多少度。比如C3A3为6度,C3B3为7度,C3C4为8度。对于升降音,需要先还原到白键才能确定音程。比如#C3A3为6度。

接下来看《上学歌》的第一节。1 23 1有下划线,表示这一节的两拍,因此每个音符占0.5拍。第二节的5.表示附点四分音符,占1.5拍,随后紧跟的0是八分休止符,占0.5拍。第三节的1上面有一个点,表示这个do需要高1个八度。第五节的1.有1条下划线,0有两条下划线,这表示1.是附点八分音符,需要高一个八度,占0.75拍,休止符占0.25拍。

五线谱阅读入门

下面以《qq堂抢包子》为例讲解五线谱的阅读方式。

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

《qq堂抢包子bgm》为C自然大调,bpm = 140,4音节一拍,一小节4拍。

我们将五线谱的五条线从下到上分别命名为第一线到第五线,线与线之间从下到上分别命名为第一间到第四间。线的下方和上方都可以继续添加线,称为上加一线和下加一线等。怎样快速看出每个音符的音高呢?在高音谱表中有一个口诀:4613。这个口诀是什么含义呢?我们知道曲目常见的调式为C自然大调,所以口诀表示在C自然大调的高音谱表中第一间到第四间的唱法分别为fa、la、do、mi,也就是F3A3C4E4

五线谱每一行最左侧的符号为高音谱号,对应的符号还有中音谱号、低音谱号等。高音谱表和低音谱表的谱线表示的音高不同。简单来说,高音谱表和低音谱表是轴对称的,高音谱表的下加一线和低音谱表的上加一线都表示C3,也就是钢琴的中央C。据此有推论,C2在低音谱的第二间,C4在高音谱表的第三间。这时你可能会有疑问,为什么要引入高音谱号和低音谱号呢?简单点不好嘛?原因很简单,一首钢琴曲往往有低音部分(一般左手弹)和高音部分(一般右手弹),如果只使用高音谱表,那么低音部分很可能需要在下方加不少线,这就不方便了。

该曲的第一个音符是四分音符,占一拍。第二个音符是两个八分音符,各占二分之一拍。所以总体上第一节有4拍。第二节的最后一个空心的音符是二分音符,在上加一线所以是A4。第八节有一条连音线,表示C4要演奏0.5 + 2 = 2.5拍。第十五节的井号跟着的音符表示要升半音,因此是fa up,后面还跟着一个点表示这个音符是附点四分音符,要演奏1.5拍。第十五节的最后一个音符是一个八分音符。所以总体上第十五节同样有4拍。第十六节有一个gliss符号表示这个音要刮奏,从G5刮到G3,总共占2拍,因此在代码中这里每个音符要演奏1 / 7拍。

上学歌Demo

代码传送门

简单讲下代码结构:

  1. main函数的模板基本上不变。
  2. MyNoteImpl myNoteImpl = new MyNoteImpl(MyNote.Major.C);设置调式为C自然大调。
  3. player.setTempoInBPM(112);设置bpm = 112
  4. 上学歌left上学歌right分别处理低音和高音部分。对于里面的addNote调用,我们基本上只需要关注第3个参数和最后两个参数:第3个参数的myNoteImpl.getDo(-1)表示do低1个八度。倒数第二个参数表示这个音演奏多少拍。最后一个参数在顿音中设置为tick + 该音播放时间 / 4即可,在非顿音中设置为tick + length即可。

这世界那么多人Demo

代码传送门

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

  1. 这首曲子难度不高,我自己用它来检验我对乐理知识的理解的正确性。如果对节拍的理解正确,那么你会发现歌曲的第一部分演奏完的时间是2分10秒左右。
  2. 上面的简谱没有体现,从其他渠道查到bpm = 72

qq堂抢包子Demo

代码传送门

所需的乐理知识在上文已经讲解完毕,代码结构也与“上学歌Demo”一致,在此不赘述。

qq堂推箱子Demo

代码传送门

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

  1. 第一节的第一个音符是八分休止符,占0.5拍。
  2. 第一节的第二个音符共占0.5拍,第四个音符的3个音分别占0.5、0.25、0.25拍。
  3. 第十三节的“♭”是临时降半音符号,按照惯例,其作用范围是当前小节的所有相同音。因此当前节总共有3 + 1 = 4个符号需要降半音。这个结论在视频中得到了验证,这一节总共按了4下黑键。
  4. 代码结构与《qq堂抢包子Demo》一致,不赘述。

菊次郎的夏天Demo

代码传送门

Java MIDI 音乐编程入门 + 基础乐理知识 for programmers

这首曲子是最难的,因此放到本文的最后一节来实现。

  1. 顿音符号:可以看到该曲简谱有不少空心倒三角,这就是顿音符号。在代码中,我们传入endTick = tick + 该音播放时间 / 4来表示顿音。
  2. 延音符号:第五节的圆弧是延音符号,表示需要延长do的演奏时间,但颜色为灰色,所以最终视为和休止符效果相同。
  3. 和五线谱同理,按照惯例,第十一节的每个4都应该升半音。
  4. 可以看到右手出现了需要三个手指同时按键的现象,为此我引入了菊次郎的夏天right2, 菊次郎的夏天right3方法。
  5. 代码引入了AddNoteParams类,这是为了能够引入以小节为单位的二维数组,从而更方便地实现仅播放某一个片段。这个想法再扩展一下,就是引入一个DSL来描述一首曲子。因为我写这篇blog的目标是检验自己对乐理知识的理解的正确性,所以就只做到硬编码这一步了。

总结

一个之前没想到过的视角:乐理知识是一种可以用代码进行验证的技术。

参考资料

  1. 《上学歌》高音和低音部分简谱
  2. 乐理入门教程:b23.tv/cPsBkTn