0
1

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に変換するWebアプリを作った話 〜ライブラリ選定の試行錯誤〜

0
Last updated at Posted at 2026-05-15

はじめに

「耳コピが大変だからAIに任せたい」

そんな動機から、音声ファイル(MP3・WAV)をMIDIに変換するWebアプリを作りました。
単純に見えてライブラリ選定で何度もつまずいたので、その経緯をまとめます。

技術スタック(最終構成)

  • フロントエンド:React(Vite)
  • バックエンド:FastAPI(Python 3.11)
  • 音源分離:Demucs(Meta)
  • MIDI変換:Basic Pitch(Spotify)
  • テンポ・キー検出:librosa

アプリの概要

完成したアプリは2つのページで構成されています。

MIDI変換ページ

  1. MP3/WAVをアップロード
  2. 分離パターンを選択(シンプル・標準・詳細)
  3. 変換開始 → combined.mid をダウンロード

テンポ・キー解析ページ

  • 音声ファイルをアップロードするだけでテンポ(BPM)とキーを素早く表示

image.png


ライブラリ選定の試行錯誤

MIDI変換:librosa.pyin → Basic Pitch

最初に試したのは librosapyin 関数によるピッチ検出です。

f0, voiced_flag, _ = librosa.pyin(
    audio,
    fmin=librosa.note_to_hz("C2"),
    fmax=librosa.note_to_hz("C7"),
    sr=sr,
)

結果:使えなかった

pyin は単音楽器(ボーカルや単音フルートなど)向けのアルゴリズムです。
バンドやオーケストラのような複数の音が重なる楽曲には対応しておらず、出力されたMIDIは「曲としてみなせないレベル」でした。


次に採用したのが Basic Pitch(Spotify製)です。

https://github.com/spotify/basic-pitch

Basic Pitchはニューラルネットワークベースのピッチ検出ライブラリで、複音(和音)に対応しています。
ピアノやギターのコードも検出できるのが大きな強みです。

from basic_pitch.inference import predict

_, midi_data, _ = predict(
    wav_path,
    onset_threshold=0.4,   # 音符の検出感度
    frame_threshold=0.3,   # 短い音も拾う
    minimum_note_length=60, # ノイズ除去(ms)
    melodia_trick=True,    # メロディ強調フィルター
)
midi_data.write(output_path)

結果:大幅に改善

単音しか拾えなかった pyin と比べ、和音・複音が正しく検出されるようになりました。
完璧ではありませんが、曲として認識できるレベルのMIDIが出力されます。


Python 3.13 vs 3.11 の壁

Basic Pitchを導入しようとしたところ、Python 3.13では動作しないという問題に直面しました。

ERROR: No matching distribution found for tensorflow<2.15.1,>=2.4.1

Basic PitchはTensorFlowに依存しており、TensorFlow 2.15以下はPython 3.11までしか対応していません。
Python 3.13では pkg_resources の仕様変更により、ビルド自体が失敗します。

解決策:Python 3.11の仮想環境を別途作成

# Python 3.11をインストール後
py -3.11 -m venv venv311
venv311\Scripts\pip install basic-pitch

既存のPython 3.13環境には影響せず、FastAPIやDemucsも3.11環境に移行することで解決しました。


音源分離:Demucs の導入

バンドサウンドをそのままBasic Pitchにかけると、複数の楽器音が混在して精度が落ちます。
そこで Demucs(Meta製)で楽器ごとに音源を分離してからMIDI変換する2段構成にしました。

https://github.com/facebookresearch/demucs

from demucs.pretrained import get_model
from demucs.apply import apply_model

model = get_model("htdemucs")
model.to("cuda")  # GPU使用

wav_tensor = torch.tensor(audio).unsqueeze(0).to("cuda")
with torch.no_grad():
    sources = apply_model(model, wav_tensor)[0]
# sources: [drums, bass, other, vocals]

使用モデルと分離パターン

モデル 分離パート
htdemucs drums, bass, other, vocals
htdemucs_6s drums, bass, guitar, piano, other, vocals

ドラムはMIDI変換に向かないため全パターンで除外し、残りのパートをそれぞれBasic Pitchにかけて1つのMIDIに統合しています。

combined_midi = pretty_midi.PrettyMIDI()

for stem in ["vocals", "bass", "other"]:
    # パートごとにWAVを保存してBasic Pitchで変換
    _, midi_data, _ = predict(wav_path, ...)
    for instrument in midi_data.instruments:
        instrument.program = INSTRUMENT_PROGRAMS[stem]
        combined_midi.instruments.append(instrument)

combined_midi.write("combined.mid")

テンポ・キー検出:librosa

MIDI変換とは独立した解析機能として、librosa でテンポとキーを検出しています。
こちらは単純な統計処理なので精度・速度ともに問題ありません。

# テンポ検出
tempo, _ = librosa.beat.beat_track(y=audio, sr=sr)
tempo_val = float(np.atleast_1d(tempo)[0])  # 3.13対応のため atleast_1d を使用

# キー検出(クロマグラム)
chroma = librosa.feature.chroma_cqt(y=audio, sr=sr)
key_idx = int(np.argmax(chroma.mean(axis=1)))
key = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"][key_idx]

注意:librosa 0.11以降、beat_track の戻り値がスカラーではなく配列になっています。
float(tempo) ではなく float(np.atleast_1d(tempo)[0]) とする必要があります。


ライブラリ比較まとめ

用途 最初に試したもの 問題点 採用したもの
MIDI変換 librosa(pyin) 単音のみ対応・複音に弱い Basic Pitch(Spotify)
音源分離 なし(直接変換) 複数楽器が混在して精度低下 Demucs(Meta)
テンポ・キー検出 librosa 問題なし librosa(継続使用)

つまずきポイントまとめ

  1. librosa.pyinは単音専用:バンドサウンドには使えない
  2. Basic PitchはPython 3.13非対応:3.11の仮想環境を別途作成する必要がある
  3. librosa 0.11のbeat_track戻り値変更atleast_1d で対処
  4. 音源を混合してからBasic Pitchにかけると精度が落ちる:パートごとに個別変換が正解

おわりに

音声→MIDI変換は「やってみると思ったより難しい」領域でした。
特にBasic PitchのPython 3.13非対応は盲点で、仮想環境を分けることで解決しました。

精度はまだ完璧ではありませんが、Basic Pitch + Demucsの組み合わせで実用的なレベルには達しています。
同じことをやろうとしている方の参考になれば幸いです。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?