当前位置:   article > 正文

【机器学习】音乐表示Music Representation_timing 音乐术语

timing 音乐术语

音乐基本术语

  • velocity (i.e. bar or body speed)
  • A tempo is how fast the beats go by in a particular piece of music.
  • quality:音程性质

音乐符号化表示(Symbolic) 

  • 最基本的音乐信息(Events):在何时起止(Onset、Offset)什么绝对音高(MIDI pitch)。
  • 元信息:该音乐数据的名称是什么,包含什么声部、使用什么音色播放。
  • 基本音乐学信息:基本的如小节线、速度、拍号、调式等,以及进一步的信息如表情记号(连线、跳音、延长音、重音、强弱)、反复、临时升降号等。
  • 高层音乐学信息:乐句、和弦、分段、情绪。

因为最基础的MIDI文件只需要起止(Onset、Offset)、绝对音高(MIDI pitch)就可以播放了(音色之类的都可以设为默认如钢琴),因此才会造成数据如此杂乱。MusicXML格式就好得多,因为其是一个面向乐谱显示或排版的格式,包含基本音乐学信息是其基础。

MIDI(Musical Instrument Digital Interface)

  • Channel通道:是指定的0~15的一个值,因为MIDI文件给我们提供了默认的16个通道,每一个通道可以对应一种乐器,相当于midi支持一首歌曲里同时使用16种乐器进行演奏
  • Track音轨:音轨与通道并不是一一对应,而是可以多对多的关系。音轨是逻辑上的划分,比如可以将钢琴的左手演奏放在track 1,右手演奏放在track 2。但是输出时候,都是对应输出到钢琴的通道。你也可以只设置一个track 1,并且在里面记录着不同通道的消息。另外,还经常将track 0用来存储midi的作者、版权、音轨名、乐器名等元信息
  • Event事件:事件也叫做消息(在mido库中使用message表示)。包括三种事件 meta event元消息,midi event主消息, sysex event系统消息。元消息上文有提及是作者,版权,音乐名等信息的存在track0中,系统消息是存储midi系统不同版本的信息,主要需要留意的就是midi消息。 midi有多种信息类型:
MIDI Events

Piano-Roll

MusicXML

MusicXML文件分为两种类型:score-partwise与score-timewise,其中较为常见的是score-partwise。

score-partwise

  1. 谱子信息,XML文件信息
  2. 各声部信息
  3. 声部1全曲:
  4. 小节1
  5. 属性
  6. 音符1
  7. 音符2
  8. ……

REMI(revamped MIDI-derived events)

基于节拍事件(Beat-based)

REMI用时值取代MIDI编码里的音符关(Note off),用小节(Bar)和位置(Position)取代MIDI编码里的时移,并且增加了音乐速度与和弦信息。REMI编码将音乐编码成按照小节、位置、和弦、音乐速度、音高、时值、力度依次排列的离散token序列

The Bar, Position and Tempo-related events entail the use of audio domain downbeat and beat tracking algorithms

相比MIDI-like,REMI的异同:

  • Note-OnNote Velocity

Note-On事件表示某一特定音高的音的开始事件,Node Velocity则表示响度。这两种事件在Midi-like和REMI表示中都存在。

  • Note-OffNote-Duration

在REMI中,使用Note-Duration取代了Note-off,将一个音符用三个连续的token表示:Note VelocityNote-OnNote-Duration。 这样做主要有两个原因:

  1. MIDI-like表示中,必须通过开始结束之间的gap推断时值,通过专门的时值事件表示更为清晰直接
  2. MIDI-like表示中的开始事件与结束事件往往中间间隔若干其他事件,这使得成对出现关系的学习存在困难
  • Time-ShiftPosition & Bar

