在Roland钢琴伴侣的开发中,首先将mid文件解析出来取到每一个音符的起始时间,每一个音符的时值,音符值(比如中央C的值是60),在绘五线谱的时候需要将每一个音符值与它对应的度(octave)和音名之间相互转换。
WhiteNote.h
/**@class WhiteNote
* The WhiteNote class represents a white keynote, a non-sharp,non-flat note. Todisplay midi notes as sheet music, the notes
must be converted to white notes andaccidentals.
*
* White notes consist of a letter (A thru G)and an octave (0 thru 10).
* The octave changes from G to A. After G2 comes A3. Middle-C is C4.
*
* The main operations are calculatingdistances between notes, and comparing notes.
*/
/*The table below is very important,you must be understand it.
@class WhiteNote includes two attributes(one is ‘letter’,another is‘Octave’)
int letter; /* The letter of the note, A thru G */
int octave; /* The octave, 0 thru 10. */
*/
这个类里面有一个很重要的枚举类型:
/** Enumeration of the notes in a scale (A, A#, ... G#) */
enum {
NoteScale_A = 0,
NoteScale_Asharp = 1,
NoteScale_Bflat = 1,
NoteScale_B = 2,
NoteScale_C = 3,
NoteScale_Csharp = 4,
NoteScale_Dflat = 4,
NoteScale_D = 5,
NoteScale_Dsharp = 6,
NoteScale_Eflat = 6,
NoteScale_E = 7,
NoteScale_F = 8,
NoteScale_Fsharp = 9,
NoteScale_Gflat = 9,
NoteScale_G = 10,
NoteScale_Gsharp = 11,
NoteScale_Aflat = 11
};
这个枚举里面的值和下表里面的A A# B C C# D D# E F F# G G# 这些值一一对应。
/**Convert a note (A, A#, B, etc) and octave into a Midi Note number.
*/
int notescale_to_number(int notescale, int octave) {
return 9 + notescale +octave * 12;
}
notescale对应上面枚举里面的值,octave对应下表的组数,举一个例,我们找到第四组的的C,在上面枚举中查找C的值和NoteScale_C的值相等(等于3),
所以notescale_to_number(NoteScale_C, 4) = 60,刚好和第四组的C的音符值对应。这是一个通过scale和octave转换成音符的核心算法。
第-1组
0 1 2 3 4 5 6 7 8
C C# D D# E F F# G G#
第0组
9 10 11 12 13 14 15 16 17 18
A A# B C C# D D# E F F#
19 20
G G#
第1组
21 22 23 24 25 26 27 28 29 30
A A# B C C# D D# E F F#
31 32
G G#
第2组
33 34 35 36 37 38 39 40 41 42
A A# B C C# D D# E F F#
43 44
G G#
第3组
45 46 47 48 49 50 51 52 53 54
A A# B C C# D D# E F F#
55 56
G G#
第4组
57 58 59 60 61 62 63 64 65 66
A A# B C C# D D# E F F#
67 68
G G#
第5组
69 70 71 72 73 74 75 76 77 78
A A# B C C# D D# E F F#
79 80
G G#
第6组
81 82 83 84 85 86 87 88 89 90
A A# B C C# D D# E F F#
91 92
G G#
第7组
93 94 95 96 97 98 99 100 101 102
A A# B C C# D D# E F F#
103 104
G G#
第8组
105 106 107 108 109 110 111 112 113 114
G G#
第9组
117 118 119 120 121 122 123 124 125 126
A A# B C C# D D# E F F#
127
接下来介绍另外一个核心方法,这个方法是将音符值转换成NoteScale枚举值,例如60,转换之后notescale_from_number(60)就等于NoteScale_C( 3 ).
int notescale_from_number(int number) {
return (number + 3) % 12;
}
/** Return true if this notescale number is a black key */
BOOL notescale_is_black_key(int notescale) {
if (notescale == NoteScale_Asharp ||
notescale == NoteScale_Csharp ||
notescale == NoteScale_Dsharp ||
notescale == NoteScale_Fsharp ||
notescale == NoteScale_Gsharp) {
return YES;
}
else {
return NO;
}
}
上面这个方法是判断一个音符是否为black key.