零、写在前面
计划要用seq2seq模型做一个交响乐编曲程序,encoder network的输入是一个乐句旋律,decoder network的目标target是这个乐句完整的管弦配乐版本。本文记录的实验的目的是自动提取出midi乐句的旋律音轨。
一、原理
参考这篇文献中的方法:提取出这个乐句中各个音轨(乐器)的以下特征:
- 平均力度
- 所有音符累加总时值
- 时值类型
- 最高音与最低音之间的音程
- 第二高音与第二低音之间的音程
每个音轨的五个特征叠在一起,作为一个乐句的神经网络输入。
对应于主旋律的音轨的one-hot向量作为神经网络的目标输出。
之前文献中,使用了其他的特征作为输入,但那些特征并不十分合理。
二、技术细节
1.midi_to_features.py
这个文件用于提取出一个乐句各个音轨的5个特征值,用了python的pretty_midi包作为处理midi文件的工具。
import pretty_midi
def get_avg_velocity(instrument):
# 平均力度
velocity = 0
for note in instrument.notes:
velocity += note.velocity
velocity /= len(instrument.notes)
return velocity
def get_sum_duration(instrument):
# 所有音符累加总时值
duration = 0
for note in instrument.notes:
duration += note.end - note.start
return duration
def get_types_of_duration(instrument):
# 时值类型
duration = []
for note in instrument.notes:
duration.append(note.end - note.start)
types = len(set(duration))
return types
def get_pitch_range(instrument):
# 最高音与最低音之间的音程
pitch = []
for note in instrument.notes:
pitch.append( note.pitch )
sorted_pitch = sorted( set(pitch) )
range = sorted_pitch[-1] - sorted_pitch[0]
return range
def get_second_pitch_range(instrument):
# 第二高音与第二低音之间的音程
pitch = []
for note in instrument.notes:
pitch.a