以固定时值出现的位置&小节(Position & Bar)事件取代原先伴随音符的时间偏移(Time-Shift)事件,能够在音乐数据表示中加入度量结构,避免基于Time-Shift的模型中时间错误累积的问题。Position&Bar更多优点:

  • (1)更容易学习不同小节中同一位置的音符的相关关系
  • (2)便于添加小节级别的约束关系
  • (3)在多音轨/多乐器音乐创作中,以位置&小节表示作为时间参照,便于协调多个不同声部
  • Tempo

用于考虑速度变化(比如常见的beats per minute; BPM)。这类事件在MIDI乐谱中不一定存在,但是在MIDI演奏数据中可以通过对音频进行乐曲速度估计得到。

  • Chord

按根音和类型定义的共60种和弦被作为额外的支持符号(supportive token)输入给模型。

节拍(beat)追踪与强拍(downbeat)追踪

为了获取Bar事件位置,本文使用RNN从音频中估计得到强拍(downbeat)位置,并用线性插值的方法得到节拍位置。这样的表示方式可以得到更规则的时间(节奏)序列。

和弦识别

使用基于规则的启发式方法进行符号域和弦识别。遍历片段中的每个音作为可能的和弦根音,并通过与其他音的音程关系计算似然得分,最终得到和弦估计。

Compound Word Representation(CP)

为了进一步缩减REMI编码的序列长度,CP提出将REMI编码的离散token序列转化为以复合词为时间单位的token序列

