<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 30977字,需瀏覽 62分鐘

           ·

          2021-04-29 21:19

          本文作者是一位多年自學(xué)成才的吉他手,但對西方樂理一無所知,因此決定編寫一些代碼來搞懂它。
          本文用了大約200行Python代碼來幫助我們理解西方音樂理論的基礎(chǔ)知識。
          我們將首先查看西方音樂理論中的音符,使用它們來導(dǎo)出給定鍵中的半音階,然后將其與音程公式結(jié)合起來以導(dǎo)出常見的音階和和弦。
          最后,我們將研究模式,這些模式是從通用音階衍生出來的整個音階集合,可以用來喚起比主要音階和次要音階所提供的悲喜二分法更微妙的情緒和氣氛。
          十二音符
          西方音樂的音樂字母由字母A到G組成,它們代表不同的音高。
          我們可以使用以下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'],
          ]
          這里有四點要注意:首先,每個音符相距半步或半音,其次,它的表示方式是通過可選的尾隨符號(稱為偶然符號)來表示半步升高(尖銳, ?)或?qū)⒒{(diào)降低半個音階(平坦,?),第三,上述音符只是循環(huán)并重新開始,但是音階較高。
          最后,您會注意到,其中一些音符由包含多個名稱的列表表示:這些是諧音等效詞,這是一種奇特的說法,即同一音符可以具有不同的“拼寫”。因此,例如,音符在A上方半步是A?,但也可以認(rèn)為是B下方半步的音符,因此可以稱為B?。由于歷史原因,音符 B/C 和 E/F 之間沒有尖銳或平坦的部分。
          我們需要這些等效詞的重要原因是,當(dāng)我們開始推導(dǎo)通用音階(大,小和模式)時,連續(xù)音符必須以連續(xù)字母開頭。具有不同字母的諧音等效詞使我們能夠正確得出這些音階。
          實際上,對于某些鍵,上述諧音音符是不夠的。為了滿足“連續(xù)字母的不同字母規(guī)則”,我們最終不得不使用雙尖銳和雙扁平方式來提高或降低音符整步。這些音階通常具有不需要這些雙重偶然性的等效詞,但是為了完整起見,我們可以通過重寫我們的注釋來包括所有可能的諧音等效詞,如下所示:
          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'],
          ]
          半音音階
          半音階是最簡單的音階,它僅由給定音調(diào)(音階中的主要音符,也稱為音調(diào))的八度之間的所有(十二個)半音組成。
          我們可以很容易地為任何給定的鍵生成一個半音階:(i)在我們的筆記列表中找到該音符的索引,(ii)向左旋轉(zhuǎn)音符列表多次。
          查找給定音符的索引
          讓我們編寫一個簡單的函數(shù)來在此列表中查找特定的音符:
          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)由音階等效音列表組成(例如上面的notenotes_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
          向左旋轉(zhuǎn)音符
          現(xiàn)在,我們可以編寫一個將給定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']
          在給定鍵中生成半音音階
          現(xiàn)在,我們終于可以編寫我們的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']]
          對于半音音階,通常在上升時使用銳利度,而在下降時使用平坦度。但是,就目前而言,我們將諧音等值保持不變。我們將看到如何選擇正確的音節(jié)以供以后使用。
          間隔時間
          間隔指定音符之間的相對距離。
          因此,可以基于半音階音符與根音的相對距離來命名。以下是每個音節(jié)的標(biāo)準(zhǔn)名稱,其順序與音節(jié)列表中的索引相同:
          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
          ]
          同樣,同一音符可以具有不同的音程名稱。例如,根音可以被認(rèn)為是完美的統(tǒng)一音色或減弱的第二音符。
          從諧音等效中選取音符
          給定鍵中的半音音階和上述數(shù)組中的間隔,我們可以指出要使用的確切音符(并從一組諧音等效項中過濾掉)。讓我們看一下執(zhí)行此操作的基本方法。
          舉例來說,讓我們看一下如何從D色階中找到與M3或主要的第三音階相對應(yīng)的音符。
          1、從區(qū)間數(shù)組中,我們可以看到找到M3的索引為4。即'M3' in intervals[4] == True
          2、現(xiàn)在,我們在D半音音階(以其長度為模)中查看相同的索引。我們發(fā)現(xiàn)colour('D')[4]是音符['E ##','F#','Gb']的列表。
          3、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#
          4、結(jié)論:相對于D的三分之一(M3)是F#。
          以編程方式標(biāo)記給定鍵的間隔
          我們可以編寫一個相對簡單的函數(shù),以編程方式為我們應(yīng)用此邏輯,并為我們提供一個字典,將給定鍵中的所有音程名稱映射到正確的音符名稱:
          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
          這是我們返回C鍵的字典:
          >>> 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#'}
          間隔公式
          現(xiàn)在,我們可以使用間隔名稱指定公式或音節(jié)組,并能夠?qū)⑺鼈冇成涞轿覀兿胍娜魏捂I:
          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']
          美化音階
          我們還快速編寫一個更好的方法來打印音階的函數(shù):
          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
          對公式使用大音階區(qū)間
          公式命名的另一種方法是基于主要標(biāo)準(zhǔn)的音節(jié)。彈奏樂器時這會更容易,因為如果您熟悉其主要音階,則可以在給定的琴鍵中獲得音階和和弦。
          以下是相對于給定鍵中主音階的音程名稱:
          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'],
          ]
          我還添加了用于更復(fù)雜的和弦(第9、11和13)的常用音程。這些本質(zhì)上是圍繞模八進(jìn)行包裝的。因此,例如,第9位只是第2位,但高了八度。
          我們還可以修改我們的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ù)即可。
          推導(dǎo)通用音階和和弦
          這是一堆涵蓋最常見音階和和弦的公式:
          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?
          模式
          模式本質(zhì)上是刻度的左旋。
          mode = rotate
          需要注意的是,由于旋轉(zhuǎn)后的根音會發(fā)生變化,因此所得到的旋轉(zhuǎn)比例或模式處于不同的鍵中。
          對于每個鍵,主要有七個主要音階模式,具體取決于所應(yīng)用的左旋次數(shù),每個模式都有一個特定的名稱:
          major_mode_rotations = {
              'Ionian':     0,
              'Dorian':     1,
              'Phrygian':   2,
              'Lydian':     3,
              'Mixolydian'4,
              'Aeolian':    5,
              'Locrian':    6,
          }
          使用此方法,我們現(xiàn)在可以為任何給定鍵生成主要比例的模式。這是C大調(diào)的一個例子:
          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)))
          這就是結(jié)果。請記住,根音隨著每次旋轉(zhuǎn)而變化:
          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
          上面,我們正在研究從給定比例導(dǎo)出的模式。但是,實際上我們關(guān)心的是給定鍵的模式。因此,給定C的鍵,我們想知道C Ionian,C Dorian,C Mixolydian等。
          另一種表達(dá)方式是,例如“ 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[0not in modes:
                      modes[v[0]] = {}
                  modes[v[0]][m] = v
          上面,我們循環(huán)了每個鍵,并建立了一個字典,其中包含我們遇到每個鍵時所使用的模式(通過檢查模式的第一個音符)。
          現(xiàn)在,例如,如果我們打印出模式['C'],則會得到以下內(nèi)容:
          總結(jié)
          因此,我們研究了西方音樂理論中的基本音符。如何從這些音節(jié)中得出音階。如何利用間隔名稱從諧音等效項中選擇正確的音符。然后,我們研究了如何使用間隔公式(使用標(biāo)準(zhǔn)音程名稱和相對于大音階的音程)來生成各種音階和和弦。最后,我們看到模式只是音階的旋轉(zhuǎn),對于給定的鍵可以用兩種方式查看:通過旋轉(zhuǎn)給定鍵的音階(將在另一個鍵中)得出的模式,以及從模式中得出的模式。從某些鍵開始,這樣第一個音符就是我們想要的鍵。

          更多閱讀



          5 分鐘快速上手 pytest 測試框架


          5分鐘掌握 Python 隨機爬山算法


          5分鐘快速掌握 Adam 優(yōu)化算法

          特別推薦




          點擊下方閱讀原文加入社區(qū)會員

          瀏覽 88
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  热久久蜜芽 | 午夜国产 | 美女被艹视频久久久 | 无码人妻一区二区三区四区老鸭窝 | 中文字幕乱伦大杂烩 |