前回、Pythonで試したSwiftF0の推論を、WindowsのC++プログラムでリアルタイムに行う方法を検討した。
SwiftF0のモデル
SwiftF0のモデルは、ONNXで公開されているので、それをそのまま使うことを検討する。
Netronで、ONNXモデルを確認すると、STFTもONNXで処理されるようになっている。
STFTオペレータはopset 17から追加されている。

窓関数もこのSTFTオペレータで適用される。
そのため、音声の前処理は必要なく、そのままモデルに渡せばよい。
WindowsでのONNXの推論
Windows App SDK に含まれる Windows ML は、ONNXRuntimeを内蔵している。
そのため、ヘッダーをincludeするだけで追加のライブラリなしで、ONNXRuntimeを使って推論処理を実装できる。
#include <winml/onnxruntime_cxx_api.h>
実装
GPT-Codex-5.3を使って、リアルタイムピッチ解析を実装した。
SwiftF0でリアルタイムにピッチ検出するプログラムを、WinPitchDetectionフォルダにあるC++/WinRT(WinUI3)のプロジェクトに実装してください。 ### 条件 - WASAPI Capture のイベント駆動で音声入力する(WASAPI共有モード) - サンプリングレート16kHz、モノラル、ビット深度24 or 16 - SwiftF0のONNXモデルはAsstesに追加済み(ms-appx:///model.onnx) - Windows App SDK に含まれる Windows MLでONNXの推論を行う - 推論処理はPythonの実装を参考にする - 横軸を時間、縦軸をピッチ(音階スケール)としてグラフを描画 - 録音中グラフを横スクロールする - SwapChainPanelで描画領域を作る。文字の描画にはDirectWriteを使用 - ディスプレイのDPIのスケールを正しく処理すること - D2D COM オブジェクトを確実に解放すること(winrt::com_ptr<>を使用) - ピッチ検出処理は再利用可能なようにソースを分割して実装 ### 参考 - samples/swift_f0: SwiftF0の推論のPython実装 - SwiftF0のリポジトリ: https://github.com/lars76/swift-f0
はじめ、弦をミュートした後に、オクターブエラーが発生した。
Pythonの推論処理でも試したが、同様に発生する。

無音区間はモデルに渡さない方がよいことがわかったので、音量しきい値を追加することにした。
-50dBでカットするとオクターブエラーが発生しなくなった。
実行結果
ギターの各弦のピッチを検出した結果は以下の通り。

安定して検出できている。
まとめ
Windowsで、SwiftF0のONNXモデルを推論する処理を実装した。
Windows App SDK内蔵のWindows ML(ONNXRuntime)を使うことで追加ライブラリなしで実装できた。
次は、チューナーアプリのアルゴリズムをSwiftF0に置き換えたい。
追記
その後、チューナーアプリに組み込んでみたが、キーボードのピアノの音を入力したところ、音階により20cent近くの誤差があることがわかった。
誤差が大きくチューナー用途では実用的とは言えない。
SwiftF0は教師データ作成に活用して、チューナーに直接組み込むのは見送ることにする。