Corpus2Event

  1. # ---- define event ---- #
  2. ''' 8 kinds:
  3. tempo: 0: IGN (ignore)
  4. 1: no change
  5. int: tempo
  6. chord: 0: IGN
  7. 1: no change
  8. str: chord types
  9. bar-beat: 0: IGN
  10. int: beat position (1...16)
  11. int: bar (bar)
  12. type: 0: eos
  13. 1: metrical
  14. 2: note
  15. duration: 0: IGN
  16. int: length
  17. pitch: 0: IGN
  18. int: pitch
  19. velocity: 0: IGN
  20. int: velocity
  21. '''
  22. # event template
  23. compound_event = {
  24. 'tempo': 0,
  25. 'chord': 0,
  26. 'bar-beat': 0,
  27. 'type': 0,
  28. 'pitch': 0,
  29. 'duration': 0,
  30. 'velocity': 0,
  31. }
  32. # event生成的过程 process : 每一个bar,中的每一个tick
  33. final_sequence = []
  34. for bar_step in range(0, global_end, BAR_RESOL):
  35. final_sequence.append(create_bar_event())
  36. # --- piano track --- #
  37. for timing in range(bar_step, bar_step + BAR_RESOL, TICK_RESOL):
  38. pos_on = False
  39. pos_events = []
  40. pos_text = 'Beat_' + str((timing-bar_step)//TICK_RESOL)
  41. ...metrical (tempo+chord)
  42. ...for note in notes
  43. ...
  44. if len(pos_events):
  45. final_sequence.extend(pos_events)
  46. # BAR ending
  47. final_sequence.append(create_bar_event())
  48. # EOS
  49. final_sequence.append(create_eos_event())

event2word

  1. # --- build dictionary --- #
  2. # all files
  3. class_keys = pickle.load(
  4. open(os.path.join(path_indir, eventfiles[0]), 'rb'))[0].keys()
  5. print('class keys:', class_keys)
  6. # define dictionary
  7. event2word = {}
  8. word2event = {}
  9. corpus_kv = collections.defaultdict(list)
  10. for file in eventfiles:
  11. for event in pickle.load(open(
  12. os.path.join(path_indir, file), 'rb')):
  13. for key in class_keys:
  14. corpus_kv[key].append(event[key])
  15. for ckey in class_keys:
  16. class_unique_vals = sorted(
  17. set(corpus_kv[ckey]), key=lambda x: (not isinstance(x, int), x))
  18. event2word[ckey] = {key: i for i, key in enumerate(class_unique_vals)}
  19. word2event[ckey] = {i: key for i, key in enumerate(class_unique_vals)}

OctupleMIDI

Multi-track MIDI 编码方式被提出用于对多个音轨同时编码,具有对和声建模的优势。为了进一步缩短编码长度,并提供足够丰富的音乐信息,OctupleMIDI编码将每个音符编码成一个包含拍号、音乐速度、小节、位置、乐器、音高、时值、力度这8个元素的元组。更短的序列长度可以使模型一次性处理更长的音乐片段,从而提升模型的建模能力。用在MusicBERT中。

Python音乐表示库

Music21库

music21可以处理包括MusicXML,MIDI,abc等多种格式的音乐文件,并可以从零开始构建音乐文件或对音乐进行分析。它读取midi文件时,输出是一个个音符object,甚至如果多个音符同时按响,输出就是一个和弦object。而不是一个动作。

  1. import music21
  2. mid = music21.converter.parse("twinkle-twinkle-little-star.mid") # 读取midi文件
  3. for note in mid[0].flat.notes: # 所有的音符
  4. print(note, note.duration.type, note.offset) # 音符, 时长, 位置
  5. #输出
  6. >>> <music21.note.Note C> quarter 0.0
  7. >>> <music21.chord.Chord E3 C3> half 0.0
  8. >>> <music21.note.Note C> quarter 1.0
  9. >>> <music21.note.Note G> quarter 2.0
  10. >>> <music21.chord.Chord C4 C3> half 2.0
  11. >>> <music21.note.Note G> quarter 3.0

音符

  1. f = note.Note("F5#") #创建一个音高为F5#的音符
  2. f.name #音符的音名
  3. f.step #音符的音级(不包含变化音及八度信息的音名,这里成为音级严格来说并不准确)
  4. f.pitch.pitchClassString #音级(以C为0级的音程数)
  5. f.octave #八度
  6. f.pitch #音符的音高,返回一个音高对象
  7. f.duration #音符的时值,返回一个时值对象
  8. f.duration.type #音符的时值的类型 'quarter','half'
  9. f.pitch.midi
  10. #改变属性
  11. f.duration.dots #改变符点数量
  12. f.duration.quarterLength #直接改变时值,以四分音符计
  13. f.pitch.accidental #变化音的类型

和弦

  1. cMajor = chord.Chord(["E3","C4","G4"]) #初始化和弦
  2. cMajor.add(note.Note("E3")) #添加和弦
  3. cMajor.duration.quarterLength=2 #和弦也可以修改时值

Stream

类似list的基本单位,它可以储存任意music21对象及其组合。

  1. stream1 = stream.Stream() #创建
  2. stream1.append(f)
  3. stream1.insert(0,f)
  4. stream1.repeatAppend(f, 4) #重复添加
  5. stream1.show('text') #显示

小节 (Measure)

乐谱Score

MusPy库

MusPy documentation — MusPy documentation (salu133445.github.io)https://salu133445.github.io/muspy/

  • 数据集准备,可以对接PyTorch和TensorFlow。
  • 数据的读取和预处理,支持了常见格式,有这和其他库合作的接口。支持数种常见表示。
  • 模型的评估算法和工具,包括音频渲染、乐谱可视化、pianoroll可视化,以及指标计算。

允许的四种表示方式

Musicaiz库(2022)

MusicAIz — Musicaiz 0.0.2 documentationhttps://carlosholivan.github.io/musicaiz/index.html

支持提供了音乐生成客观评价指标

Python工具包

Miditoolkit

  1. import miditoolkit
  2. midi_obj = miditoolkit.midi.parser.MidiFile(path_midi)
  3. print(midi_obj)
  4. """
  5. Output:
  6. ticks per beat: 480
  7. max tick: 72002
  8. tempo changes: 68
  9. time sig: 2
  10. key sig: 0
  11. markers: 71
  12. lyrics: False
  13. instruments: 2
  14. """

Tempo and Beat Resolution

Timing in MIDI files is centered around ticks and beats. A beat is the same as a quarter note. Beats are divided into ticks, the smallest unit of time in MIDI.

Madmom

Introduction — madmom 0.17.dev0 documentationhttps://madmom.readthedocs.io/en/latest/introduction.html

  • madmom 是一个音频信号处理库,主要用于音乐信号提取(MIR)
  • 提取特征和使用它的HMM包来提取beat和downbeat(即音乐节拍和强拍)并计算多种评价指标得分
  1. from madmom.audio.signal import SignalProcessor, FramedSignalProcessor
  2. from madmom.audio.stft import ShortTimeFourierTransformProcessor
  3. from madmom.audio.spectrogram import (
  4. FilteredSpectrogramProcessor, LogarithmicSpectrogramProcessor,
  5. SpectrogramDifferenceProcessor)
  6. from madmom.processors import ParallelProcessor, Processor, SequentialProcessor

多线程提取频谱特征以及频谱的一阶差分

  1. def madmom_feature(wav):
  2. sig = SignalProcessor(num_channels=1, sample_rate=44100)
  3. multi = ParallelProcessor([])
  4. frame_sizes = [1024, 2048, 4096]
  5. num_bands = [3, 6, 12]
  6. for frame_size, num_bands in zip(frame_sizes, num_bands):
  7. frames = FramedSignalProcessor(frame_size=frame_size, fps=100)
  8. stft = ShortTimeFourierTransformProcessor() # caching FFT window
  9. filt = FilteredSpectrogramProcessor(
  10. num_bands=num_bands, fmin=30, fmax=17000, norm_filters=True)
  11. spec = LogarithmicSpectrogramProcessor(mul=1, add=1)
  12. diff = SpectrogramDifferenceProcessor(
  13. diff_ratio=0.5, positive_diffs=True, stack_diffs=np.hstack)
  14. # process each frame size with spec and diff sequentially
  15. multi.append(SequentialProcessor((frames, stft, filt, spec, diff)))
  16. # stack the features and processes everything sequentially
  17. pre_processor = SequentialProcessor((sig, multi, np.hstack))
  18. feature = pre_processor.process( wav)
  19. return feature

用madmom自带的HMM模块处理beat和downbeat联合检测算法生成的激活值

  1. from madmom.features.downbeats import DBNDownBeatTrackingProcessor as DownBproc
  2. hmm_proc = DownBproc(beats_per_bar = [3,4], num_tempi = 80,
  3. transition_lambda = 180,
  4. observation_lambda = 21,
  5. threshold = 0.5, fps = 100)
  6. #act是用神经网络等音频节拍检测算法处理得到的激活值
  7. beat_fuser_est = hmm_proc(act)
  8. beat_pred = beat_fuser_est[:,0]
  9. downbeat_pred = beat_pred[beat_fuser_est[:,1]==1]

对节拍检测结果和节拍标注值计算多种评估指标:

  1. from madmom.evaluation.beats import BeatEvaluation
  2. scr = BeatEvaluation(beat_pred,beat_true)
  3. print(scr.fmeasure,scr.pscore,scr.cemgil,scr.cmlc,scr.cmlt,
  4. scr.amlc,scr.amlt)

liborsa

  • librosa.beat:用于检测速度和节拍
  • librosa.core:用于从磁盘加载音频和计算各种频谱图
  • librosa.decompose:实现矩阵分解进行谐波和冲击源分离通用频谱图分解
  • librosa.display:音频特征的显示
  • librosa.effects:时域音频处理,音高变换和时间拉伸,时域包装器。
  • librosa.feature:特征提取和操作:色度图,伪常数Q(对数频率)变换,Mel频谱图,MFCC和调谐估计
  • librosa.filters:滤波器生成色度。伪CQT、CQT等
  • librosa.onset:其实检测和起始强度计算。
  • librosa.segment:用于结构分段的函数
  • librosa.swquence:顺序建模功能
  • librosa.util:辅助工具(规范化。填充、居中)

References

Pop Music Transformer:基于节拍事件表示的流行钢琴作品的建模与生成 - 知乎

AI之歌,旋律动人 - 知乎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/248546
推荐阅读
  

闽ICP备14008679号