我问了这个问题的堆栈溢出,并指示到这里。我正在做一个函数,它将帮助我快速找到所有上层结构的三音(3音符和弦),我可以添加到一个4音符第7和弦,以创建一个更大的复合和弦,以及每个三位一体的根和名字。我现在正在测试的例子是一个13#11 chord,它在一个12音符的八度音阶(当根数为0时)达到了以下程度:[0, 2, 4, 6, 7, 9, 10]*
*附带注意:[0, 4, 6, 7, 9, 10]也将匹配为13#11。
基础的第七和弦是占主导地位的第七和弦:[0, 4, 7, 10].I已经知道哪个三合唱完成了和弦:第九和弦是一个主要的三音,第十一和弦是减少的,0, 6, 9 (只有6 ( #11 )和9 (第13)才是真正必要的13#11和弦;2 (9)是可选的)。
实际上,我已经有了一个函数,它可以给出这些结果,我只是想知道是否有一种更快/更有效的方法来做到这一点?现在感觉有点笨重/笨重。
RobNapier建议我使用Enum代替String、Int和。我肯定知道Enum将如何帮助我的triadQualities数组。我不知道数字组合会有什么改善。或者我还能做什么其他的改进(与枚举相关的或者其他的)。有人能帮我启发一下吗?任何帮助都将不胜感激。
extension Int {
func degreeInOctave() -> Int {
switch self {
case 0...11:
return self
case 12...:
return self - 12
default:
return self + 12
}
}
}
var ust: [Int] = [0, 2, 4, 6, 7, 9, 10]
let maj = [0, 4, 7]
let min = [0, 3, 7]
let aug = [0, 4, 8]
let dim = [0, 3, 6]
let sus4 = [0, 5, 7]
let sus2 = [0, 2, 7]
let triadDegs = [maj, min, aug, dim, sus4, sus2]
var triadRoots: [Int] = []
var triadQualities: [String] = []
func findUpperStructureTriads(degs: [Int]) {
let degCount = degs.count
var firstIndex = 0
while firstIndex < (degCount - 2) {
var secondIndex = firstIndex + 1
while secondIndex < (degCount - 1) {
var thirdIndex = secondIndex + 1
while thirdIndex < (degCount) {
var threeNoteGroup = [degs[firstIndex], degs[secondIndex], degs[thirdIndex]]
func checkForTriad(triad: [Int]) -> Bool {
if triadDegs.contains(triad) {
switch triad {
case maj:
triadQualities.append("major")
case min:
triadQualities.append("minor")
case aug:
triadQualities.append("augmented")
case dim:
triadQualities.append("diminished")
case sus4:
triadQualities.append("sus4")
case sus2:
triadQualities.append("sus2")
default:
()
}
return true
} else {
return false
}
}
if threeNoteGroup.contains(6), threeNoteGroup.contains(9){
var inversionCount = 0
var newGroup = threeNoteGroup.map {$0 - threeNoteGroup[0]}
while inversionCount < 3 {
func invert() {
newGroup = newGroup.map {($0 - newGroup[1]).degreeInOctave()}
let newlast = newGroup.remove(at: 0)
newGroup.append(newlast)
}
if checkForTriad(triad: newGroup) {
print(threeNoteGroup, threeNoteGroup[inversionCount])
triadRoots.append(threeNoteGroup[inversionCount])
break
}
invert()
inversionCount += 1
}
}
thirdIndex += 1
}
secondIndex += 1
}
firstIndex += 1
}
for i in 0...(triadRoots.count - 1) {
print(triadRoots[i], triadQualities[i])
}
}
findUpperStructureTriads(degs: ust)[0, 6, 9] 6
[2, 6, 9] 2
6 diminished
2 major组合的ust和弦总是从最低到最高排序。它的元素可以在0到11之间,而且它们从不重复。下面的4音符和弦和上部的3音符和弦被合并成一个大和弦,下和弦第一和弦。如果上和弦中的任何数字已经在合并和弦中,则不会增加两次。所以,如果下和弦是[0, 4, 7, 10],上和弦是[2, 7, 10],那么ust就是[0, 2, 4, 7, 10]。对于该和弦,组合函数的输出(理想情况下)如下:
[0, 2, 7] 0
[2, 7, 10] 2
0 sus2
7 minor注意:有一件事我意识到,这个函数可能实际上对我的更大的程序没有帮助-它将取代我已经使用的一个函数,该函数对每个组合的和弦度数组都采用硬编码的Int数组,并将它们转换为字符串公式(即=“Maj 2上的min三合会”)。所以我已经完成了这项工作。为了使新功能发挥作用,我需要找出一个if语句,说明完成工作需要哪个学位,这对每个可能的和弦质量都有影响。所以这一切都是毫无意义的
发布于 2019-05-14 08:25:28
声明:我不是音乐理论方面的专家,英语不是我的第一语言。因此,我可能会在下面的检讨中使用错误的字眼。
I/O应与计算分开。在您的例子中,findUpperStructureTriads()函数应该返回一些东西,而不是打印它。这使得该函数更好地使用和测试,并增加了程序的清晰度。
此外,应该避免全局变量(triadRoots和triadQualities):调用findUpperStructureTriads()两次将显示意外的结果。
嵌套循环写得更好、更简单,因为在(半开)范围内的循环:
for firstIndex in 0 ..< degs.count {
for secondIndex in firstIndex+1 ..< degs.count {
for thirdIndex in secondIndex+1 ..< degs.count {
// ...
}
}
}和类似的
for inversionCount in 0 ..< 2 { ... }和
for i in 0..请注意,您的版本
(triadRoots.count- 1) {.}
如果upperBound
对于从未发生变异的变量,请使用let。
let threeNoteGroup = [degs[firstIndex], degs[secondIndex], degs[thirdIndex]]
checkForTriad()中的默认情况是“不应该发生”的情况--除非您犯了编程错误。若要及早检测此类错误,可以使用
default:
fatalError("Should never come here")
但实际上,函数可以被更有效的字典查找所取代:
let qualities: [[Int]: String] = [
maj : "major",
min : "minor",
dim : "diminished",
]
// ...
if let quality = qualities[newGroup] {
print(threeNoteGroup, threeNoteGroup[inversionCount])
triadRoots.append(threeNoteGroup[inversionCount])
triadQualities.append(quality)
break
}
将整数音符降为八度可以通过模运算来完成:
extension Int {
var degreeInOctave: Int {
let mod12 = self % 12
return mod12 >= 0 ? mod12 : mod12 + 12
}
}
一种可供选择的方法
你的程序测试给定程度的三个音符的每一个子集,如果它是已知的三位一体,则测试它的三个反转。如果只遍历给定的列表一次,并将每个音符视为每个三合会的根音,可能会更有效。然后你只需测试三合会的其他音符是否在名单上。
多结构
使用类型给出了我们在名称上操作的对象,允许将功能与对象进行分组,提供初始化方法等等。
例如,不是普通的音符数组(或者是度吗?)我们可以定义一个Chord结构:
struct Chord {
let notes: [Int] // Increasing array of degrees in the range 0...11
init(notes: [Int]) {
// Reduce module 12 and sort:
self.notes = notes.map { $0.degreeInOctave }.sorted()
}
func translated(by offset: Int) -> Chord {
return Chord(notes: notes.map { $0 + offset })
}
}
init方法确保按递增顺序和在适当范围内对数字进行排序。translated(by:)方法通过移动所有的度来计算新的和弦。如果需要,可以在以后添加更多的方法。
struct Chord {
mutating func invert() { ... }
}
用于和弦倒置。
三合会可以定义为枚举:
enum Triad: String, CaseIterable {
case major
case minor
case augmented
case diminished
case sus4
case sus2
var chord: Chord {
switch self {
case .major: return Chord(notes: [ 0, 4, 7 ])
case .minor: return Chord(notes: [ 0, 3, 7 ])
case .augmented: return Chord(notes: [ 0, 4, 8 ])
case .diminished: return Chord(notes: [ 0, 3, 6 ])
case .sus4: return Chord(notes: [ 0, 5, 7 ])
case .sus2: return Chord(notes: [ 0, 2, 7 ])
}
}
}
而不是全局变量(maj,min,.)我们现在可以将三合会称为枚举的值,例如
let triad = Triad.major
print(triad) // major
print(triad.chord) // Chord(notes: [0, 4, 7])
在符合CaseIterable的情况下,我们免费获得所有三合会的列表:
for triad in Triad.allCases { ... }
最后,我们需要一个结果类型,即在某个位置的三合会,例如:
struct UpperStructure: CustomStringConvertible {
let triad: Triad
let root: Int
var description: String {
return "\(root) \(triad.rawValue)"
}
}
description方法提供了值的文本表示,可以根据需要进行调整。
有了这些准备,我们就可以定义一个函数,在给定的和弦中找到所有上层结构的三位一体。这可以是Chord类型的方法,而不是全局函数,因此我们现在有
struct Chord {
let notes: [Int]
init(notes: [Int]) {
self.notes = notes.map { $0.degreeInOctave }.sorted()
}
func translated(by offset: Int) -> Chord {
return Chord(notes: notes.map { $0 + offset })
}
func upperStructureTriads() -> [UpperStructure] {
let notesSet = Set(notes)
var result: [UpperStructure] = []
for rootNote in notes {
for triad in Triad.allCases {
let chordNotes = triad.chord.translated(by: rootNote).notes
if chordNotes.contains(6) && chordNotes.contains(9)
&& notesSet.isSuperset(of: chordNotes) {
result.append(UpperStructure(triad: triad, root: rootNote))
}
}
}
return result
}
}
所有可能的根注释和三叉组合都会被测试,并且使用Set来提高包容测试的效率。
用法示例:
let chord = Chord(notes: [0, 2, 4, 6, 7, 9, 10])
let upperStructures = chord.upperStructureTriads()
for us in upperStructures {
print(us)
}
// 2 major
// 6 diminishedhttps://codereview.stackexchange.com/questions/220187
复制相似问题