【问题标题】:Convert Midi Note Numbers To Name and Octave将 Midi 音符编号转换为名称和八度音阶
【发布时间】:2010-10-17 07:04:31
【问题描述】:

有没有人知道 Java 世界中存在将 midi 音符编号映射到特定音符名称和八度音阶编号的任何东西。例如,参见参考表:

http://www.harmony-central.com/MIDI/Doc/table2.html

我想在 octave 4 中将 60 号 midi 音符映射到它对应的音符名称 (MiddleC)。我可以为此编写一个实用程序类/枚举,但这会相当乏味。有人知道吗?

我专门用它来用 Java 写一个 Tenori-On/Monome 克隆,到目前为止一切都很好......

解决方案

这就是我最终使用的:

String[] noteString = new String[] { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };

int octave = (initialNote / 12) - 1;
int noteIndex = (initialNote % 12);
String note = noteString[noteIndex];

【问题讨论】:

  • 乔恩,我在回答中添加了一些真正的 Java。
  • 太棒了,谢谢指点...

标签: java audio midi javasound


【解决方案1】:

我不相信你的建议是乏味的。这实际上只是一个除模运算,一个得到八度,另一个得到音符。

octave = int (notenum / 12) - 1;
note = substring("C C#D D#E F F#G G#A A#B ",(notenum % 12) * 2, 2);

在真正的 Java 中,与上面的伪代码相反,您可以使用如下代码:

public class Notes {
  public static void main(String [] args) {
    String notes = "C C#D D#E F F#G G#A A#B ";
    int octv;
    String nt;
    for (int noteNum = 0; noteNum < 128; noteNum++) {
      octv = noteNum / 12 - 1;
      nt = notes.substring((noteNum % 12) * 2, (noteNum % 12) * 2 + 2);
      System.out.println("Note # " + noteNum + " = octave " + octv + ", note " + nt);
    }
  }
}

【讨论】:

  • 也许 Jon 正在考虑为每个音符 + 八度音阶组合创建一个枚举?
  • 这是最初的疯狂建议。我一直在寻找算法...我确信我可以解决这个问题,我认为它在 Java 中无效...应该不会花很长时间来翻译...
  • 另外,也许人们可能希望有一个内在的 com..Midi,它与 Java 一起“发布”,包含这样的方法。但是,调用音符(61?)C# 还是 Db 仍然没有得到解决。如果一个人有一个密钥签名,那么可以根据密钥签名(在许多情况下)解决这个问题。即,对于 B 的键,它将是 b C#。对于 Gb 的键,它将是 Db。
  • 我需要在 Lua 中做同样的事情,但从音符名称和八度到音符编号。
【解决方案2】:

JFugue 中,Note 类有一个实用方法可以做到这一点 - 请参阅 public static String getStringForNote(byte noteValue)

编辑:从 JFugue 5.0 及更高版本开始,Note 类具有多种实用方法,用于从 MIDI 音符值获取字符串表示:

  • getToneString(byte noteValue) 将值转换为 60 到字符串 C5
  • getToneStringWithoutOctave(byte noteValue) 将值 60 转换为字符串 C
  • getPercussionString(byte noteValue) 转换为 60 的值到字符串 "[AGOGO]"

这些替换原来的getStringForNote() 方法。

【讨论】:

  • 有趣。看起来 jFugue 5 不再有 org.jfugue.Note。它有org.jfugue.theory.Note,但似乎没有getStringForNote 方法。不知道为什么人们决定拿走有用的功能(特别是因为它的成本不是那么高),尽管可能是他们把它移到了其他地方,但不是我能找到它:-)
  • 实际上,新的 Note 类比旧版本多了几个实用功能。新的 getStringForNote 是 getToneString(byte noteValue) - 对于 60 的值,这将返回“C5”。现在还有 getToneStringWithoutOctave(byte noteValue),它将为 60 返回“C”。您还可以找到 getPercussionString(byte noteValue),它对于 60 将返回“[AGOGO]”。新方法比原来的方法更丰富,并且需要新的函数名称来阐明它们的目的。
【解决方案3】:
public static String getNoteName(int noteNumber){
    noteNumber -= 21; // see the explanation below.
    String[] notes = new String[] {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"};
    int octave = noteNumber / 12 + 1;
    String name = notes[noteNumber % 12];
    return name + octave;
}

说明:

  • midi 中的 A0 是第一个音符,编号为 21。我们将索引调整为从 0 开始(因此开头为 noteNumber -= 21;)。如果您的音符编号是从 0 开始的,例如在钢琴中从 0 到 88,那么您可以将这一行注释掉。

  • 请注意,在此解决方案中,数组中的音符名称从 A 到 G 开始。

  • 八度为 noteNumber / 12 + 1(或上限为 num / 12)。

  • 笔记名称索引为noteNumber % 12

【讨论】:

  • 这是错误的。如果给定 69(A4 的数字),您的代码将返回 A5。八度计算已关闭。
  • 修复一个错误后效果很好:在向下调整 21 之前,必须从原始 noteNumber 计算八度音阶。 - 所以将八度音阶的线移到顶部,它的效果很好!
【解决方案4】:

这是没有太多命名常量的最短形式。也不需要任何循环。

public static String getNoteFromMidiNumber(int midiNote){
    String[] note_names = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
    return note_names[midiNote % 12] + ((midiNote / 12) - 1);
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 2022-10-30
    • 2020-12-31
    • 1970-01-01
    相关资源
    最近更新 更多