OpenSiv3Dでwhisper.cppを使ってみる

はじめに

この記事は前回の記事の続きの記事です 前回の記事ではwhisper.cppのGPU付きでのビルドをしました。

whisper.cppの静的ライブラリを作成する

whisper.cppの静的ライブラリを作成するために、以下のcmakeコマンドを実行します。

cmake -S . -B ./build -A x64 -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF

今回は静的ライブラリを使っていきたいので、上記のようなコマンドを実行しました。

参考

https://github.com/ggerganov/whisper.cpp/issues/212

また、静的ライブラリを生成するために、ランタイムライブラリを変更しなければなりません。

ビルドの準備

ソリューションエクスプローラーから bench, common, ggml, ggml-base, ggml-cpu, main, quantize, server, whisperを選択し、

whisper.cpp ソリューションエクスプローラー画像

プロパティから構成プロパティ > C/C++ > コード生成 > ランタイムライブラリRelease構成ではマルチスレッドDLL(/MD)からマルチスレッド(/MT)Debug構成ではマルチスレッドデバッグDLL(/MDd)からマルチスレッドデバッグ(/MTd)に変更します。

次に、ggml-cudaのプロパティから 構成プロパティ > CUDA C/C++ > Host > Runtime Libraryを上記と同じように、 Release構成ではマルチスレッドDLL(/MD)からマルチスレッド(/MT)Debug構成ではマルチスレッドデバッグDLL(/MDd)からマルチスレッドデバッグ(/MTd)に変更します。

それぞれ済んだら、ウィンドウ上部のメニューバーからビルド > バッチビルドを選択します。その後、ALL_BUILDDebugReleaseそれぞれのビルドにチェックを入れ、ビルドをします。

バッチビルド

少し時間がかかりますが、気長に待ちましょう。

OpenSiv3Dプロジェクトを作成する

公式サイトから、手順通りにプロジェクトを作成してください。

インクルードディレクトリの追加

まず、構成がすべての構成になっていることを確認します。

次に、プロジェクトのプロパティから 構成プロパティ > C/C++ > 全般 > 追加のインクルードディレクトリ に以下を追加します

whisper.cpp/include
whisper.cpp/ggml/include

ライブラリディレクトリの追加

構成をDebugに変更し 構成プロパティ > リンカー > 全般 > 追加のライブラリディレクトリ に以下を追加します。

whisper.cpp/build/src/
whisper.cpp/build/ggml/src/

依存ファイルの追加

構成をDebugのままで、 構成プロパティ > リンカー > 入力 > 追加の依存ファイル に以下を追加します

Debug/whisper.lib
Debug/ggml.lib
Debug/ggml-base.lib
Debug/ggml-cpu.lib
ggml-cuda/Debug/ggml-cuda.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cudart_static.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cublas.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cublasLt.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cuda.lib

また、構成をReleaseに変更し、同じく 構成プロパティ > リンカー > 入力 > 追加の依存ファイル に以下を追加します

Release/whisper.lib
Release/ggml.lib
Release/ggml-base.lib
Release/ggml-cpu.lib
ggml-cuda/Release/ggml-cuda.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cudart_static.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cublas.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cublasLt.lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64\cuda.lib

OpenSiv3Dでwhisper.cppを実行する

以下のコードを実行し、シーン真ん中のボタンを押すとコンソールに実行結果が表示されます!

#include <Siv3D.hpp> // Siv3D v0.6.15
#include <whisper.h>

String getTimestampString(const int64& t) {
    const Milliseconds ms{ t * 10 };

    return U"{:0>2d}:{:0>2d}:{:0>2d}.{:3d}"_fmt(
        DurationCast<Hours>(ms).count() % 24,
        DurationCast<Minutes>(ms).count() % 60,
        DurationCast<Seconds>(ms).count() % 60,
        ms.count() % 1000
    );
}

void Main() {
    // モデルのパス
    const FilePath modelPath = UR"(C:\Users\tas9n\Desktop\whisper_test\ggml-base.en.bin)";

    // 音声ファイルのパス
    const FilePath audioPath = UR"(C:\Users\tas9n\Desktop\whisper_test\test.wav)";

    whisper_context_params params = whisper_context_default_params();

    // コンテキストの作成
    whisper_context* ctx = whisper_init_from_file_with_params(modelPath.narrow().c_str(), params);

    if (ctx == nullptr) {
        whisper_free(ctx);

        throw Error{ U"コンテキストの作成に失敗しました。モデルパスなどを確認してください。" };
    }

    Wave wav{ audioPath };

    if (wav.isEmpty()) {
        whisper_free(ctx);

        throw Error{ U"音声ファイルが無効です。" };
    }

    wav.setSampleRate(16000);

    Array<float> samples;

    for (auto& sample : wav) {
        samples << (sample.right + sample.left) / 2;
    }

    // 推論
    whisper_full_params fullParams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
    fullParams.language = "en";

    while (System::Update()) {
        if (SimpleGUI::ButtonAt(U"実行", Scene::CenterF())) {
            if (whisper_full(ctx, fullParams, samples.data(), samples.size()) != 0) {
                Print << U"失敗";
                continue;
            }

            // データの取得
            const int32 segmentCount = whisper_full_n_segments(ctx);

            for (int32 i : step(segmentCount)) {
                const int64 from = whisper_full_get_segment_t0(ctx, i);
                const int64 to = whisper_full_get_segment_t1(ctx, i);

                const char* rawText = whisper_full_get_segment_text(ctx, i);

                const String text = Unicode::FromUTF8(rawText);

                Console << U"[{} --> {}]: {}"_fmt(getTimestampString(from), getTimestampString(to), text);
            }
        }
    }

    whisper_free(ctx);
}

まとめ

今回はOpenSiv3Dでwhisper.cppを使ってみました。 2年前にBulletを使ったのが今回のビルドの際に役立ちましたのでよかったらこっちの記事も読んでください😊

また、前回の記事では

動画編集などの助けになればいいと考え、字幕生成ツールを作ろうとしたといった背景があります。

といっていましたので、次回は字幕生成ツールを作成しようかなと思います。

ブログ一覧に戻る