1

我正在尝试编写一个程序来获取音阶的音符。这就是我现在所做的,但它看起来非常复杂!我错过了什么?应该是这样吗?

notes = [ "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b" ]
major = [2,2,1,2,2,2] # semitone steps
root  = "f"
root_i= notes.index(root)

index = [root_i+i for i in [sum(major[:y]) for y in range(len(major)+1)]]
scale = [notes[i] if i < len(notes) else notes[i-len(notes)] for i in index]

我只需要增加root_i每个“步骤”major并在我到达末尾时重新启动notes...

谢谢。

4

4 回答 4

2

一种方法是使用 a ,但基于方法deque并没有什么问题。list我只是倾向于通过将它放在自己的功能中来更清楚地了解正在发生的事情......

from collections import deque

notes = [ "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b" ]

def get_scale(seq, start):
    d = deque(seq)
    d.rotate(-seq.index(start)) 
    yield d[0]
    for idx in [2, 2, 1, 2, 2, 2]:
        d.rotate(-idx) # always bring element to index 0
        yield d[0] 

print list(get_scale(notes, 'c'))

然后,您不妨预先计算很多:

>>> scales = {k:list(get_scale(notes, k)) for k in notes}
>>> scales
{'a': ['a', 'b', 'c#', 'd', 'e', 'f#', 'g#'], 'c': ['c', 'd', 'e', 'f', 'g', 'a', 'b'], 'b': ['b', 'c#', 'd#', 'e', 'f#', 'g#', 'a#'], 'e': ['e', 'f#', 'g#', 'a', 'b', 'c#', 'd#'], 'd': ['d', 'e', 'f#', 'g', 'a', 'b', 'c#'], 'g': ['g', 'a', 'b', 'c', 'd', 'e', 'f#'], 'f': ['f', 'g', 'a', 'a#', 'c', 'd', 'e'], 'c#': ['c#', 'd#', 'f', 'f#', 'g#', 'a#', 'c'], 'd#': ['d#', 'f', 'g', 'g#', 'a#', 'c', 'd'], 'f#': ['f#', 'g#', 'a#', 'b', 'c#', 'd#', 'f'], 'g#': ['g#', 'a#', 'c', 'c#', 'd#', 'f', 'g'], 'a#': ['a#', 'c', 'd', 'd#', 'f', 'g', 'a']}
>>> scales['d']
['d', 'e', 'f#', 'g', 'a', 'b', 'c#']
>>> scales['c']
['c', 'd', 'e', 'f', 'g', 'a', 'b']
于 2012-12-05T12:56:51.443 回答
2

如果您关心音符的正确拼写,您将需要一种更复杂的方法。例如,您的 F# 大调音阶将变为 [F#, G#, A#, B, C#, D#, F],而您真正想要的是 E# 作为主音。同样,如果您关心拼写,您也需要实现单位。如果您关心除大调音阶(自然和和声小调、Lydian 等)之外的全音阶音阶,您还需要将音符间距与所需的音阶间距分离。相反,您需要的是更复杂的东西,例如:

def getScale(root='C', mode='major')
    noteNames = ['C','D','E','F','G','A','B']
    noteSpacing = [2,2,1,2,2,2,1]
    if mode == 'natural minor':
        scaleSpacing = [2,1,2,2,1,2,2]
    elif mode == 'harmonic minor':
        scaleSpacing = [2,1,2,2,1,3,1]
    else:
        scaleSpacing = [2,2,1,2,2,2,1]

    startingIndex = noteNames.index(root[0])

    baseSemitoneOffset = root.count('#') - root.count('b')
    currentSemitones = 0
    correctSemitones = 0

    scale = [root]
    for noteDegree in range(1, 7):
        currentIndex = (startingIndex + noteDegree) % len(noteNames)
        currentSemitones += scaleSpacing[(noteDegree -1) % len(noteNames)]
        correctSemitones += noteSpacing[(currentIndex - 1) % len(noteNames)]
        currentSemitonesWithOffset = currentSemitones + baseSemitoneOffset
        thisNoteStep = noteNames[currentIndex]
        if currentSemitonesWithOffset < correctSemitones:
            thisNoteName = thisNoteStep + 'b' * (correctSemitones - currentSemitonesWithOffset)
        elif currentSemitonesWithOffset > correctSemitones:
            thisNoteName = thisNoteStep + '#' * (currentSemitonesWithOffset - correctSemitones)
        else:
            thisNoteName = thisNoteStep
        #print thisNoteName, currentSemitonesWithOffset, currentSemitones, correctSemitones
        scale.append(thisNoteName)

    return scale

对于这些值,哪个返回您所期望的

print getScale('C')
print getScale('Ab')
print getScale('F#')

['C', 'D', 'E', 'F', 'G', 'A', 'B']
['Ab', 'Bb', 'C', 'Db', 'Eb', 'F', 'G']
['F#', 'G#', 'A#', 'B', 'C#', 'D#', 'E#']

并且适用于更晦涩的音阶:

print getScale('C', mode='harmonic minor')
print getScale('Ab', mode='natural minor')
print getScale('Fb', mode='major')

['C', 'D', 'Eb', 'F', 'G', 'Ab', 'B']
['Ab', 'Bb', 'Cb', 'Db', 'Eb', 'Fb', 'Gb']
['Fb', 'Gb', 'Ab', 'Bbb', 'Cb', 'Db', 'Eb']

有一个真实的假设,即音乐理论比在计算机中实现的图形或音频要容易得多……确实如此,但并没有那么容易。Python 程序员可能会对Pedro Kroger的《Geeks and Nerds 音乐》一书感兴趣;或者,如果您想研究更深层次的音乐理论问题(旋律小音阶,升序和降序不同;非八度音阶重复音阶等),您可以(我自己的工作的无耻插件)查看music21 Python 工具包,尤其是music21.scale模块。

于 2012-12-09T20:51:05.233 回答
1
scale = [notes[i] if i < len(notes) else notes[i-len(notes)] for i in index]

可以写成

scale = [notes[i % len(notes)] for i in index]

整个可以使用重写itertools

import itertools as it
notes = [ "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b" ]
major = [2,2,1,2,2,2] # semitone steps
root  = "f"

note_iter = it.dropwhile(root.__ne__, it.cycle(notes))
scale = [list(it.islice(note_iter, m))[0] for m in major]

或“一个”-衬里:

scale = [n for i, n in it.izip(it.chain.from_iterable(xrange(m) for m in major),
                               it.dropwhile(root.__ne__, it.cycle(notes)))
           if i == 0]
于 2012-12-05T12:42:38.373 回答
1

最简单的?

scale = [notes[(y+root_i)%len(notes)] for y in [0,2,4,5,7,9,11]]

甚至

scale = [notes[(y+notes.index(root))%len(notes)] for y in [0,2,4,5,7,9,11]]

你不需要 root_i 或 index

于 2012-12-05T13:04:57.443 回答