转换音乐间隔 - 全音阶到彩色,反之亦然

时间:2013-05-05 03:21:40

标签: c# language-agnostic

我必须制作一个接收int的转换器,表示当前音调的色度间隔(即root = 1,次要秒= 2,次要第7 = 11,主要第9 = 15,主要是13 = 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对1 switch语句执行两个函数,或者as suggested使用双向字典,但在此之前我想知道我是否能找到更多有效的方法。

全音阶输出不一定是精确的音调,和谐音调也很好,因此D#Eb是相同的。

然而,解析方法必须知道如何解析锐利和平面,但这可以通过将所有锐利设置为更高的音调来实现。

对于铬。要diat。函数,我正在考虑更多计算它的算法。我现在想弄明白,仍然没有成功。它必须根据钢琴键盘的视觉顺序划分彩色步骤,意味着将数量除以一半,不包括E-F和B-C之间被认为是整个全音阶的半步。

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

2 个答案:

答案 0 :(得分:1)

为此,您需要一个特殊的双向词典。 这是一个: Getting key of value of a generic Dictionary?

通过模运算和计算音符之间的相对距离,可以轻松处理换位。

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

答案 1 :(得分: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