在数据结构中表示各种和弦进程(音乐)规则的最合适(自然适合)的方式是什么,这样每个和弦都有一组可以进展的加权选项?
此数据结构将在程序音乐生成程序中以您可以编码的方式实现:(与语言无关的伪代码)
Chord[7] songArray;
Chord first = new Chord(I); //set the first chord's value
songArray[0] = first;
for (i=0; i<7; i++){
Chord temp = songArray[i].next(); //select the following chord
songArray[i+1] = temp;
}
注意:在古典型音乐中,给定键中的每个和弦可以按照以下规则自然地进入另一个和弦:
----------------------
| Chord | Leads to |
|=======================
| I | any |
| ii | V, vii |
| iii | IV, vi |
| IV | ii, V, vii |
| V | vi |
| vi | ii, ii, IV, V|
| vii | I |
----------------------
数据结构将各种进度存储为加权选项。例如,考虑任何给定主键中的IV和弦:IV可以自然地进展到ii,V或vii,但也可以打破进入任何其他和弦的规则。违反规则的情况很少发生。
我已经考虑了某种链表/树数据结构,但它几乎不像我曾经使用的任何类型的树或列表 - 另外,我无法弄清楚如何实现加权:
另一个想法是使用JSON或类似的东西,但它似乎很快就会变得多余:
{
"I":{
"100%":{
"I",
"ii",
"iii",
"IV",
"V",
"vi",
"vii"
}
},
"ii":{
"80%":{
"V",
"vii"
},
"20%":{
"i",
"ii",
"iii",
"IV",
"vi"
}
},
// ...
}
注意:我很乐意用少数几种语言实现它,此时我并不关心特定的语言实现,而是与语言无关的数据结构体系结构。
答案 0 :(得分:3)
Markov Chain可能非常适合此问题。
马尔可夫链是一个随机过程,其中向下一个状态的进展由当前状态决定。因此,对于表格中的给定间隔,您可以将权重应用于“Leads to”值,然后随机确定要进展的状态。
答案 1 :(得分:3)
我希望你的和弦少于100个,因此如果你使用32位表示概率系列(可能是极端矫枉过正)你最终得到一个100x100x4(40000)字节数组对于平面马尔可夫矩阵表示。根据矩阵的稀疏性(例如,如果你有50个和弦,但每个通常映射到2或3个和弦)的速度和不太重要的空间原因,你可能需要一个数组,其中每个最终的数组元素是(和弦ID,概率)。
在任何一种情况下,这里的关键点之一是你应该使用概率序列,而不是概率序列。也就是说,不是说“这个和弦有10%的几率,而且这个有10%的几率,而且这个有80%的几率”说“第一个和弦有10%的几率,前两个和弦有一个20%的几率,前三个和弦有100%的几率。“
原因如下:当您选择随机但加权的值时,您可以生成固定范围内的数字(对于无符号整数,0到0xFFFFFFFF),然后通过和弦而不是线性搜索执行二进制搜索。 (搜索具有最小概率系列值的元素,该值仍然大于或等于您生成的数字。)
另一方面,如果你的每个和弦只有几个和弦,由于环路更紧密,线性搜索可能比二分搜索更快,然后所有概率系列都可以让你计算出一个简单的运行概率值的总和。
如果你不需要最令人惊讶的惊人表现(我怀疑你没有 - 对于一台计算机而言,音乐中没有那么多的和弦)这部分代码,我老实说只需坚持马尔可夫矩阵的平面表示 - 易于理解,易于实现,合理的执行速度。
除了有趣之外,这种事情很适合考虑预测编码 - 数据压缩中的常用方法。您可以考虑使用基于n-gram的算法(例如PPM)来实现音乐生成中的高阶结构,而无需太多示例材料。多年来,它一直致力于数据压缩。
答案 2 :(得分:2)
听起来你想要某种形式的directed, weighted graph,其中节点是和弦,边缘是渐进选项,边缘权重是进展的可能性。