コード例
1つ目のセル.配列からSMFを生成する関数を定義している.
# 必要なライブラリの読み込み.これは以前と同じ.
from mido import MidiFile, MidiTrack, MetaMessage, Message, bpm2tempo
from google.colab import files
def generate_smf_drum(hat, snare, bassdrum, file_name, index):
# ドラムパターンをMIDIにする部分を関数定義したもの
from mido import MidiFile, MidiTrack, MetaMessage, Message, bpm2tempo
midi_file = MidiFile()
drum_track = MidiTrack()
drum_track.append(MetaMessage('midi_port', port=1))
drum_track.append(MetaMessage('set_tempo', tempo=bpm2tempo(120)))
time_from_previous_message = 0
for i in range(16):
# Closed Hi-hat
drum_track.append(Message('note_off', note=42, time=time_from_previous_message))
# Snare
drum_track.append(Message('note_off', note=38, time=0))
# Bass Drum
drum_track.append(Message('note_off', note=35, time=0))
if(hat[i] == 1):
drum_track.append(Message('note_on', note=42, velocity=80, time=0, channel=9))
if(snare[i] == 1):
drum_track.append(Message('note_on', note=38, velocity=80, time=0, channel=9))
if(bassdrum[i] == 1):
drum_track.append(Message('note_on', note=35, velocity=80, time=0, channel=9))
time_from_previous_message = int(0.25 * 480)
#MIDI file (Standard MIDI File)の作成
midi_file.tracks.append(drum_track)
midi_file.save(file_name + str(index) + '.mid')
files.download(file_name + str(index) + '.mid')
2つ目のセル.非対話型遺伝的アルゴリズムを回す.
# GA
import numpy as np
tournament_unit_size = 4
generation_max = 10
population_size = 200
beat_base = 16 # 1小節をいくつに区切るか.16だと16分音符
num_of_instrument = 3 # 楽器の数.ドラムの場合
# 集団の初期化
population = np.array([[np.random.randint(0, 2) for i in np.arange(beat_base * num_of_instrument)] for j in np.arange(population_size)])
print(population.shape)
# MainLoop
for generation in range(generation_max):
new_generation = np.zeros((population_size, beat_base * num_of_instrument), dtype=np.uint8)
print(new_generation.shape)
# 点数付け(正解からの距離)
# ここではフルビットを正解とする
sum_array = np.sum(population, axis=1)
# 現在の点数を表示
print('Max Value in current generation:', np.max(sum_array))
best_index = np.argmax(sum_array)
# ドラムパターンを作って書き出す
print(population[best_index][0:16])
hat = list(population[best_index][0:16])
snare = list(population[best_index][16:32])
bassdrum = list(population[best_index][32:48])
generate_smf_drum(hat, snare, bassdrum, 'ga_generating_drum', generation)
# 子世代を作る
for i in range(int(population_size / 2)):
# 2つの子につき2つの親を選ぶ
parent_indexes = np.zeros(2, dtype=np.uint8)
for j in range(2):
tournament_max_value = 0
# tournament_unit_size分だけ個体を持ってきて
# 一番高い点数のものを親とする
# 親2つ分
for k in range(tournament_unit_size):
index = np.random.randint(population_size)
if sum_array[index] > tournament_max_value:
tournament_max_value = sum_array[index]
parent_indexes[j] = index
# 一点交叉
# 交叉ポイントをランダムに決めて
cutting_point = np.random.randint(beat_base * num_of_instrument)
for j in range(beat_base * num_of_instrument):
# 単純に入れ替えた子供を作る.2つの親から2つの子.
if j < cutting_point:
new_generation[i][j] = population[parent_indexes[0]][j]
new_generation[i+1][j] = population[parent_indexes[1]][j]
else:
new_generation[i+1][j] = population[parent_indexes[0]][j]
new_generation[i][j] = population[parent_indexes[1]][j]
# 集団サイズ分子供ができたら
# 新しく作った子世代で親世代を置き換え
population = new_generation