前回、録音した音声にSwiftF0で疑似ラベルを付けて、決定木を学習することを試した。
学習したモデルを使うことで、アコースティックギター、エレキギター、エレキベースで、安定してピッチ推定が行えるようになった。
ギター、ベース以外にも様々な楽器のピッチ推定精度を上げるために、様々な楽器の複数のピッチでの音声データが欲しい。
物理的に楽器を鳴らしてマイクで収録するのは、非常にコストと時間がかかるため、VST2 インストゥルメント(VSTi)を使うことを考える。
VST2 インストゥルメント(VSTi)
CubaseなどのDAWで読み込みできる楽器のプラグインである。
様々な楽器のVST2 インストゥルメントが販売されている。
最近はVST3に移行している。
Native InstrumentsのKontaktは、プロの音楽制作現場で業界標準として使用されているサンプルベースのソフトウェア音源である。
膨大な音色が用意されている。
だいぶ古いバージョンだが、Kontakt5を購入しているので、Kontakt5を使って訓練データを生成する。
VSTiが扱えるPythonライブラリ
VSTiが扱えるPythonライブラリを探したところ、DawDreamerで、VST インストゥルメント/エフェクトの読み込み・処理が可能であることがわかった。
エフェクトにも対応しているので、EQで加工するなどしてデータ拡張することもできる。
なお、WindowsではPython 3.11までしか対応していないので、uvでPythonバージョン指定でインストールした。
再生プログラム
VST インストゥルメントを読み込んで、WAVファイルに保存するサンプルプログラムは以下の通り。
import os
import numpy as np
import soundfile as sf
import dawdreamer as daw
SAMPLE_RATE = 44100
BUFFER_SIZE = 256
KONTAKT_DLL = r"C:\Program Files\Native Instruments\VSTPlugins 64 bit\Kontakt 5.dll"
STATE_PATH = r".\kontakt5_instrument.state" # 一度作ると以後使い回せる
OUT_WAV = r".\out_16bit.wav"
RENDER_SEC = 6.0
engine = daw.RenderEngine(SAMPLE_RATE, BUFFER_SIZE)
engine.set_bpm(120.0)
kontakt = engine.make_plugin_processor("Kontakt5", KONTAKT_DLL)
# --- 1) 音色ロード済みstateが無ければ、UIで手動ロードしてstate保存 ---
if not os.path.exists(STATE_PATH):
print("STATEが無いのでKontakt UIを開きます。Kontakt上でNKI等をロードしてからUIを閉じてください。")
kontakt.open_editor() # UIが開く(閉じた後に復帰する想定)
kontakt.save_state(STATE_PATH)
print(f"Saved state -> {STATE_PATH}")
# --- 2) stateをロードして、MIDIを流してレンダリング ---
kontakt.load_state(STATE_PATH)
kontakt.add_midi_note(60, 100, 0.0, 2.0)
kontakt.add_midi_note(64, 100, 1.0, 1.5)
kontakt.add_midi_note(67, 100, 2.5, 2.0)
engine.load_graph([(kontakt, [])])
engine.render(RENDER_SEC)
audio = engine.get_audio() # shape: (channels, samples)
st = audio[:2, :]
# (samples, channels) にして 16-bit PCM で書く
st_sf = np.clip(st.T, -1.0, 1.0).astype(np.float32)
sf.write(OUT_WAV, st_sf, SAMPLE_RATE, subtype="PCM_16")
注意点
音色指定
音色は、UIで選択する必要がある。
調べた限りではコードから指定する方法はなかった。
一度選択するとstateを保存して、次回からはそのsateをロードできる。
出力チャンネル
出力は、64チャンネルになる。
そのままWAVに保存しても再生できないため、ch1-2を抽出している。
まとめ
PythonライブラリDawDreamerでVSTiを制御しWAVを書き出す方法について記載した。
次はフィルタを適用する方法を調べたい。