用 200 行 Python 代碼掌握基本音樂理論

alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
notes_basic = [
['A'],
['A#', 'Bb'],
['B'],
['C'],
['C#', 'Db'],
['D'],
['D#', 'Eb'],
['E'],
['F'],
['F#', 'Gb'],
['G'],
['G#', 'Ab'],
]
notes = [
['B#', 'C', 'Dbb'],
['B##', 'C#', 'Db'],
['C##', 'D', 'Ebb'],
['D#', 'Eb', 'Fbb'],
['D##', 'E', 'Fb'],
['E#', 'F', 'Gbb'],
['E##', 'F#', 'Gb'],
['F##', 'G', 'Abb'],
['G#', 'Ab'],
['G##', 'A', 'Bbb'],
['A#', 'Bb', 'Cbb'],
['A##', 'B', 'Cb'],
]
def find_note_index(scale, search_note):
''' Given a scale, find the index of a particular note '''
for index, note in enumerate(scale):
# Deal with situations where we have a list of enharmonic
# equivalents, as well as just a single note as and str.
if type(note) == list:
if search_note in note:
return index
elif type(note) == str:
if search_note == note:
return index
find_note_index()函數(shù)將一系列音符(scale)和要搜索的音符(search_note)作為參數(shù),并通過簡單的線性搜索返回索引。我們在循環(huán)中處理兩種情況:(i)提供的音階由單個音符組成(例如上面的字母列表),或(ii)由音階等效音列表組成(例如上面的note或notes_basic列表)。下面是該函數(shù)對于這兩種情況的示例:>>> find_note_index(notes, 'A') # notes is a list of lists
9
>>> find_note_index(alphabet, 'A') # alphabet is a list of notes
0
scale旋轉(zhuǎn)n步的函數(shù):def rotate(scale, n):
''' Left-rotate a scale by n positions. '''
return scale[n:] + scale[:n]
n處切割scale列表,并交換這兩半。這是將alphabet列表旋轉(zhuǎn)三個位置(將音符D放在前面)的示例:>>> alphabet
['A', 'B', 'C', 'D', 'E', 'F', 'G']
>>> rotate(alphabet, 3)
['D', 'E', 'F', 'G', 'A', 'B', 'C']
colour()函數(shù)了,該函數(shù)通過旋轉(zhuǎn)notes數(shù)組為給定的鍵生成一個半音音階:def chromatic(key):
''' Generate a chromatic scale in a given key. '''
# Figure out how much to rotate the notes list by and return
# the rotated version.
num_rotations = find_note_index(notes, key)
return rotate(notes, num_rotations)
colour()函數(shù)在注釋列表中找到所提供鍵的索引(使用我們的find_note_index()函數(shù)),然后將其旋轉(zhuǎn)該量以使其移到最前面(使用我們的rotate()函數(shù))。這是生成D半音音階的示例:>>> import pprint
>>> pprint.pprint(chromatic('D'))
[['C##', 'D', 'Ebb'],
['D#', 'Eb', 'Fbb'],
['D##', 'E', 'Fb'],
['E#', 'F', 'Gbb'],
['E##', 'F#', 'Gb'],
['F##', 'G', 'Abb'],
['G#', 'Ab'],
['G##', 'A', 'Bbb'],
['A#', 'Bb', 'Cbb'],
['A##', 'B', 'Cb'],
['B#', 'C', 'Dbb'],
['B##', 'C#', 'Db']]
intervals = [
['P1', 'd2'], # Perfect unison Diminished second
['m2', 'A1'], # Minor second Augmented unison
['M2', 'd3'], # Major second Diminished third
['m3', 'A2'], # Minor third Augmented second
['M3', 'd4'], # Major third Diminished fourth
['P4', 'A3'], # Perfect fourth Augmented third
['d5', 'A4'], # Diminished fifth Augmented fourth
['P5', 'd6'], # Perfect fifth Diminished sixth
['m6', 'A5'], # Minor sixth Augmented fifth
['M6', 'd7'], # Major sixth Diminished seventh
['m7', 'A6'], # Minor seventh Augmented sixth
['M7', 'd8'], # Major seventh Diminished octave
['P8', 'A7'], # Perfect octave Augmented seventh
]
D色階中找到與M3或主要的第三音階相對應(yīng)的音符。M3的索引為4。即'M3' in intervals[4] == True。colour('D')[4]是音符['E ##','F#','Gb']的列表。M3中的數(shù)字(即3)表示我們需要使用的字母,其中1表示根字母。因此,例如,對于D的鍵,1 = D,2 = E,3 = F,4 = G,5 = A,6 = B,7 = C,8 = D…等等。因此,我們需要在包含字母F的音節(jié)列表(['E ##','F#','Gb'])中尋找一個音節(jié)。這就是音節(jié)F#。M3)是F#。def make_intervals_standard(key):
# Our labeled set of notes mapping interval names to notes
labels = {}
# Step 1: Generate a chromatic scale in our desired key
chromatic_scale = chromatic(key)
# The alphabets starting at provided key's alphabet
alphabet_key = rotate(alphabet, find_note_index(alphabet, key[0]))
# Iterate through all intervals (list of lists)
for index, interval_list in enumerate(intervals):
# Step 2: Find the notes to search through based on degree
notes_to_search = chromatic_scale[index % len(chromatic_scale)]
for interval_name in interval_list:
# Get the interval degree
degree = int(interval_name[1]) - 1 # e.g. M3 --> 3, m7 --> 7
# Get the alphabet to look for
alphabet_to_search = alphabet_key[degree % len(alphabet_key)]
try:
note = [x for x in notes_to_search if x[0] == alphabet_to_search][0]
except:
note = notes_to_search[0]
labels[interval_name] = note
return labels
>>> import pprint
>>> pprint.pprint(make_intervals_standard('C'), sort_dicts=False)
{'P1': 'C',
'd2': 'Dbb',
'm2': 'Db',
'A1': 'C#',
'M2': 'D',
'd3': 'Ebb',
'm3': 'Eb',
'A2': 'D#',
'M3': 'E',
'd4': 'Fb',
'P4': 'F',
'A3': 'E#',
'd5': 'Gb',
'A4': 'F#',
'P5': 'G',
'd6': 'Abb',
'm6': 'Ab',
'A5': 'G#',
'M6': 'A',
'd7': 'Bbb',
'm7': 'Bb',
'A6': 'A#',
'M7': 'B',
'd8': 'Cb',
'P8': 'C',
'A7': 'B#'}
def make_formula(formula, labeled):
'''
Given a comma-separated interval formula, and a set of labeled
notes in a key, return the notes of the formula.
'''
return [labeled[x] for x in formula.split(',')]
formula = 'P1,M2,M3,P4,P5,M6,M7,P8'
>>> for key in alphabet:
>>> print(key, make_formula(formula, make_intervals_standard(key)))
C ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C']
D ['D', 'E', 'F#', 'G', 'A', 'B', 'C#', 'D']
E ['E', 'F#', 'G#', 'A', 'B', 'C#', 'D#', 'E']
F ['F', 'G', 'A', 'Bb', 'C', 'D', 'E', 'F']
G ['G', 'A', 'B', 'C', 'D', 'E', 'F#', 'G']
A ['A', 'B', 'C#', 'D', 'E', 'F#', 'G#', 'A']
B ['B', 'C#', 'D#', 'E', 'F#', 'G#', 'A#', 'B']
def dump(scale, separator=' '):
'''
Pretty-print the notes of a scale. Replaces b and # characters
for unicode flat and sharp symbols.
'''
return separator.join(['{:<3s}'.format(x) for x in scale]) \
.replace('b', '\u266d') \
.replace('#', '\u266f')
unicode字符的更好輸出:>>> for key in alphabet:
>>> scale = make_formula(formula, make_intervals_standard(key))
>>> print('{}: {}'.format(key, dump(scale)))
C: C D E F G A B C
D: D E F? G A B C? D
E: E F? G? A B C? D? E
F: F G A B? C D E F
G: G A B C D E F? G
A: A B C? D E F? G? A
B: B C? D? E F? G? A? B
intervals_major = [
[ '1', 'bb2'],
['b2', '#1'],
[ '2', 'bb3', '9'],
['b3', '#2'],
[ '3', 'b4'],
[ '4', '#3', '11'],
['b5', '#4', '#11'],
[ '5', 'bb6'],
['b6', '#5'],
[ '6', 'bb7', '13'],
['b7', '#6'],
[ '7', 'b8'],
[ '8', '#7'],
]
make_intervals()函數(shù)以使用此函數(shù):def make_intervals(key, interval_type='standard'):
...
for index, interval_list in enumerate(intervals):
...
intervs = intervals if interval_type == 'standard' else intervals_major
for interval_name in intervs:
# Get the interval degree
if interval_type == 'standard':
degree = int(interval_name[1]) - 1 # e.g. M3 --> 3, m7 --> 7
elif interval_type == 'major':
degree = int(re.sub('[b#]', '', interval_name)) - 1
...
return labels
make_intervals()函數(shù)添加了一個新參數(shù)(interval_type),并在內(nèi)部循環(huán)中以不同的方式計算degree度數(shù)。如果將interval_type指定為'major',則只需刪除所有b和#字符,然后再轉(zhuǎn)換為整數(shù)以獲取度數(shù)即可。formulas = {
# Scale formulas
'scales': {
# Major scale, its modes, and minor scale
'major': '1,2,3,4,5,6,7',
'minor': '1,2,b3,4,5,b6,b7',
# Melodic minor and its modes
'melodic_minor': '1,2,b3,4,5,6,7',
# Harmonic minor and its modes
'harmonic_minor': '1,2,b3,4,5,b6,7',
# Blues scales
'major_blues': '1,2,b3,3,5,6',
'minor_blues': '1,b3,4,b5,5,b7',
# Penatatonic scales
'pentatonic_major': '1,2,3,5,6',
'pentatonic_minor': '1,b3,4,5,b7',
'pentatonic_blues': '1,b3,4,b5,5,b7',
},
'chords': {
# Major
'major': '1,3,5',
'major_6': '1,3,5,6',
'major_6_9': '1,3,5,6,9',
'major_7': '1,3,5,7',
'major_9': '1,3,5,7,9',
'major_13': '1,3,5,7,9,11,13',
'major_7_#11': '1,3,5,7,#11',
# Minor
'minor': '1,b3,5',
'minor_6': '1,b3,5,6',
'minor_6_9': '1,b3,5,6,9',
'minor_7': '1,b3,5,b7',
'minor_9': '1,b3,5,b7,9',
'minor_11': '1,b3,5,b7,9,11',
'minor_7_b5': '1,b3,b5,b7',
# Dominant
'dominant_7': '1,3,5,b7',
'dominant_9': '1,3,5,b7,9',
'dominant_11': '1,3,5,b7,9,11',
'dominant_13': '1,3,5,b7,9,11,13',
'dominant_7_#11': '1,3,5,b7,#11',
# Diminished
'diminished': '1,b3,b5',
'diminished_7': '1,b3,b5,bb7',
'diminished_7_half': '1,b3,b5,b7',
# Augmented
'augmented': '1,3,#5',
# Suspended
'sus2': '1,2,5',
'sus4': '1,4,5',
'7sus2': '1,2,5,b7',
'7sus4': '1,4,5,b7',
},
}
這是在C鍵中生成所有這些音階和和弦時的輸出:
intervs = make_intervals('C', 'major')
for ftype in formulas:
print(ftype)
for name, formula in formulas[ftype].items():
v = make_formula(formula, intervs)
print('\t{}: {}'.format(name, dump(v)))
scales
major: C D E F G A B
minor: C D E? F G A? B?
melodic_minor: C D E? F G A B
harmonic_minor: C D E? F G A? B
major_blues: C D E? E G A
minor_blues: C E? F G? G B?
pentatonic_major: C D E G A
pentatonic_minor: C E? F G B?
pentatonic_blues: C E? F G? G B?
chords
major: C E G
major_6: C E G A
major_6_9: C E G A D
major_7: C E G B
major_9: C E G B D
major_13: C E G B D F A
major_7_#11: C E G B F?
minor: C E? G
minor_6: C E? G A
minor_6_9: C E? G A D
minor_7: C E? G B?
minor_9: C E? G B? D
minor_11: C E? G B? D F
minor_7_b5: C E? G? B?
dominant_7: C E G B?
dominant_9: C E G B? D
dominant_11: C E G B? D F
dominant_13: C E G B? D F A
dominant_7_#11: C E G B? F?
diminished: C E? G?
diminished_7: C E? G? B??
diminished_7_half: C E? G? B?
augmented: C E G?
sus2: C D G
sus4: C F G
7sus2: C D G B?
7sus4: C F G B?
mode = rotate
major_mode_rotations = {
'Ionian': 0,
'Dorian': 1,
'Phrygian': 2,
'Lydian': 3,
'Mixolydian': 4,
'Aeolian': 5,
'Locrian': 6,
}
intervs = make_intervals('C', 'major')
c_major_scale = make_formula(formulas['scales']['major'], intervs)
for m in major_mode_rotations:
v = mode(c_major_scale, major_mode_rotations[m])
print('{} {}: {}'.format(dump([v[0]]), m, dump(v)))
C Ionian: C D E F G A B
D Dorian: D E F G A B C
E Phrygian: E F G A B C D
F Lydian: F G A B C D E
G Mixolydian: G A B C D E F
A Aeolian: A B C D E F G
B Locrian: B C D E F G A
C Ionian,C Dorian,C Mixolydian等。“ C Mixolidian”與“the Mixolydian of C”不同。前者是指根音為C的混合音階,后者是指C大音階的混合音階(即上方的G混合音階)。keys = [
'B#', 'C', 'C#', 'Db', 'D', 'D#', 'Eb', 'E', 'Fb', 'E#', 'F',
'F#', 'Gb', 'G', 'G#', 'Ab', 'A', 'A#', 'Bb', 'B', 'Cb',
]
modes = {}
for key in keys:
intervs = make_intervals(key, 'major')
c_major_scale = make_formula(formulas['scales']['major'], intervs)
for m in major_mode_rotations:
v = mode(c_major_scale, major_mode_rotations[m])
if v[0] not in modes:
modes[v[0]] = {}
modes[v[0]][m] = v
['C'],則會得到以下內(nèi)容:更多閱讀
特別推薦

點擊下方閱讀原文加入社區(qū)會員
評論
圖片
表情
