1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

音声→MIDI変換を再現可能に評価する:入力ハッシュとノートイベントの比較

1
Posted at

音声→MIDI変換の紹介では「精度○%」という数字が目立ちます。しかし、入力音源、採点単位、時間許容幅、対象楽器が違えば、その数字を横に並べても同じものを測ったことにはなりません。

小規模でも再現可能な評価にするには、少なくとも次の四つを分離します。

  1. 同じ入力を使ったか
  2. MIDIファイルとして正常に配送されたか
  3. ノートイベントが期待する音楽構造に近いか
  4. 実用状態まで何分の修正が必要か

1. 入力と出力をハッシュで固定する

ファイル名だけでは、再エンコードや差し替えを検出できません。比較に使う音声と生成されたMIDIについて、SHA-256を保存します。

from hashlib import sha256
from pathlib import Path


def file_sha256(path: str) -> str:
    digest = sha256()
    with Path(path).open("rb") as source:
        for chunk in iter(lambda: source.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


print(file_sha256("input.wav"))
print(file_sha256("result.mid"))

記録するのはハッシュだけではありません。音源の長さ、チャンネル数、サンプルレート、圧縮形式、変換モード、実行日時も一緒に残します。これで「同じ曲だった」という曖昧な説明から、「同じバイト列を同じ条件で処理した」という確認に近づきます。

2. 配送確認と音楽的な正しさを分ける

MIDIを開ける、ノートが一つ以上ある、再生時間がゼロではない。これらは重要ですが、確認できるのは主に配送の成立です。正しい音程やタイミングを復元できたことまでは示しません。

まず構造を機械的に確認します。以下はMidoでトラック数、ノート開始数、再生時間を取り出す最小例です。

from mido import MidiFile


def summarize_midi(path: str) -> dict:
    midi = MidiFile(path)
    note_on_count = sum(
        1
        for track in midi.tracks
        for message in track
        if message.type == "note_on" and message.velocity > 0
    )
    tracks_with_notes = sum(
        any(
            message.type == "note_on" and message.velocity > 0
            for message in track
        )
        for track in midi.tracks
    )
    return {
        "seconds": round(midi.length, 3),
        "tracks_with_notes": tracks_with_notes,
        "note_on_count": note_on_count,
        "ticks_per_beat": midi.ticks_per_beat,
    }

この結果が前回と同じなら、出力構造に大きな回帰がないかを素早く確認できます。ただし、18ノートがすべて正しいのか、同じ18ノートを重複検出したのかは、別の評価が必要です。

3. 同じ抜粋でノートイベントを比較する

方式Aには単音メロディ、方式Bには完成済みのミックスを与える、という比較は成立しません。評価用の抜粋を固定し、各方式へ同じ入力を渡します。

比較対象は最低でも次の四つです。

  • pitch: MIDIノート番号
  • onset: ノート開始時刻
  • offset: ノート終了時刻
  • velocity: 強さ

正解MIDIがある場合は、ノート単位のprecisionとrecallを計算できます。その際は、onsetの許容幅やoffsetの扱いも結果と一緒に保存します。正解MIDIがない場合は、主要フレーズの保持、余分な短音、欠落、オクターブ誤りを人手で分類し、単一の「精度」に潰さない方が原因を追いやすくなります。

4. 編集コストを独立した指標にする

音楽制作では、採点値が少し高い出力より、修正箇所がまとまっている出力の方が使いやすいことがあります。そこで次も記録します。

  • 削除した余分なノート数
  • 追加した欠落ノート数
  • タイミングを直したノート数
  • トラック整理にかかった時間
  • DAWへ持ち込める状態までの合計時間

この編集ログは、モデルの性能だけでなく、前処理や後処理の改善点も示します。

公開例をどう読むか

公開されている固定ベンチマークでは、PureMIDI所有の合成デモと手修正前のMIDIについて、入力・出力ハッシュと構造値が掲載されています。

2026年8月25日に確認したfixed benchmark v1では、同じ単音メロディを使ったWAVと192 kbps MP3の例が、ともに17.84秒、1トラック、18ノートです。一方、短い混合WAVの例は31.77秒、8トラック、113ノートです。

この数字から「WAVとMP3の精度が同じ」「113ノートが正解」とは言えません。確認できるのは、公開された限定入力に対する出力構造と、後から同じファイルを再確認できることです。そこから先は、音程・開始時刻・長さ・編集コストを別々に評価します。

最小の評価レコード

最終的には、一回の変換を次のようなレコードとして保存すると追跡しやすくなります。

{
  "input_sha256": "...",
  "output_sha256": "...",
  "input_format": "wav",
  "route": "single_part",
  "duration_seconds": 17.84,
  "tracks_with_notes": 1,
  "note_on_count": 18,
  "onset_tolerance_ms": 50,
  "manual_deletions": 0,
  "manual_additions": 0,
  "edit_minutes": 0
}

評価の価値は、大きな数字を一つ出すことではなく、後から同じ条件を再現し、どの段階で結果が変わったかを説明できることにあります。

参考資料

開示:この記事はPureMIDIの公開ベンチマークを限定例として使用しています。記事の中心は製品比較ではなく、音声→MIDI評価を再現可能にする手順です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?