正如我所承诺的,只是为了此事和参考,这里是(在使用GetNote
值之前应该除以 12 的模数,以排除整个八度音阶):
/// <summary>
/// The values are organized so that the note value + 10 is sharp, -10 is flat, for readability.
/// For instance, Note.C - 10 = Note.CFlat, Note.C + 10 = Note.CSharp.
/// </summary>
public enum Note
{
Silent = 0,
CFlat = -9,
DFlat = -8,
EFlat = -7,
FFlat = -6,
GFlat = -5,
AFlat = -4,
BFlat = -3,
C = 1,
D = 2,
E = 3,
F = 4,
G = 5,
A = 6,
B = 7,
CSharp = 10,
DSharp = 12,
ESharp = 13,
FSharp = 14,
GSharp = 15,
ASharp = 16,
BSharp = 17,
}
/// <summary>
/// Returns the note from a chromatic level.
/// For instance: 1 = C, 2 = Db, 6 = F, etc.
/// </summary>
/// <param name="chromaticStep"></param>
public static Note GetNote(int chromaticStep)
{
if (chromaticStep < 0 || chromaticStep > 12)
throw new ArgumentOutOfRangeException("chromaticStep",
"The value must be within the octave range.");
var diatonicStep = (chromaticStep / 2) + 1;
//determines whether it's in the upper half of the keyboard layout (> E)
var isUpperHalf = chromaticStep > 5;
var isOdd = chromaticStep % 2 != 0;
var isChromatic = isUpperHalf ? isOdd : !isOdd;
if (isChromatic)
diatonicStep += isUpperHalf ? 10 : -10;
return (Note)diatonicStep;
}
测试:
static void Main(string[] args)
{
for (int i = 1; i < 13; i++)
Console.WriteLine("{0}: {1}", i, GetNote(i));
}
结果:
1: C
2: DFlat
3: D
4: EFlat
5: E
6: F
7: FSharp
8: G
9: GSharp
10: A
11: ASharp
12: B