Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

#VOICEVOX Core 0.14.1のScalaバインディング『voicevoxcore4s』をリリースしました

掲題の通りです。

皆様はVOICEVOXをご存知でしょうか。特に説明は不要と思いますが・・・

voicevox.hiroshiba.jp

テキスト読み上げソフトウェアなのですが、キャラクターなどの創作文化と合わさって大きなエコシステムを形成している面白いシステムです。ライセンスも比較的自由なので、関連したソフトウェアがたくさん開発されています。

VOICEVOXの3層構造

VOICEVOXは3つの層で構成されています。

  • エディター
  • エンジン
  • コア

エディターはエンドユーザが触るGUIアプリケーションです。だいたいの人はここを触っています。

エンジンはPythonで書かれたRESTfulなHTTPサーバです。エディター等からリクエストを受け取って、HTTPレスポンスとしてWAVファイルを返します。

最深部がコアです。コアはRustで書かれており、C APIを提供しています。あらかじめ同梱されたキャラごとのモデルファイルとONNXRuntimeを使ってニューラルネットワークによる音声合成を実行し、メモリ空間として(byte**を経由して)WAVファイルを返します。

詳細は以下のページを見るのが良いでしょう。

github.com

コアを呼び出す

前述の通り、コアを直接呼び出したほうが効率的な局面もあります。私が開発しているZMMは、大量の音声合成を並行して行うため、直接コアを呼び出す方針で実装を進めています(現在はエンジンを呼び出しています)。またこうすることで依存するコンポーネントが減り、エンドユーザにインストールしてもらいやすくなります。

www.3qe.us

ただし言語に依存しないHTTPを経由していたエンジンとは異なり、コアはC APIによる通信を行うため、各言語で使用するためにはバインディングが必要となります。

voicevoxcore4s

今回私が制作したのはScala向けのVOICEVOX Coreバインディング、voicevoxcore4sです。

github.com

現在最新のVOICEVOX Core 0.14.1に対応しており、ネイティブライブラリを同梱したJARファイルをリリース済みのため、すぐにサンプルコードを実行可能です。

以下の手順で、JARに同梱してあるテストプログラムを実行可能です:

$ mkdir voicevoxcore4s
$ cd voicevoxcore4s
$ wget https://github.com/windymelt/voicevoxcore4s/releases/download/v0.14.1/voicevoxcore4s-linux-x64-cpu-assembly-0.14.1.jar
$ java -jar voicevoxcore4s-linux-x64-cpu-assembly-0.14.1.jar

するとローカルディレクトリにライブラリが展開され、result.wavが出力されます。

自分のマシンでしか動作を確認していないため、動作報告をいただけると非常に喜びます。

sbtを使って依存性を定義すると、以下のようなコードで音声合成が可能です:

import com.sun.jna.ptr.{PointerByReference, IntByReference}
import java.io.FileOutputStream

val dictionaryDirectory = Util.extractDictFiles()
Util.extractModels()
Util.extractAndLoadLibraries()

val core = Core()

val initializeOptions = core.voicevox_make_default_initialize_options()
initializeOptions.open_jtalk_dict_dir = dictionaryDirectory
initializeOptions.acceleration_mode =
  Core.VoicevoxAccelerationMode.VOICEVOX_ACCELERATION_MODE_CPU.code

val initialized = core.voicevox_initialize(initializeOptions)
if (initialized == Core.VoicevoxResultCode.VOICEVOX_RESULT_OK.code) {
  val loadResult = core.voicevox_load_model(2) // metan
  val (wl, wav) = (new IntByReference(), new PointerByReference())
  val ttsOpts = core.voicevox_make_default_tts_options()
  ttsOpts.kana = false

  val tts = core.voicevox_tts(
    "こんにちは、世界",
    2, // metan
    ttsOpts,
    wl,
    wav
  )
  if (tts == Core.VoicevoxResultCode.VOICEVOX_RESULT_OK.code) {
    val resultPtr = wav.getValue()
    val resultArray = resultPtr.getByteArray(0, wl.getValue())
    val fs = new FileOutputStream("./result.wav")
    fs.write(resultArray)
    fs.close()
    core.voicevox_wav_free(resultPtr)
  } else {
    println(s"tts failed: $tts")
  }

  core.voicevox_finalize()
}

今のところ生のC APIの仕様が露出していますが、さらに別ライブラリでScala風の書き味に仕上げたり、Cats Effect 3を使った非同期処理への対応を行う予定です。

やっていないこと

いったん動くものを完成させたかったため、プラットフォーム対応などを大幅に省略しています。

  • GPU対応
  • Windows/macOS対応
  • x86_64以外のプラットフォーム対応

今後、リクエストに応じて随時対応させていく予定です。

前回記事

前回の記事では呼び出すだけでしたが、今回はCoreのバージョンを最新に追従させ、JARファイルのリリースまでこぎつけました。大幅にパワーアップしています。

blog.3qe.us

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?