DAW悪戦苦闘記

DAWやMIDIを通じてDTMを楽しむ記録。MIDI検定試験にもチャレンジするなり。

PythonでSMFを操作する (4) デルタタイム修正

前回記事の続き(注: かなりマニアックです)。今回は、前回未解決であった最初のノートオン・メッセージのデルタタイム、すなわち発音タイミングをシフトして修正する。

daw-jones.hatenablog.com

データ挿入に伴うズレ

途中挿入したセットアップ・データのメッセージ総数と送信経過時間を求める。以下のような簡単な関数を定義してみる。なお、各メッセージのデルタタイムは、そのtime属性*1を参照して引っ張り出せる。下記プログラム例では、msg.timeがそれに該当する。

# セットアップ・データのメッセージ総数と経過時間を求める関数
def setup_time(setup_msg):
    n = len(setup_msg)
    delta_time = sum([msg.time for msg in setup_msg])
    return (n, delta_time)

# 実際に計算してみると
nmsg, time_to_shift = setup_time(setup_msg)
print(nmsg, time_to_shift)

実際の計算結果は、15メッセージ (nmsg) かつ600ティック (time_to_shift) 分の長さとなる。したがって、冒頭から18 (= 3*2 + 15) メッセージ目に来る最初のノートオン・メッセージ*3につき、そのデルタタイムを600ティックだけ減らす必要がある。

該当メッセージのデルタタイム修正

該当メッセージのデルタタイム値を書き換えるには、そのメッセージ・オブジェクトのtime属性値を直接修正してしまえばよい。たとえば、以下の1行で事足りる。

# 該当メッセージのデルタタイム修正
track1[3 + nmsg].time -= time_to_shift

修正後のtrack1冒頭は下例の通りとなり、タイミングが修正されたことがわかる。

f:id:daw_jones:20170716173156p:plain

このように、メッセージ・オブジェクトの属性値を修正すれば、元からあるMIDIデータを色々と自由自在に変更修正可能で、MIDIチャネルや移調なども同様のやり方で簡単に編集できる。これらについては次回以降述べる。

*1:タイムと言いつつ値はティック単位である。ティックあたりの時間分解能(μs)は、メタトラックのテンポ設定値で定義される。

*2:元からあったメタメッセージ2件に、前々回に追加挿入したSysExメッセージ1件、計3件。

*3:本例ではたまたまノートオンだが、一般的にはコントロール・チェンジやピッチベンド・チェンジなどの可能性がある。