Как использовать матрицу цепей Маркова для создания музыки c? - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть матрица (квадрат - nxn) <- Зависит от количества аккордов. </p>

------------------------------------------
            Transition Matrix: (FROM)
------------------------------------------
 A     Bm   C#m    D     E    F#m    G#   
------------------------------------------
0.07  0.00  0.00  0.00  0.66  0.14  0.86 | A   | 
0.15  0.17  0.00  0.05  0.07  0.30  0.00 | Bm  | 
0.00  0.00  0.00  0.00  0.00  0.37  0.00 | C#m | 
0.19  0.00  0.39  0.16  0.14  0.00  0.00 | D   | (TO)
0.52  0.83  0.29  0.43  0.00  0.19  0.00 | E   | 
0.07  0.00  0.32  0.36  0.14  0.00  0.14 | F#m | 
0.00  0.00  0.00  0.00  0.00  0.00  0.00 | G#  | 

Эта матрица умножается на другую матрицу:

1
0
0
0
0
0
0

Это означает, что начальная нота - A (1-я строка соответствует A).

Следующая нота определяется столбцом матрицы переходов Маркова, в котором говорится:

7% шанс стать A

15% шанс стать Bm

0% шанс стать C # m, et c. et c.

(выполняется умножением матрицы с использованием numPy).

Таким образом, полученная матрица представляет собой матрицу 1col x nrows.

Эта матрица будет выглядеть как это:

0.07
0.15
0.00
0.19
0.52
0.07
0.00

^ Это означает, что есть 0,07%, что следующая нота - это A, et c.

^ Используя эти вероятности, я могу воспроизвести эти ноты ? Или сгенерировать миди-файл на его основе?

Я должен получить только одну заметку (плюс первую), и исходя из вероятности, что это должен быть E.

1 Ответ

0 голосов
/ 23 февраля 2020

Я написал небольшую программу для демонстрации генерации Маркова, включая вывод в MIDI-файл с использованием библиотеки music21.

Обратите внимание, что у вашей матрицы перехода есть две проблемы:

  1. Вероятности в 5-м столбце не суммируйте до 1,00. Я заменил 0,66 на 0,65, чтобы все заработало.
  2. Это матрица вероятностей хордовых переходов, а не переходов нот. Так что мой пример включает аккорды (триады), а не отдельные ноты. Ваш вопрос использует слово «примечание» много раз, когда я думаю, что вы вместо этого имели в виду «аккорд», потому что все ваши примеры включают аккорды, такие как си минор.

Я написал программу для повторения каждого аккорда 4 раза , так что каждый аккорд длится целую меру из 4 ударов.

Я выбрал C Major как значение по умолчанию вместо вашего A Major. Если вы хотите создать аккорды в другом ключе, вы можете изменить масштаб root в вызовах chord_to_names на chord_to_midi, используя параметр root_midi. Например, назовите его 57 вместо значения по умолчанию 60, чтобы получить мажор.

Как только вы запустите эту программу, она сгенерирует chords.mid, которую вы можете открыть в программе, такой как MuseScore или редактор миди.

Пример вывода:

Generated chords: [0, 0, 1, 4, 0, 3, 4, 5]
Note names:
['C', 'E', 'G']
['C', 'E', 'G']
['D', 'F', 'A']
['G', 'B', 'D']
['C', 'E', 'G']
['F', 'A', 'C']
['G', 'B', 'D']
['A', 'C', 'E']
MIDI Notes:
[60, 64, 67]
[60, 64, 67]
[62, 65, 69]
[55, 59, 62]
[60, 64, 67]
[53, 57, 60]
[55, 59, 62]
[57, 60, 64]

Что выглядит так, как показано в MuseScore:

enter image description here

import numpy as np

from music21.chord import Chord
from music21.stream import Part
from music21.midi.translate import streamToMidiFile


CHORD_TRANSITIONS = np.matrix([
  #              Transition Matrix: (FROM)
  # ---------------------------------------------
  #  I     ii     iii    IV      V     vi    viio   
  # ---------------------------------------------
    [0.07,  0.00,  0.00,  0.00,  0.65,  0.14,  0.86],  # | I    | 
    [0.15,  0.17,  0.00,  0.05,  0.07,  0.30,  0.00],  # | ii   | 
    [0.00,  0.00,  0.00,  0.00,  0.00,  0.37,  0.00],  # | iii  | 
    [0.19,  0.00,  0.39,  0.16,  0.14,  0.00,  0.00],  # | IV   | (TO)
    [0.52,  0.83,  0.29,  0.43,  0.00,  0.19,  0.00],  # | V    | 
    [0.07,  0.00,  0.32,  0.36,  0.14,  0.00,  0.14],  # | vi   |  
    [0.00,  0.00,  0.00,  0.00,  0.00,  0.00,  0.00]]) # | viio |  

CHORD_TRANSITIONS = CHORD_TRANSITIONS.T  # swap axes for simpler lookup based on current chord

TRIADS = [
  (0, 4, 7),  # I
  (2, 5, 9),  # ii
  (4, 7, 11),  # iii
  (-7, -3, 0),  # IV
  (-5, -1, 2),  # V
  (-3, 0, 4),  # vi
  (-1, 2, 5),  # viio
] 

PC_TO_NAME = ('C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B')

def midi_to_pc(midi_note):
  return midi_note % 12

def midi_to_name(midi_note):
  return PC_TO_NAME[midi_to_pc(midi_note)]

def chord_to_midi(chord_index, root_midi=60):  # chord_index is from 0 to 6
  return [root_midi + x for x in TRIADS[chord_index]]

def chord_to_names(chord_index, root_midi=60):  # chord_index is from 0 to 6
  return [midi_to_name(note) for note in chord_to_midi(chord_index, root_midi)]

num_chords = len(CHORD_TRANSITIONS)

def generate(start_chord=0, length=8):
  cur = start_chord
  chords = [cur]
  for _ in range(length - 1):
    probs = CHORD_TRANSITIONS[cur,:].tolist()[0]
    chord = np.random.choice(num_chords, p=probs)
    chords.append(chord)
    cur = chord
  return chords

chords = generate()

print(f'Generated chords: {chords}')

print(f'Note names:')
for chord in chords:
  print(chord_to_names(chord))

print(f'MIDI notes:')
for chord in chords:
  print(chord_to_midi(chord))

print('Converting to MIDI')
part = Part()
for chord in chords:
  midis = chord_to_midi(chord)

  # Repeat each chord 4 times.
  for i in range(4):  
    part.append(Chord(midis, quarterLength=1))

mf = streamToMidiFile(part)

mf.open('chords.mid', 'wb')
mf.write()
mf.close()
...