0

我必须制作一个转换器来接受int表示当前音调的半音间隔(即根 = 1,小二 = 2,小七 = 11,大九 = 15,大十三 = 22 等),并将其转换为全音阶音阶间隔,反之亦然。

所以考虑到上面的例子,这里有一些映射:

Diat.     |  Chrom.
---------------------
1   (C)   |  1
b2  (Db)  |  2
2   (D)   |  3
4   (F)   |  6
b7  (Bb)  |  11
9   (D)   |  15
#11 (F#)  |  19
b13 (Ab)  |  21

显然,我可以使用简单的 1 对 1switch语句来完成两个功能,或者按照建议,使用双向字典,但在这样做之前,我想知道是否可以找到更有效的方法来做到这一点。

全音阶输出不必是精确的音调,等音调也很好,所以D#Eb相同。

然而,解析方法必须知道如何解析升号和降号,但这可以通过将所有升号设置为更高的降号来简单地实现。

对于铬。诊断。函数,我在考虑更多的算法来计算它。我现在想弄明白,还是没弄明白。它必须根据钢琴键盘的视觉顺序来划分半音阶,这意味着将数量分成两半,不包括被认为是全全音阶的 EF 和 BC 之间的半音。

我更喜欢它是一个计算而不是静态映射,所以我以后可以使用转置比例等。

4

2 回答 2

1

为此,您需要一个特殊的双向字典。这是一个: 获取通用字典的价值键?

换位可以很容易地通过模算术和计算音符之间的相对距离来处理。

如果您正在寻找速度,您还可以定义包含所需元素对的类并将它们放在循环链表或二叉搜索树中。但我认为当你只处理 12 个简单元素时,这并不重要。

于 2013-05-05T03:40:55.440 回答
0

正如我所承诺的,只是为了此事和参考,这里是(在使用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
于 2013-05-05T23:34:04.717 回答