好的,我查看了 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 编写所有 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 我现在真的很想笑。
这解决了微音问题。我现在可以听到完美的间隔!我感到快乐和满足。
编辑2
我只是想分享我的进一步更改,这些更改会导致更好的微调:
if (pitches >= 12288)
{
int diff = 16384-pitches;
int applieddiff = 8192-diff;
pitches = applieddiff;
semitone += 1;
if (semitone == 12)
{
octave += 1;
semitone = 0;
}
}
这也有助于在 midi 板上使用半音(黑色)键,而不是仅使用具有高音高值的纯音(白色)键。因此,如果您将数据发送到另一个软件,它将单独检测所有键。例如,之前没有 G 和 G#,只有 G 和 G-with-high-pitch。当同时发送音符消息时,这些会导致键彼此停止。