我正在尝试在Java项目中使用JFugue 5.0.9来创建* .midi文件。在使用24 tune makam piano的频率将JFugue的midi功能实现到我的项目中时,我意识到它存在一些调优问题。
例如此代码:
ChordProgression cp = new ChordProgression("I-III-IV-iv").setKey("E");
System.out.println(cp);
Player player = new Player();
player.play(cp);
应打印
E4MAJ G#4MAJ A4MAJ A4MIN
在控制台上说here。
但是打印
E4MAJ E4MAJ E4MAJ A4MIN
在我的项目中。是的,由于某些原因,前三个和弦相同。当然,它们听起来也一样。
此外,当使用“ m390”之类的微音时,它并不能精确地以该频率听起来。
在另一个文件的主要方法中,我这样写:
Player player = new Player();
player.play("A4 m440 m400 m390 m380 m370 m360");
我知道A4和m440相同,但正如here所说,A5和m440应该听起来相同。但是在我的项目中,A4和m440的声音相同,但并非完全是440Hz。当我发现出问题时,我决定使用一个调谐应用程序,以下是它分别计算的频率:
221.5 221.5 197.5 186.6 186.6 186.6 176.2
如您所见,它在A3附近播放的声音非常远,而不是清晰的A4。但这并不是全部。对于m390,m380和m370,听起来也完全一样。
这到底是什么问题?任何帮助将不胜感激。
一些注意事项: 我很确定这与我的项目无关。我尝试在一个全新的项目中运行上面的代码,发生了同样的问题。而且我的系统没有问题,因为我的主项目和其他任何软件(例如SunVox)实际上听起来都很好。
答案 0 :(得分:1)
好的,我看了JFugue 5.0.9的源代码,这是我在ChordProgression.java中得到的内容:
/**
* Only converts Roman numerals I through VII, because that's all we need in music theory...
* VIII would be the octave and equal I!
*/
private int romanNumeralToIndex(String romanNumeral) {
String s = romanNumeral.toLowerCase();
if (s.startsWith("vii")) { return 6; }
else if (s.startsWith("vi")) { return 5; }
else if (s.startsWith("v")) { return 4; }
else if (s.startsWith("iv")) { return 3; }
else if (s.startsWith("iii")) { return 2; }
else if (s.startsWith("ii")) { return 1; }
else if (s.startsWith("i")) { return 0; }
else { return 0; }
}
有点懒惰...:D问题之一就在这里。如果在不指定语言环境的情况下使用toLowerCase()方法,则会在运行时引起一些问题。在我现在使用的土耳其语字母中,I的小写字母是“ı”,而不是“ i”。因此,该程序将我的和弦从“ I-II-III”转换为“ iii”,因为如您所见,土耳其语字母(ı)的小写字母I没有if语句,这导致它返回0 “ i”。
要解决此问题,我们必须删除小写转换并为大写I编写所有if语句,或将默认语言环境设置为“ en”,以确保将(大写)I转换为(小写)i。 。因此,应在源代码中使用它:
Locale.setDefault(new Locale("en"));
幸运的是,JFugue是在Apache 2.0下发布的开源软件。
此静止不能解释为什么音色听起来不正确,但是现在至少我们知道这些完全是不同的问题。或似乎如此...我不知道。如果我找到其余的解释或解决方案,我将编辑此答案。
最后,我偶然发现了微调的问题。我决定再看一次源代码中的微调计算功能。
在MicrotonePreprocessor类(位于org.staccato包中)中,有一个名为 convertFrequencyToStaccato()的函数。该功能的作用是将频率转换为MIDI音符编号和弯音值。在第107行,如果计算出的音调值与下一个音符非常接近,则该代码会四舍五入半音,八度和音调值:
// If we're close enough to the next note, just use the next note.
if (pitches >= 16380)
{
pitches = 0;
semitone += 1;
if (semitone == 12)
{
octave += 1;
semitone = 0;
}
}
重置音高的行应更改为:
pitches = 8192;
因为,您知道中性螺距值为8192。0(零)是最小螺距值,而16384是最大螺距值。最初,我以与开发人员相同的方式思考:“在16384之后,应该为0。没关系。这里没有问题。”然后我说:“如果我将音高重置值从0更改为8192,该怎么办?”。有效。这是我们俩都有的美丽的感知错误。 :D我现在真的很开心。
这可以解决微调问题。我现在可以听到完美的间隔了!我感到幸福和满足。
我只想分享我的进一步变化,从而更好地调整微调:
if (pitches >= 12288)
{
int diff = 16384-pitches;
int applieddiff = 8192-diff;
pitches = applieddiff;
semitone += 1;
if (semitone == 12)
{
octave += 1;
semitone = 0;
}
}
这也有助于在中板上使用半音(黑)键,而不是仅使用音高值高的音(白)键。因此,如果将数据发送到另一个软件,它将单独检测所有密钥。例如,之前没有G和G#,只有G和高音距G。当同时发送备忘消息时,这些会导致按键彼此停止。