diff --git a/.github/actions/create-venv/action.yml b/.github/actions/create-venv/action.yml index c8883621e..484ad892f 100644 --- a/.github/actions/create-venv/action.yml +++ b/.github/actions/create-venv/action.yml @@ -1,3 +1,6 @@ +name: Create venv +description: Pythonの仮想環境を作成し、$PATHと$VIRTUAL_ENVを設定する。 + runs: using: composite steps: diff --git a/.github/actions/rust-toolchain-from-file/action.yml b/.github/actions/rust-toolchain-from-file/action.yml index d82c9c159..917faed3c 100644 --- a/.github/actions/rust-toolchain-from-file/action.yml +++ b/.github/actions/rust-toolchain-from-file/action.yml @@ -1,3 +1,6 @@ +name: rustup toolchain install from file +description: rust-toolchainファイルをもとにRustのツールチェーンをインストールする。 + inputs: targets: required: false diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index caabb9d78..1b468a33a 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -443,7 +443,7 @@ jobs: - name: Set up Rust uses: ./.github/actions/rust-toolchain-from-file - name: Set up Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: java-version: "17" distribution: "adopt" diff --git a/.github/workflows/generate_document.yml b/.github/workflows/generate_document.yml index e3890d82a..37c39a1dd 100644 --- a/.github/workflows/generate_document.yml +++ b/.github/workflows/generate_document.yml @@ -21,7 +21,7 @@ jobs: with: python-version: "3.8" - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: java-version: "11" distribution: "adopt" diff --git a/.github/workflows/java_lint.yml b/.github/workflows/java_lint.yml index c75222912..ad408e3a7 100644 --- a/.github/workflows/java_lint.yml +++ b/.github/workflows/java_lint.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v4 with: java-version: "11" distribution: "adopt" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4ff92a84b..0496eebdb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -277,13 +277,6 @@ jobs: pip install --upgrade poetry poetry install --with dev --with test - run: cargo build -p test_util -vv # build scriptにより/crates/test_util/data/の生成 - # `macos-latest`(=`macos-12`)で次の問題が発生するため、それに対するワークアラウンド - # https://github.com/VOICEVOX/voicevox_core/issues/653#issuecomment-1782108410 - - if: startsWith(matrix.os, 'mac') - name: Build open_jtalk-sys - run: | - poetry run -- cargo build -p voicevox_core_python_api -vv || true - [ -n "$(find ../../target/debug/deps -name 'libopen_jtalk_sys-*.rlib')" ] - run: poetry run maturin build --locked - run: poetry run maturin develop --locked - name: 必要なDLLをコピーしてpytestを実行 @@ -296,7 +289,7 @@ jobs: - name: Exampleを実行 run: | for file in ../../example/python/run{,-asyncio}.py; do - poetry run python "$file" ../../model/sample.vvm --dict-dir ../test_util/data/open_jtalk_dic_utf_8-1.11 + poetry run python "$file" ../test_util/data/model/sample.vvm --dict-dir ../test_util/data/open_jtalk_dic_utf_8-1.11 done build-and-test-java-api: strategy: @@ -312,7 +305,7 @@ jobs: - name: Set up Rust uses: ./.github/actions/rust-toolchain-from-file - name: Set up Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: java-version: "11" distribution: "adopt" diff --git a/Cargo.lock b/Cargo.lock index 6222c0f39..4015b7e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,26 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher 0.2.5", -] - [[package]] name = "aes" version = "0.7.5" @@ -44,45 +24,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug", ] -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes 0.6.0", - "cipher 0.2.5", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher 0.2.5", - "opaque-debug", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -196,27 +142,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.102", -] - -[[package]] -name = "async-channel" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - [[package]] name = "async-compression" version = "0.4.6" @@ -230,97 +155,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 1.8.0", - "futures-lite 1.12.0", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite 1.12.0", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" -dependencies = [ - "autocfg", - "concurrent-queue", - "futures-lite 1.12.0", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 1.12.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" - [[package]] name = "async-trait" version = "0.1.57" @@ -340,17 +174,11 @@ checksum = "527207465fb6dcafbf661b0d4a51d0d2306c9d0c2975423079a6caa807930daf" dependencies = [ "async-compression", "crc32fast", - "futures-lite 2.2.0", + "futures-lite", "pin-project", "thiserror", ] -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - [[package]] name = "atty" version = "0.2.14" @@ -383,12 +211,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.0" @@ -413,7 +235,7 @@ version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6720a8b7b2d39dd533285ed438d458f65b31b5c257e6ac7bb3d7e82844dd722" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -429,6 +251,29 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools 0.11.0", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.48", + "which", +] + [[package]] name = "binstall-tar" version = "0.4.39" @@ -447,13 +292,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "block-buffer" -version = "0.9.0" +name = "bitflags" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -464,20 +306,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand 1.8.0", - "futures-lite 1.12.0", - "once_cell", -] - [[package]] name = "bstr" version = "1.2.0" @@ -502,12 +330,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.1.0" @@ -535,12 +357,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - [[package]] name = "camino" version = "1.1.6" @@ -616,15 +432,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.3.0" @@ -636,9 +443,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -652,7 +459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_lex 0.2.4", "indexmap 1.9.1", "strsim", @@ -667,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b1a0a4208c6c483b952ad35c6eed505fc13b46f08f631b81e828084a9318d74" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex 0.3.0", "once_cell", @@ -764,7 +571,7 @@ version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ - "bytes 1.1.0", + "bytes", "memchr", ] @@ -774,7 +581,7 @@ version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "318d6c16e73b3a900eb212ad6a82fc7d298c5ab8184c7a9998646455bc474a16" dependencies = [ - "bitflags", + "bitflags 1.3.2", "concolor-query", "is-terminal", ] @@ -785,15 +592,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317" -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - [[package]] name = "console" version = "0.15.4" @@ -807,12 +605,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -825,23 +617,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.0", - "hkdf", - "hmac 0.10.1", - "percent-encoding", - "rand 0.8.5", - "sha2 0.9.9", - "time 0.2.27", - "version_check", -] - [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -857,12 +632,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crc32fast" version = "1.3.2" @@ -925,16 +694,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "cstr" version = "0.2.11" @@ -955,46 +714,6 @@ dependencies = [ "syn 1.0.102", ] -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher 0.2.5", -] - -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.56+curl-7.83.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093e169dd4de29e468fa649fbae11cdcd5551c81fe5bf1b0677adad7ef3d26f" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "cxx" version = "1.0.86" @@ -1105,7 +824,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.102", ] @@ -1121,32 +840,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.3", + "block-buffer", "crypto-common", "subtle", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "doc-comment" version = "0.3.3" @@ -1159,7 +863,7 @@ version = "0.0.0" dependencies = [ "anyhow", "binstall-tar", - "bytes 1.1.0", + "bytes", "clap 4.0.10", "flate2", "fs-err", @@ -1331,12 +1035,6 @@ dependencies = [ "libc", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "eyre" version = "0.6.8" @@ -1384,17 +1082,6 @@ dependencies = [ "miniz_oxide 0.6.2", ] -[[package]] -name = "flume" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" -dependencies = [ - "futures-core", - "futures-sink", - "spinning_top", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1468,21 +1155,6 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand 1.8.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.2.0" @@ -1553,17 +1225,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.7" @@ -1572,17 +1233,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "ghash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" -dependencies = [ - "opaque-debug", - "polyval", + "wasi", ] [[package]] @@ -1608,25 +1259,13 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "gloo-timers" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "h2" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -1687,33 +1326,13 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac 0.10.1", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.5", + "digest", ] [[package]] @@ -1722,7 +1341,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "itoa", ] @@ -1733,47 +1352,11 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes 1.1.0", + "bytes", "http", "pin-project-lite", ] -[[package]] -name = "http-client" -version = "6.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "http-types", - "isahc", - "log", -] - -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel", - "async-std", - "base64 0.13.0", - "cookie", - "futures-lite 1.12.0", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", -] - [[package]] name = "httparse" version = "1.8.0" @@ -1801,7 +1384,7 @@ version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -1919,12 +1502,6 @@ version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - [[package]] name = "instant" version = "0.1.12" @@ -1973,29 +1550,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "isahc" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" -dependencies = [ - "bytes 0.5.6", - "crossbeam-utils", - "curl", - "curl-sys", - "flume", - "futures-lite 1.12.0", - "http", - "log", - "once_cell", - "slab", - "sluice", - "tracing", - "tracing-futures", - "url", - "waker-fn", -] - [[package]] name = "itertools" version = "0.10.5" @@ -2083,15 +1637,6 @@ dependencies = [ "simple_asn1", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2126,16 +1671,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" -[[package]] -name = "libnghttp2-sys" -version = "0.1.7+1.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "libtest-mimic" version = "0.6.0" @@ -2147,18 +1682,6 @@ dependencies = [ "threadpool", ] -[[package]] -name = "libz-sys" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "link-cplusplus" version = "1.0.7" @@ -2197,7 +1720,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", - "value-bag", ] [[package]] @@ -2254,16 +1776,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2296,7 +1808,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.42.0", ] @@ -2306,7 +1818,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" dependencies = [ - "rand 0.8.5", + "rand", ] [[package]] @@ -2334,7 +1846,7 @@ dependencies = [ "noisy_float", "num-integer", "num-traits", - "rand 0.8.5", + "rand", ] [[package]] @@ -2457,7 +1969,7 @@ dependencies = [ "arc-swap", "async-trait", "base64 0.21.0", - "bytes 1.1.0", + "bytes", "cfg-if", "chrono", "either", @@ -2514,7 +2026,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "open_jtalk" version = "0.1.25" -source = "git+https://github.com/VOICEVOX/open_jtalk-rs.git?rev=70c76bb54522830e92803038191bf533ba68ce85#70c76bb54522830e92803038191bf533ba68ce85" +source = "git+https://github.com/VOICEVOX/open_jtalk-rs.git?rev=e1940f3fd61a48bed5bbec8cd2645e13923b1f80#e1940f3fd61a48bed5bbec8cd2645e13923b1f80" dependencies = [ "camino", "open_jtalk-sys", @@ -2524,32 +2036,13 @@ dependencies = [ [[package]] name = "open_jtalk-sys" version = "0.16.111" -source = "git+https://github.com/VOICEVOX/open_jtalk-rs.git?rev=70c76bb54522830e92803038191bf533ba68ce85#70c76bb54522830e92803038191bf533ba68ce85" +source = "git+https://github.com/VOICEVOX/open_jtalk-rs.git?rev=e1940f3fd61a48bed5bbec8cd2645e13923b1f80#e1940f3fd61a48bed5bbec8cd2645e13923b1f80" dependencies = [ - "bindgen", + "bindgen 0.62.0", "cmake", "link-cplusplus", ] -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_pipe" version = "1.1.2" @@ -2674,7 +2167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2684,10 +2177,10 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.5", - "hmac 0.12.1", + "digest", + "hmac", "password-hash", - "sha2 0.10.6", + "sha2", ] [[package]] @@ -2738,41 +2231,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - -[[package]] -name = "polling" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" -dependencies = [ - "autocfg", - "cfg-if", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "polyval" -version = "0.4.5" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "portable-atomic" @@ -2833,6 +2301,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2857,12 +2335,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.78" @@ -2977,19 +2449,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -2997,18 +2456,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -3018,16 +2467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -3036,16 +2476,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.7", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -3082,7 +2513,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3091,7 +2522,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3151,7 +2582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" dependencies = [ "base64 0.13.0", - "bytes 1.1.0", + "bytes", "encoding_rs", "futures-core", "futures-util", @@ -3208,7 +2639,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -3220,7 +2651,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.102", ] @@ -3231,8 +2662,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88530b681abe67924d42cca181d070e3ac20e0740569441a9e35a7cedd2b34a4" dependencies = [ "quote", - "rand 0.8.5", - "rustc_version 0.4.0", + "rand", + "rustc_version", "syn 2.0.48", ] @@ -3248,22 +2679,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver", ] [[package]] @@ -3272,7 +2694,7 @@ version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno 0.2.8", "io-lifetimes", "libc", @@ -3286,7 +2708,7 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno 0.3.1", "io-lifetimes", "libc", @@ -3336,16 +2758,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -3377,27 +2789,12 @@ dependencies = [ "zeroize", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.164" @@ -3439,17 +2836,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror", -] - [[package]] name = "serde_spanned" version = "0.6.1" @@ -3485,7 +2871,7 @@ dependencies = [ "serde", "serde_json", "serde_with_macros", - "time 0.3.15", + "time", ] [[package]] @@ -3500,15 +2886,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.5" @@ -3517,26 +2894,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] @@ -3547,7 +2905,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest", ] [[package]] @@ -3584,7 +2942,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.15", + "time", ] [[package]] @@ -3596,17 +2954,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "sluice" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" -dependencies = [ - "async-channel", - "futures-core", - "futures-io", -] - [[package]] name = "smallvec" version = "1.13.1" @@ -3652,79 +2999,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spinning_top" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" -dependencies = [ - "lock_api", -] - -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.102", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.102", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.10.0" @@ -3782,29 +3062,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "surf" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "encoding_rs", - "futures-util", - "getrandom 0.2.7", - "http-client", - "http-types", - "log", - "mime_guess", - "once_cell", - "pin-project-lite", - "serde", - "serde_json", - "web-sys", -] - [[package]] name = "syn" version = "1.0.102" @@ -3878,17 +3135,19 @@ name = "test_util" version = "0.0.0" dependencies = [ "anyhow", - "async-std", - "async_zip", + "bindgen 0.69.4", + "camino", "flate2", "fs-err", - "futures-lite 2.2.0", + "indoc", + "libloading", "once_cell", + "reqwest", "serde", "serde_json", - "surf", "tar", "tokio", + "zip", ] [[package]] @@ -3935,21 +3194,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi", -] - [[package]] name = "time" version = "0.3.15" @@ -3960,17 +3204,7 @@ dependencies = [ "libc", "num_threads", "serde", - "time-macros 0.2.4", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "time-macros", ] [[package]] @@ -3979,19 +3213,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.102", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -4014,7 +3235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" dependencies = [ "autocfg", - "bytes 1.1.0", + "bytes", "libc", "mio", "num_cpus", @@ -4052,7 +3273,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "futures-sink", "pin-project-lite", @@ -4153,16 +3374,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.3" @@ -4228,15 +3439,6 @@ dependencies = [ "syn 1.0.102", ] -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -4270,16 +3472,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "untrusted" version = "0.7.1" @@ -4327,7 +3519,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ - "getrandom 0.2.7", + "getrandom", "serde", ] @@ -4337,22 +3529,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "value-bag" -version = "1.0.0-alpha.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -4393,7 +3569,9 @@ dependencies = [ "rstest_reuse", "serde", "serde_json", + "serde_with", "smallvec", + "strum", "tempfile", "test_util", "thiserror", @@ -4435,7 +3613,6 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", "tempfile", "test_util", "thiserror", @@ -4499,12 +3676,6 @@ dependencies = [ "libc", ] -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "walkdir" version = "2.3.3" @@ -4525,12 +3696,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -4632,15 +3797,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "which" version = "4.3.0" @@ -4935,17 +4091,17 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" dependencies = [ - "aes 0.7.5", + "aes", "byteorder", "bzip2", "constant_time_eq", "crc32fast", "crossbeam-utils", "flate2", - "hmac 0.12.1", + "hmac", "pbkdf2", - "sha1 0.10.5", - "time 0.3.15", + "sha1", + "time", "zstd", ] diff --git a/Cargo.toml b/Cargo.toml index 21b9a0ac9..69d924a16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,8 @@ anstream = { version = "0.5.0", default-features = false } anstyle-query = "1.0.0" anyhow = "1.0.65" assert_cmd = "2.0.8" -async-std = "1.12.0" async_zip = "=0.0.16" +bindgen = "0.69.4" binstall-tar = "0.4.39" bytes = "1.1.0" camino = "1.1.6" @@ -38,6 +38,7 @@ heck = "0.4.1" humansize = "2.1.2" indexmap = "2.0.0" indicatif = "0.17.3" +indoc = "2.0.4" inventory = "0.3.4" itertools = "0.10.5" jlabel = "0.1.2" @@ -69,7 +70,6 @@ serde_json = "1.0.85" serde_with = "3.3.0" smallvec = "1.13.1" strum = "0.24.1" -surf = "2.3.2" syn = "2.0.38" tar = "0.4.38" tempfile = "3.6.0" @@ -92,7 +92,7 @@ rev = "ebb9dcb9b26ee681889b52b6db3b4f642b04a250" [workspace.dependencies.open_jtalk] git = "https://github.com/VOICEVOX/open_jtalk-rs.git" -rev = "70c76bb54522830e92803038191bf533ba68ce85" +rev = "e1940f3fd61a48bed5bbec8cd2645e13923b1f80" # FIXME: iOS対応のpull request(https://github.com/wesleywiser/process_path/pull/16)がマージされる見込みが無いため [workspace.dependencies.process_path] diff --git a/crates/test_util/Cargo.toml b/crates/test_util/Cargo.toml index bea6e4d4e..d113b57ce 100644 --- a/crates/test_util/Cargo.toml +++ b/crates/test_util/Cargo.toml @@ -3,23 +3,25 @@ name = "test_util" edition.workspace = true [dependencies] -async_zip = { workspace = true, features = ["deflate"] } -futures-lite.workspace = true +libloading.workspace = true once_cell.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true -tokio = { workspace = true, features = ["fs", "io-util", "sync"] } [build-dependencies] anyhow.workspace = true -async-std = { workspace = true, features = ["attributes"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +bindgen.workspace = true +camino.workspace = true flate2.workspace = true fs-err.workspace = true +indoc.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["preserve_order"] } -surf.workspace = true +reqwest = { workspace = true, features = ["rustls-tls"] } tar.workspace = true +zip.workspace = true [lints.rust] -unsafe_code = "forbid" +unsafe_code = "allow" # C APIのbindgen rust_2018_idioms = "warn" diff --git a/crates/test_util/build.rs b/crates/test_util/build.rs index eae3ac286..79e3bc90e 100644 --- a/crates/test_util/build.rs +++ b/crates/test_util/build.rs @@ -1,33 +1,94 @@ use std::{ env, - path::{Path, PathBuf}, + io::{self, Cursor, Write as _}, + path::Path, }; -use anyhow::ensure; -use async_std::io::ReadExt as _; +use anyhow::{anyhow, ensure}; +use camino::{Utf8Path, Utf8PathBuf}; use flate2::read::GzDecoder; +use indoc::formatdoc; use tar::Archive; +use zip::{write::FileOptions, ZipWriter}; #[path = "src/typing.rs"] mod typing; const DIC_DIR_NAME: &str = "open_jtalk_dic_utf_8-1.11"; -#[async_std::main] +#[tokio::main] async fn main() -> anyhow::Result<()> { - let mut dist = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); - dist.push("data"); + let out_dir = &Utf8PathBuf::from(env::var("OUT_DIR").unwrap()); + let dist = &Utf8Path::new(env!("CARGO_MANIFEST_DIR")).join("data"); let dic_dir = dist.join(DIC_DIR_NAME); if !dic_dir.try_exists()? { - download_open_jtalk_dict(&dist).await?; - ensure!(dic_dir.exists(), "`{}` does not exist", dic_dir.display()); + download_open_jtalk_dict(dist.as_ref()).await?; + ensure!(dic_dir.exists(), "`{dic_dir}` does not exist"); } - generate_example_data_json(&dist)?; + create_sample_voice_model_file(out_dir, dist)?; + + generate_example_data_json(dist.as_ref())?; println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=src/typing.rs"); + + generate_c_api_rs_bindings(out_dir) +} + +fn create_sample_voice_model_file(out_dir: &Utf8Path, dist: &Utf8Path) -> anyhow::Result<()> { + const SRC: &str = "../../model/sample.vvm"; + + let files = fs_err::read_dir(SRC)? + .map(|entry| { + let entry = entry?; + let md = entry.metadata()?; + ensure!(!md.is_dir(), "directory in {SRC}"); + let mtime = md.modified()?; + let name = entry + .file_name() + .into_string() + .map_err(|name| anyhow!("{name:?}"))?; + Ok((name, entry.path(), mtime)) + }) + .collect::>>()?; + + let output_dir = &dist.join("model"); + let output_file = &output_dir.join("sample.vvm"); + + let up_to_date = fs_err::metadata(output_file) + .and_then(|md| md.modified()) + .map(|t1| files.iter().all(|&(_, _, t2)| t1 >= t2)); + let up_to_date = match up_to_date { + Ok(p) => p, + Err(e) if e.kind() == io::ErrorKind::NotFound => false, + Err(e) => return Err(e.into()), + }; + + if !up_to_date { + let mut zip = ZipWriter::new(Cursor::new(vec![])); + for (name, path, _) in files { + let content = &fs_err::read(path)?; + zip.start_file(name, FileOptions::default().compression_level(Some(0)))?; + zip.write_all(content)?; + } + let zip = zip.finish()?; + fs_err::create_dir_all(output_dir)?; + fs_err::write(output_file, zip.get_ref())?; + } + + fs_err::write( + out_dir.join("sample_voice_model_file.rs"), + formatdoc! {" + pub const SAMPLE_VOICE_MODEL_FILE_PATH: &::std::primitive::str = {output_file:?}; + + const SAMPLE_VOICE_MODEL_FILE_C_PATH: &::std::ffi::CStr = c{output_file:?}; + const VV_MODELS_ROOT_DIR: &::std::primitive::str = {output_dir:?}; + ", + }, + )?; + println!("cargo:rerun-if-changed={SRC}"); Ok(()) } @@ -37,13 +98,11 @@ async fn download_open_jtalk_dict(dist: &Path) -> anyhow::Result<()> { "https://github.com/r9y9/open_jtalk/releases/download/v1.11.1/{DIC_DIR_NAME}.tar.gz" ); - let req = surf::get(download_url); - let client = surf::client().with(surf::middleware::Redirect::default()); - let mut res = client.send(req).await.map_err(surf::Error::into_inner)?; + let res = reqwest::get(&download_url).await?; ensure!(res.status() == 200, "{}", res.status()); - let mut body_bytes = Vec::with_capacity(100 * 1024 * 1024); - res.read_to_end(&mut body_bytes).await?; - let dict_tar = GzDecoder::new(&body_bytes[..]); + + let bytes = res.bytes().await?; + let dict_tar = GzDecoder::new(&*bytes); let mut dict_archive = Archive::new(dict_tar); dict_archive.unpack(dist)?; @@ -120,3 +179,19 @@ fn generate_example_data_json(dist: &Path) -> anyhow::Result<()> { Ok(()) } + +fn generate_c_api_rs_bindings(out_dir: &Utf8Path) -> anyhow::Result<()> { + static C_BINDINGS_PATH: &str = "../voicevox_core_c_api/include/voicevox_core.h"; + static ADDITIONAL_C_BINDINGS_PATH: &str = "./compatible_engine.h"; + + bindgen::Builder::default() + .header(C_BINDINGS_PATH) + .header(ADDITIONAL_C_BINDINGS_PATH) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .dynamic_library_name("CApi") + .generate()? + .write_to_file(out_dir.join("c_api.rs"))?; + println!("cargo:rerun-if-changed={C_BINDINGS_PATH}"); + println!("cargo:rerun-if-changed={ADDITIONAL_C_BINDINGS_PATH}"); + Ok(()) +} diff --git a/crates/test_util/compatible_engine.h b/crates/test_util/compatible_engine.h new file mode 100644 index 000000000..254fd8161 --- /dev/null +++ b/crates/test_util/compatible_engine.h @@ -0,0 +1,28 @@ +#include + +bool initialize(bool use_gpu, int cpu_num_threads, bool load_all_models); + +bool load_model(int64_t speaker_id); + +bool is_model_loaded(int64_t speaker_id); + +void finalize(); + +const char *metas(); + +const char *supported_devices(); + +bool yukarin_s_forward(int64_t length, int64_t *phoneme_list, + int64_t *speaker_id, float *output); + +bool yukarin_sa_forward(int64_t length, int64_t *vowel_phoneme_list, + int64_t *consonant_phoneme_list, + int64_t *start_accent_list, int64_t *end_accent_list, + int64_t *start_accent_phrase_list, + int64_t *end_accent_phrase_list, int64_t *speaker_id, + float *output); + +bool decode_forward(int64_t length, int64_t phoneme_size, float *f0, + float *phoneme, int64_t *speaker_id, float *output); + +const char *last_error_message(); diff --git a/crates/test_util/src/lib.rs b/crates/test_util/src/lib.rs index 03e8309b8..f234d7f76 100644 --- a/crates/test_util/src/lib.rs +++ b/crates/test_util/src/lib.rs @@ -1,17 +1,23 @@ mod typing; -use async_zip::{base::write::ZipFileWriter, Compression, ZipEntryBuilder}; -use futures_lite::AsyncWriteExt as _; +include!(concat!(env!("OUT_DIR"), "/sample_voice_model_file.rs")); + +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_extern_crates, + clippy::missing_safety_doc, + clippy::too_many_arguments +)] +pub mod c_api { + include!(concat!(env!("OUT_DIR"), "/c_api.rs")); + + pub const SAMPLE_VOICE_MODEL_FILE_PATH: &std::ffi::CStr = super::SAMPLE_VOICE_MODEL_FILE_C_PATH; + pub const VV_MODELS_ROOT_DIR: &str = super::VV_MODELS_ROOT_DIR; +} + use once_cell::sync::Lazy; -use std::{ - collections::HashMap, - path::{Path, PathBuf}, -}; -use tokio::{ - fs::{self, File}, - io::AsyncReadExt, - sync::Mutex, -}; pub use self::typing::{ DecodeExampleData, DurationExampleData, ExampleData, IntonationExampleData, @@ -30,43 +36,3 @@ const EXAMPLE_DATA_JSON: &str = include_str!(concat!( pub static EXAMPLE_DATA: Lazy = Lazy::new(|| { serde_json::from_str(EXAMPLE_DATA_JSON).expect("failed to parse example_data.json") }); - -static PATH_MUTEX: Lazy>>> = - Lazy::new(|| Mutex::new(HashMap::default())); - -pub async fn convert_zip_vvm(dir: impl AsRef) -> PathBuf { - let dir = dir.as_ref(); - let output_file_name = dir.file_name().unwrap().to_str().unwrap().to_owned() + ".vvm"; - - let out_file_path = PathBuf::from(env!("OUT_DIR")) - .join("test_data/models/") - .join(output_file_name); - let mut path_map = PATH_MUTEX.lock().await; - if !path_map.contains_key(&out_file_path) { - path_map.insert(out_file_path.clone(), Mutex::new(())); - } - let _m = path_map.get(&out_file_path).unwrap().lock().await; - - if !out_file_path.exists() { - fs::create_dir_all(out_file_path.parent().unwrap()) - .await - .unwrap(); - let mut writer = ZipFileWriter::new(vec![]); - - for entry in dir.read_dir().unwrap().flatten() { - let entry_builder = ZipEntryBuilder::new( - entry.path().file_name().unwrap().to_str().unwrap().into(), - Compression::Deflate, - ); - let mut entry_writer = writer.write_entry_stream(entry_builder).await.unwrap(); - let mut file = File::open(entry.path()).await.unwrap(); - let mut buf = Vec::with_capacity(entry.metadata().unwrap().len() as usize); - file.read_to_end(&mut buf).await.unwrap(); - entry_writer.write_all(&buf).await.unwrap(); - entry_writer.close().await.unwrap(); - } - let zip = writer.close().await.unwrap(); - fs::write(&out_file_path, zip).await.unwrap(); - } - out_file_path -} diff --git a/crates/voicevox_core/Cargo.toml b/crates/voicevox_core/Cargo.toml index bd3456abb..5c8dd440d 100644 --- a/crates/voicevox_core/Cargo.toml +++ b/crates/voicevox_core/Cargo.toml @@ -32,9 +32,11 @@ open_jtalk.workspace = true ouroboros.workspace = true rayon.workspace = true regex.workspace = true -serde = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive", "rc"] } serde_json = { workspace = true, features = ["preserve_order"] } +serde_with.workspace = true smallvec.workspace = true +strum = { workspace = true, features = ["derive"] } tempfile.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["rt"] } # FIXME: feature-gateする diff --git a/crates/voicevox_core/src/__internal/doctest_fixtures.rs b/crates/voicevox_core/src/__internal/doctest_fixtures.rs index 426f6cd09..f314845fe 100644 --- a/crates/voicevox_core/src/__internal/doctest_fixtures.rs +++ b/crates/voicevox_core/src/__internal/doctest_fixtures.rs @@ -1,8 +1,11 @@ +use std::path::Path; + use camino::Utf8Path; use crate::{AccelerationMode, InitializeOptions}; pub async fn synthesizer_with_sample_voice_model( + voice_model_path: impl AsRef, open_jtalk_dic_dir: impl AsRef, ) -> anyhow::Result> { let syntesizer = crate::tokio::Synthesizer::new( @@ -13,11 +16,7 @@ pub async fn synthesizer_with_sample_voice_model( }, )?; - let model = &crate::tokio::VoiceModel::from_path(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../model/sample.vvm", - )) - .await?; + let model = &crate::tokio::VoiceModel::from_path(voice_model_path).await?; syntesizer.load_voice_model(model).await?; Ok(syntesizer) diff --git a/crates/voicevox_core/src/engine/open_jtalk.rs b/crates/voicevox_core/src/engine/open_jtalk.rs index 1ec737f95..88d16f381 100644 --- a/crates/voicevox_core/src/engine/open_jtalk.rs +++ b/crates/voicevox_core/src/engine/open_jtalk.rs @@ -181,9 +181,6 @@ pub(crate) mod blocking { njd: ManagedResource, jpcommon: ManagedResource, } - - // FIXME: open_jtalk-rs側で宣言する - unsafe impl Send for Resources {} } pub(crate) mod tokio { diff --git a/crates/voicevox_core/src/error.rs b/crates/voicevox_core/src/error.rs index 19d464d21..916964429 100644 --- a/crates/voicevox_core/src/error.rs +++ b/crates/voicevox_core/src/error.rs @@ -1,11 +1,12 @@ use crate::{ engine::{FullContextLabelError, KanaParseError}, user_dict::InvalidWordError, - StyleId, VoiceModelId, + StyleId, StyleType, VoiceModelId, }; //use engine:: use duplicate::duplicate_item; -use std::path::PathBuf; +use itertools::Itertools as _; +use std::{collections::BTreeSet, path::PathBuf}; use thiserror::Error; use uuid::Uuid; @@ -38,6 +39,7 @@ impl Error { LoadModelErrorKind::ReadZipEntry { .. } => ErrorKind::ReadZipEntry, LoadModelErrorKind::ModelAlreadyLoaded { .. } => ErrorKind::ModelAlreadyLoaded, LoadModelErrorKind::StyleAlreadyLoaded { .. } => ErrorKind::StyleAlreadyLoaded, + LoadModelErrorKind::InvalidModelFormat { .. } => ErrorKind::InvalidModelFormat, LoadModelErrorKind::InvalidModelData => ErrorKind::InvalidModelData, }, ErrorRepr::GetSupportedDevices(_) => ErrorKind::GetSupportedDevices, @@ -70,10 +72,14 @@ pub(crate) enum ErrorRepr { GetSupportedDevices(#[source] anyhow::Error), #[error( - "`{style_id}`に対するスタイルが見つかりませんでした。音声モデルが読み込まれていないか、読\ - み込みが解除されています" + "`{style_id}` ([{style_types}])に対するスタイルが見つかりませんでした。音声モデルが\ + 読み込まれていないか、読み込みが解除されています", + style_types = style_types.iter().format(", ") )] - StyleNotFound { style_id: StyleId }, + StyleNotFound { + style_id: StyleId, + style_types: &'static BTreeSet, + }, #[error( "`{model_id}`に対する音声モデルが見つかりませんでした。読み込まれていないか、読み込みが既\ @@ -117,6 +123,8 @@ pub enum ErrorKind { OpenZipFile, /// ZIP内のファイルが読めなかった。 ReadZipEntry, + /// モデルの形式が不正。 + InvalidModelFormat, /// すでに読み込まれている音声モデルを読み込もうとした。 ModelAlreadyLoaded, /// すでに読み込まれているスタイルを読み込もうとした。 @@ -165,6 +173,8 @@ pub(crate) enum LoadModelErrorKind { OpenZipFile, #[display(fmt = "`{filename}`を読み取れませんでした")] ReadZipEntry { filename: String }, + #[display(fmt = "モデルの形式が不正です")] + InvalidModelFormat, #[display(fmt = "モデル`{id}`は既に読み込まれています")] ModelAlreadyLoaded { id: VoiceModelId }, #[display(fmt = "スタイル`{id}`は既に読み込まれています")] diff --git a/crates/voicevox_core/src/infer.rs b/crates/voicevox_core/src/infer.rs index c816c9899..fc8954e7d 100644 --- a/crates/voicevox_core/src/infer.rs +++ b/crates/voicevox_core/src/infer.rs @@ -1,9 +1,9 @@ -pub(crate) mod domain; +pub(crate) mod domains; mod model_file; pub(crate) mod runtimes; -pub(crate) mod status; +pub(crate) mod session_set; -use std::{borrow::Cow, fmt::Debug}; +use std::{borrow::Cow, collections::BTreeSet, fmt::Debug}; use derive_new::new; use duplicate::duplicate_item; @@ -11,9 +11,10 @@ use enum_map::{Enum, EnumMap}; use ndarray::{Array, ArrayD, Dimension, ShapeError}; use thiserror::Error; -use crate::SupportedDevices; +use crate::{StyleType, SupportedDevices}; pub(crate) trait InferenceRuntime: 'static { + // TODO: "session"とは何なのかを定め、ドキュメントを書く。`InferenceSessionSet`も同様。 type Session: Sized + Send + 'static; type RunContext<'a>: From<&'a mut Self::Session> + PushInputTensor; @@ -32,9 +33,17 @@ pub(crate) trait InferenceRuntime: 'static { fn run(ctx: Self::RunContext<'_>) -> anyhow::Result>; } -/// ある`VoiceModel`が提供する推論操作の集合を示す。 -pub(crate) trait InferenceDomain { +/// 共に扱われるべき推論操作の集合を示す。 +pub(crate) trait InferenceDomain: Sized { type Operation: InferenceOperation; + + /// 対応する`StyleType`。 + /// + /// 複数の`InferenceDomain`に対応する`StyleType`があってもよい。 + /// + /// また、どの`InferenceDomain`にも属さない`StyleType`があってもよい。そのような`StyleType`は + /// 音声モデルのロード時に単に拒否されるべきである。 + fn style_types() -> &'static BTreeSet; } /// `InferenceDomain`の推論操作を表す列挙型。 diff --git a/crates/voicevox_core/src/infer/domains.rs b/crates/voicevox_core/src/infer/domains.rs new file mode 100644 index 000000000..687550399 --- /dev/null +++ b/crates/voicevox_core/src/infer/domains.rs @@ -0,0 +1,22 @@ +mod talk; + +pub(crate) use self::talk::{ + DecodeInput, DecodeOutput, PredictDurationInput, PredictDurationOutput, PredictIntonationInput, + PredictIntonationOutput, TalkDomain, TalkOperation, +}; + +pub(crate) struct InferenceDomainMap { + pub(crate) talk: V::Talk, +} + +pub(crate) trait InferenceDomainMapValues { + type Talk; +} + +impl InferenceDomainMapValues for (T,) { + type Talk = T; +} + +impl InferenceDomainMapValues for [A] { + type Talk = A; +} diff --git a/crates/voicevox_core/src/infer/domain.rs b/crates/voicevox_core/src/infer/domains/talk.rs similarity index 82% rename from crates/voicevox_core/src/infer/domain.rs rename to crates/voicevox_core/src/infer/domains/talk.rs index bb83886dd..e0716fa50 100644 --- a/crates/voicevox_core/src/infer/domain.rs +++ b/crates/voicevox_core/src/infer/domains/talk.rs @@ -1,22 +1,32 @@ +use std::collections::BTreeSet; + use enum_map::Enum; use macros::{InferenceInputSignature, InferenceOperation, InferenceOutputSignature}; use ndarray::{Array0, Array1, Array2}; +use once_cell::sync::Lazy; + +use crate::StyleType; -use super::{ +use super::super::{ InferenceDomain, InferenceInputSignature as _, InferenceOutputSignature as _, OutputTensor, }; -pub(crate) enum InferenceDomainImpl {} +pub(crate) enum TalkDomain {} + +impl InferenceDomain for TalkDomain { + type Operation = TalkOperation; -impl InferenceDomain for InferenceDomainImpl { - type Operation = InferenceOperationImpl; + fn style_types() -> &'static BTreeSet { + static STYLE_TYPES: Lazy> = Lazy::new(|| [StyleType::Talk].into()); + &STYLE_TYPES + } } #[derive(Clone, Copy, Enum, InferenceOperation)] #[inference_operation( - type Domain = InferenceDomainImpl; + type Domain = TalkDomain; )] -pub(crate) enum InferenceOperationImpl { +pub(crate) enum TalkOperation { #[inference_operation( type Input = PredictDurationInput; type Output = PredictDurationOutput; diff --git a/crates/voicevox_core/src/infer/session_set.rs b/crates/voicevox_core/src/infer/session_set.rs new file mode 100644 index 000000000..56d570f98 --- /dev/null +++ b/crates/voicevox_core/src/infer/session_set.rs @@ -0,0 +1,102 @@ +use std::{collections::HashMap, fmt::Display, marker::PhantomData, sync::Arc}; + +use anyhow::bail; +use enum_map::{Enum as _, EnumMap}; +use itertools::Itertools as _; + +use crate::error::ErrorRepr; + +use super::{ + model_file, InferenceDomain, InferenceInputSignature, InferenceOperation, InferenceRuntime, + InferenceSessionOptions, InferenceSignature, ParamInfo, +}; + +pub(crate) struct InferenceSessionSet( + EnumMap>>, +); + +impl InferenceSessionSet { + pub(crate) fn new( + model_bytes: &EnumMap>, + options: &EnumMap, + ) -> anyhow::Result { + let mut sessions = model_bytes + .iter() + .map(|(op, model_bytes)| { + let (expected_input_param_infos, expected_output_param_infos) = + ::PARAM_INFOS[op]; + + let (sess, actual_input_param_infos, actual_output_param_infos) = + R::new_session(|| model_file::decrypt(model_bytes), options[op])?; + + check_param_infos(expected_input_param_infos, &actual_input_param_infos)?; + check_param_infos(expected_output_param_infos, &actual_output_param_infos)?; + + Ok((op.into_usize(), std::sync::Mutex::new(sess).into())) + }) + .collect::>>()?; + + return Ok(Self(EnumMap::::from_fn(|k| { + sessions.remove(&k.into_usize()).expect("should exist") + }))); + + fn check_param_infos( + expected: &[ParamInfo], + actual: &[ParamInfo], + ) -> anyhow::Result<()> { + if !(expected.len() == actual.len() + && itertools::zip_eq(expected, actual) + .all(|(expected, actual)| expected.accepts(actual))) + { + let expected = display_param_infos(expected); + let actual = display_param_infos(actual); + bail!("expected {{{expected}}}, got {{{actual}}}") + } + Ok(()) + } + + fn display_param_infos(infos: &[ParamInfo]) -> impl Display { + infos + .iter() + .map(|ParamInfo { name, dt, ndim }| { + let brackets = match *ndim { + Some(ndim) => "[]".repeat(ndim), + None => "[]...".to_owned(), + }; + format!("{name}: {dt}{brackets}") + }) + .join(", ") + } + } +} + +impl InferenceSessionSet { + pub(crate) fn get(&self) -> InferenceSessionCell + where + I: InferenceInputSignature, + I::Signature: InferenceSignature, + { + InferenceSessionCell { + inner: self.0[I::Signature::OPERATION].clone(), + marker: PhantomData, + } + } +} + +pub(crate) struct InferenceSessionCell { + inner: Arc>, + marker: PhantomData, +} + +impl InferenceSessionCell { + pub(crate) fn run( + self, + input: I, + ) -> crate::Result<::Output> { + let inner = &mut self.inner.lock().unwrap(); + let ctx = input.make_run_context::(inner); + R::run(ctx) + .and_then(TryInto::try_into) + .map_err(|e| ErrorRepr::InferenceFailed(e).into()) + } +} diff --git a/crates/voicevox_core/src/infer/status.rs b/crates/voicevox_core/src/infer/status.rs deleted file mode 100644 index 2a575153d..000000000 --- a/crates/voicevox_core/src/infer/status.rs +++ /dev/null @@ -1,429 +0,0 @@ -use std::{ - collections::{BTreeMap, HashMap}, - fmt::Display, - marker::PhantomData, - sync::Arc, -}; - -use anyhow::bail; -use educe::Educe; -use enum_map::{Enum as _, EnumMap}; -use indexmap::IndexMap; -use itertools::{iproduct, Itertools as _}; - -use crate::{ - error::{ErrorRepr, LoadModelError, LoadModelErrorKind, LoadModelResult}, - infer::{InferenceOperation, ParamInfo}, - manifest::ModelInnerId, - metas::{self, SpeakerMeta, StyleId, StyleMeta, VoiceModelMeta}, - voice_model::{VoiceModelHeader, VoiceModelId}, - Result, -}; - -use super::{ - model_file, InferenceDomain, InferenceInputSignature, InferenceRuntime, - InferenceSessionOptions, InferenceSignature, -}; - -pub(crate) struct Status { - loaded_models: std::sync::Mutex>, - session_options: EnumMap, -} - -impl Status { - pub(crate) fn new(session_options: EnumMap) -> Self { - Self { - loaded_models: Default::default(), - session_options, - } - } - - pub(crate) fn insert_model( - &self, - model_header: &VoiceModelHeader, - model_bytes: &EnumMap>, - ) -> Result<()> { - self.loaded_models - .lock() - .unwrap() - .ensure_acceptable(model_header)?; - - let session_set = - SessionSet::new(model_bytes, &self.session_options).map_err(|source| { - LoadModelError { - path: model_header.path.clone(), - context: LoadModelErrorKind::InvalidModelData, - source: Some(source), - } - })?; - - self.loaded_models - .lock() - .unwrap() - .insert(model_header, session_set)?; - Ok(()) - } - - pub(crate) fn unload_model(&self, voice_model_id: &VoiceModelId) -> Result<()> { - self.loaded_models.lock().unwrap().remove(voice_model_id) - } - - pub(crate) fn metas(&self) -> VoiceModelMeta { - self.loaded_models.lock().unwrap().metas() - } - - pub(crate) fn ids_for(&self, style_id: StyleId) -> Result<(VoiceModelId, ModelInnerId)> { - self.loaded_models.lock().unwrap().ids_for(style_id) - } - - pub(crate) fn is_loaded_model(&self, voice_model_id: &VoiceModelId) -> bool { - self.loaded_models - .lock() - .unwrap() - .contains_voice_model(voice_model_id) - } - - pub(crate) fn is_loaded_model_by_style_id(&self, style_id: StyleId) -> bool { - self.loaded_models.lock().unwrap().contains_style(style_id) - } - - pub(crate) fn validate_speaker_id(&self, style_id: StyleId) -> bool { - self.is_loaded_model_by_style_id(style_id) - } - - /// 推論を実行する。 - /// - /// # Performance - /// - /// CPU/GPU-boundな操作であるため、非同期ランタイム上では直接実行されるべきではない。 - /// - /// # Panics - /// - /// `self`が`model_id`を含んでいないとき、パニックする。 - pub(crate) fn run_session( - &self, - model_id: &VoiceModelId, - input: I, - ) -> Result<::Output> - where - I: InferenceInputSignature, - I::Signature: InferenceSignature, - { - let sess = self.loaded_models.lock().unwrap().get(model_id); - sess.run(input) - } -} - -/// 読み込んだモデルの`Session`とそのメタ情報を保有し、追加/削除/取得の操作を提供する。 -/// -/// この構造体のメソッドは、すべて一瞬で完了すべきである。 -#[derive(Educe)] -#[educe(Default(bound = "R: InferenceRuntime, D: InferenceDomain"))] -struct LoadedModels( - IndexMap>, -); - -struct LoadedModel { - model_inner_ids: BTreeMap, - metas: VoiceModelMeta, - session_set: SessionSet, -} - -impl LoadedModels { - fn metas(&self) -> VoiceModelMeta { - metas::merge(self.0.values().flat_map(|LoadedModel { metas, .. }| metas)) - } - - fn ids_for(&self, style_id: StyleId) -> Result<(VoiceModelId, ModelInnerId)> { - let ( - model_id, - LoadedModel { - model_inner_ids, .. - }, - ) = self - .0 - .iter() - .find(|(_, LoadedModel { metas, .. })| { - metas - .iter() - .flat_map(SpeakerMeta::styles) - .any(|style| *style.id() == style_id) - }) - .ok_or(ErrorRepr::StyleNotFound { style_id })?; - - let model_inner_id = *model_inner_ids - .get(&style_id) - .expect("`model_inner_ids` should contains all of the style IDs in the model"); - - Ok((model_id.clone(), model_inner_id)) - } - - /// # Panics - /// - /// `self`が`model_id`を含んでいないとき、パニックする。 - fn get(&self, model_id: &VoiceModelId) -> SessionCell - where - I: InferenceInputSignature, - I::Signature: InferenceSignature, - { - self.0[model_id].session_set.get() - } - - fn contains_voice_model(&self, model_id: &VoiceModelId) -> bool { - self.0.contains_key(model_id) - } - - fn contains_style(&self, style_id: StyleId) -> bool { - self.styles().any(|style| *style.id() == style_id) - } - - /// 音声モデルを受け入れ可能かをチェックする。 - /// - /// # Errors - /// - /// 次の場合にエラーを返す。 - /// - /// - 音声モデルIDかスタイルIDが`model_header`と重複するとき - fn ensure_acceptable(&self, model_header: &VoiceModelHeader) -> LoadModelResult<()> { - let error = |context| LoadModelError { - path: model_header.path.clone(), - context, - source: None, - }; - - let loaded = self.speakers(); - let external = model_header.metas.iter(); - for (loaded, external) in iproduct!(loaded, external) { - if loaded.speaker_uuid() == external.speaker_uuid() { - loaded.warn_diff_except_styles(external); - } - } - - let loaded = self.styles(); - let external = model_header - .metas - .iter() - .flat_map(|speaker| speaker.styles()); - if self.0.contains_key(&model_header.id) { - return Err(error(LoadModelErrorKind::ModelAlreadyLoaded { - id: model_header.id.clone(), - })); - } - if let Some((style, _)) = - iproduct!(loaded, external).find(|(loaded, external)| loaded.id() == external.id()) - { - return Err(error(LoadModelErrorKind::StyleAlreadyLoaded { - id: *style.id(), - })); - } - Ok(()) - } - - fn insert( - &mut self, - model_header: &VoiceModelHeader, - session_set: SessionSet, - ) -> Result<()> { - self.ensure_acceptable(model_header)?; - - let prev = self.0.insert( - model_header.id.clone(), - LoadedModel { - model_inner_ids: model_header.model_inner_ids(), - metas: model_header.metas.clone(), - session_set, - }, - ); - assert!(prev.is_none()); - Ok(()) - } - - fn remove(&mut self, model_id: &VoiceModelId) -> Result<()> { - if self.0.remove(model_id).is_none() { - return Err(ErrorRepr::ModelNotFound { - model_id: model_id.clone(), - } - .into()); - } - Ok(()) - } - - fn speakers(&self) -> impl Iterator + Clone { - self.0.values().flat_map(|LoadedModel { metas, .. }| metas) - } - - fn styles(&self) -> impl Iterator { - self.speakers().flat_map(|speaker| speaker.styles()) - } -} - -struct SessionSet( - EnumMap>>, -); - -impl SessionSet { - fn new( - model_bytes: &EnumMap>, - options: &EnumMap, - ) -> anyhow::Result { - let mut sessions = model_bytes - .iter() - .map(|(op, model_bytes)| { - let (expected_input_param_infos, expected_output_param_infos) = - ::PARAM_INFOS[op]; - - let (sess, actual_input_param_infos, actual_output_param_infos) = - R::new_session(|| model_file::decrypt(model_bytes), options[op])?; - - check_param_infos(expected_input_param_infos, &actual_input_param_infos)?; - check_param_infos(expected_output_param_infos, &actual_output_param_infos)?; - - Ok((op.into_usize(), std::sync::Mutex::new(sess).into())) - }) - .collect::>>()?; - - return Ok(Self(EnumMap::::from_fn(|k| { - sessions.remove(&k.into_usize()).expect("should exist") - }))); - - fn check_param_infos( - expected: &[ParamInfo], - actual: &[ParamInfo], - ) -> anyhow::Result<()> { - if !(expected.len() == actual.len() - && itertools::zip_eq(expected, actual) - .all(|(expected, actual)| expected.accepts(actual))) - { - let expected = display_param_infos(expected); - let actual = display_param_infos(actual); - bail!("expected {{{expected}}}, got {{{actual}}}") - } - Ok(()) - } - - fn display_param_infos(infos: &[ParamInfo]) -> impl Display { - infos - .iter() - .map(|ParamInfo { name, dt, ndim }| { - let brackets = match *ndim { - Some(ndim) => "[]".repeat(ndim), - None => "[]...".to_owned(), - }; - format!("{name}: {dt}{brackets}") - }) - .join(", ") - } - } -} - -impl SessionSet { - fn get(&self) -> SessionCell - where - I: InferenceInputSignature, - I::Signature: InferenceSignature, - { - SessionCell { - inner: self.0[I::Signature::OPERATION].clone(), - marker: PhantomData, - } - } -} - -struct SessionCell { - inner: Arc>, - marker: PhantomData, -} - -impl SessionCell { - fn run(self, input: I) -> crate::Result<::Output> { - let inner = &mut self.inner.lock().unwrap(); - let ctx = input.make_run_context::(inner); - R::run(ctx) - .and_then(TryInto::try_into) - .map_err(|e| ErrorRepr::InferenceFailed(e).into()) - } -} - -#[cfg(test)] -mod tests { - use enum_map::enum_map; - use pretty_assertions::assert_eq; - use rstest::rstest; - - use crate::{ - infer::domain::{InferenceDomainImpl, InferenceOperationImpl}, - macros::tests::assert_debug_fmt_eq, - synthesizer::InferenceRuntimeImpl, - test_util::open_default_vvm_file, - }; - - use super::{super::InferenceSessionOptions, Status}; - - #[rstest] - #[case(true, 0)] - #[case(true, 1)] - #[case(true, 8)] - #[case(false, 2)] - #[case(false, 4)] - #[case(false, 8)] - #[case(false, 0)] - fn status_new_works(#[case] use_gpu: bool, #[case] cpu_num_threads: u16) { - let light_session_options = InferenceSessionOptions::new(cpu_num_threads, false); - let heavy_session_options = InferenceSessionOptions::new(cpu_num_threads, use_gpu); - let session_options = enum_map! { - InferenceOperationImpl::PredictDuration - | InferenceOperationImpl::PredictIntonation => light_session_options, - InferenceOperationImpl::Decode => heavy_session_options, - }; - let status = Status::::new(session_options); - - assert_eq!( - light_session_options, - status.session_options[InferenceOperationImpl::PredictDuration], - ); - assert_eq!( - light_session_options, - status.session_options[InferenceOperationImpl::PredictIntonation], - ); - assert_eq!( - heavy_session_options, - status.session_options[InferenceOperationImpl::Decode], - ); - - assert!(status.loaded_models.lock().unwrap().0.is_empty()); - } - - #[rstest] - #[tokio::test] - async fn status_load_model_works() { - let status = Status::::new( - enum_map!(_ => InferenceSessionOptions::new(0, false)), - ); - let model = &open_default_vvm_file().await; - let model_bytes = &model.read_inference_models().await.unwrap(); - let result = status.insert_model(model.header(), model_bytes); - assert_debug_fmt_eq!(Ok(()), result); - assert_eq!(1, status.loaded_models.lock().unwrap().0.len()); - } - - #[rstest] - #[tokio::test] - async fn status_is_model_loaded_works() { - let status = Status::::new( - enum_map!(_ => InferenceSessionOptions::new(0, false)), - ); - let vvm = open_default_vvm_file().await; - let model_header = vvm.header(); - let model_bytes = &vvm.read_inference_models().await.unwrap(); - assert!( - !status.is_loaded_model(&model_header.id), - "model should not be loaded" - ); - let result = status.insert_model(model_header, model_bytes); - assert_debug_fmt_eq!(Ok(()), result); - assert!( - status.is_loaded_model(&model_header.id), - "model should be loaded", - ); - } -} diff --git a/crates/voicevox_core/src/lib.rs b/crates/voicevox_core/src/lib.rs index 29efba8f1..0f34c5962 100644 --- a/crates/voicevox_core/src/lib.rs +++ b/crates/voicevox_core/src/lib.rs @@ -9,6 +9,7 @@ mod macros; mod manifest; mod metas; mod result; +mod status; mod synthesizer; mod task; mod text_analyzer; @@ -33,7 +34,8 @@ pub use self::{ engine::{AccentPhraseModel, AudioQueryModel, FullcontextExtractor}, error::{Error, ErrorKind}, metas::{ - RawStyleId, RawStyleVersion, SpeakerMeta, StyleId, StyleMeta, StyleVersion, VoiceModelMeta, + RawStyleId, RawStyleVersion, SpeakerMeta, StyleId, StyleMeta, StyleType, StyleVersion, + VoiceModelMeta, }, result::Result, synthesizer::{AccelerationMode, InitializeOptions, SynthesisOptions, TtsOptions}, diff --git a/crates/voicevox_core/src/manifest.rs b/crates/voicevox_core/src/manifest.rs index 650e151d5..3b17ae3f1 100644 --- a/crates/voicevox_core/src/manifest.rs +++ b/crates/voicevox_core/src/manifest.rs @@ -1,8 +1,10 @@ -use std::{collections::BTreeMap, fmt::Display}; +use std::{collections::BTreeMap, fmt::Display, sync::Arc}; use derive_getters::Getters; +use derive_more::Deref; use derive_new::new; use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; use crate::StyleId; @@ -41,9 +43,27 @@ pub struct Manifest { #[allow(dead_code)] manifest_version: ManifestVersion, metas_filename: String, - decode_filename: String, - predict_duration_filename: String, - predict_intonation_filename: String, + #[serde(flatten)] + domains: ManifestDomains, +} + +#[derive(Deserialize, Clone)] +pub(crate) struct ManifestDomains { + pub(crate) talk: Option, +} + +#[derive(Deserialize, Clone)] +pub(crate) struct TalkManifest { + pub(crate) predict_duration_filename: String, + pub(crate) predict_intonation_filename: String, + pub(crate) decode_filename: String, #[serde(default)] - style_id_to_model_inner_id: BTreeMap, + pub(crate) style_id_to_model_inner_id: StyleIdToModelInnerId, } + +#[serde_as] +#[derive(Default, Clone, Deref, Deserialize)] +#[deref(forward)] +pub(crate) struct StyleIdToModelInnerId( + #[serde_as(as = "Arc>")] Arc>, +); diff --git a/crates/voicevox_core/src/metas.rs b/crates/voicevox_core/src/metas.rs index 78314d52a..b9f274c48 100644 --- a/crates/voicevox_core/src/metas.rs +++ b/crates/voicevox_core/src/metas.rs @@ -49,7 +49,20 @@ pub type RawStyleId = u32; /// /// [**話者**(_speaker_)]: SpeakerMeta /// [**スタイル**(_style_)]: StyleMeta -#[derive(PartialEq, Eq, Clone, Copy, Ord, Hash, PartialOrd, Deserialize, Serialize, new, Debug)] +#[derive( + PartialEq, + Eq, + Clone, + Copy, + Ord, + Hash, + PartialOrd, + derive_more::FromStr, + Deserialize, + Serialize, + new, + Debug, +)] pub struct StyleId(RawStyleId); impl StyleId { @@ -154,12 +167,47 @@ pub struct StyleMeta { id: StyleId, /// スタイル名。 name: String, + /// スタイルに対応するモデルの種類。 + #[serde(default)] + r#type: StyleType, /// スタイルの順番。 /// /// [`SpeakerMeta::styles`]は、この値に対して昇順に並んでいるべきである。 order: Option, } +/// **スタイル**(_style_)に対応するモデルの種類。 +#[derive( + Default, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + strum::Display, + Deserialize, + Serialize, +)] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum StyleType { + /// 音声合成クエリの作成と音声合成が可能。 + #[default] + Talk, + + /// 歌唱音声合成用のクエリの作成が可能。 + SingingTeacher, + + /// 歌唱音声合成が可能。 + FrameDecode, + + /// 歌唱音声合成用のクエリの作成と歌唱音声合成が可能。 + Sing, +} + #[cfg(test)] mod tests { use once_cell::sync::Lazy; @@ -175,6 +223,7 @@ mod tests { { "id": 3, "name": "B_1", + "type": "talk", "order": 0 } ], @@ -188,6 +237,7 @@ mod tests { { "id": 2, "name": "A_3", + "type": "talk", "order": 2 } ], @@ -201,11 +251,13 @@ mod tests { { "id": 1, "name": "A_1", + "type": "talk", "order": 0 }, { "id": 0, "name": "A_2", + "type": "talk", "order": 1 } ], @@ -224,16 +276,19 @@ mod tests { { "id": 1, "name": "A_1", + "type": "talk", "order": 0 }, { "id": 0, "name": "A_2", + "type": "talk", "order": 1 }, { "id": 2, "name": "A_3", + "type": "talk", "order": 2 } ], @@ -247,6 +302,7 @@ mod tests { { "id": 3, "name": "B_1", + "type": "talk", "order": 0 } ], diff --git a/crates/voicevox_core/src/status.rs b/crates/voicevox_core/src/status.rs new file mode 100644 index 000000000..a47de689b --- /dev/null +++ b/crates/voicevox_core/src/status.rs @@ -0,0 +1,428 @@ +use std::any; + +use duplicate::{duplicate, duplicate_item}; +use educe::Educe; +use enum_map::EnumMap; +use indexmap::IndexMap; +use itertools::iproduct; + +use crate::{ + error::{ErrorRepr, LoadModelError, LoadModelErrorKind, LoadModelResult}, + infer::{ + domains::{InferenceDomainMap, TalkDomain, TalkOperation}, + session_set::{InferenceSessionCell, InferenceSessionSet}, + InferenceDomain, InferenceInputSignature, InferenceRuntime, InferenceSessionOptions, + InferenceSignature, + }, + manifest::{ModelInnerId, StyleIdToModelInnerId}, + metas::{self, SpeakerMeta, StyleId, StyleMeta, VoiceModelMeta}, + voice_model::{ModelBytesWithInnerIdsByDomain, VoiceModelHeader, VoiceModelId}, + Result, +}; + +pub(crate) struct Status { + loaded_models: std::sync::Mutex>, + session_options: InferenceDomainMap, +} + +impl Status { + pub(crate) fn new(session_options: InferenceDomainMap) -> Self { + Self { + loaded_models: Default::default(), + session_options, + } + } + + pub(crate) fn insert_model( + &self, + model_header: &VoiceModelHeader, + model_contents: &InferenceDomainMap, + ) -> Result<()> { + self.loaded_models + .lock() + .unwrap() + .ensure_acceptable(model_header)?; + + let session_sets_with_inner_ids = model_contents + .create_session_sets(&self.session_options) + .map_err(|source| LoadModelError { + path: model_header.path.clone(), + context: LoadModelErrorKind::InvalidModelData, + source: Some(source), + })?; + + self.loaded_models + .lock() + .unwrap() + .insert(model_header, session_sets_with_inner_ids)?; + Ok(()) + } + + pub(crate) fn unload_model(&self, voice_model_id: &VoiceModelId) -> Result<()> { + self.loaded_models.lock().unwrap().remove(voice_model_id) + } + + pub(crate) fn metas(&self) -> VoiceModelMeta { + self.loaded_models.lock().unwrap().metas() + } + + /// あるスタイルに対応する`VoiceModelId`と`ModelInnerId`の組を返す。 + /// + /// `StyleId` → `ModelInnerId`のマッピングが存在しない場合は、`ModelInnerId`としては + /// `style_id`と同じ値を返す。 + pub(crate) fn ids_for( + &self, + style_id: StyleId, + ) -> Result<(VoiceModelId, ModelInnerId)> { + self.loaded_models.lock().unwrap().ids_for::(style_id) + } + + pub(crate) fn is_loaded_model(&self, voice_model_id: &VoiceModelId) -> bool { + self.loaded_models + .lock() + .unwrap() + .contains_voice_model(voice_model_id) + } + + // FIXME: この関数はcompatible_engineとテストでのみ使われるが、テストのために`StyleType`を + // 引数に含めるようにする + pub(crate) fn is_loaded_model_by_style_id(&self, style_id: StyleId) -> bool { + self.loaded_models.lock().unwrap().contains_style(style_id) + } + + /// 推論を実行する。 + /// + /// # Performance + /// + /// CPU/GPU-boundな操作であるため、非同期ランタイム上では直接実行されるべきではない。 + /// + /// # Panics + /// + /// `self`が`model_id`を含んでいないとき、パニックする。 + pub(crate) fn run_session( + &self, + model_id: &VoiceModelId, + input: I, + ) -> Result<::Output> + where + I: InferenceInputSignature, + ::Domain: InferenceDomainExt, + { + let sess = self.loaded_models.lock().unwrap().get(model_id); + sess.run(input) + } +} + +/// 読み込んだモデルの`Session`とそのメタ情報を保有し、追加/削除/取得の操作を提供する。 +/// +/// この構造体のメソッドは、すべて一瞬で完了すべきである。 +#[derive(Educe)] +#[educe(Default(bound = "R: InferenceRuntime"))] +struct LoadedModels(IndexMap>); + +struct LoadedModel { + metas: VoiceModelMeta, + session_sets_with_inner_ids: InferenceDomainMap>, +} + +impl LoadedModels { + fn metas(&self) -> VoiceModelMeta { + metas::merge(self.0.values().flat_map(|LoadedModel { metas, .. }| metas)) + } + + fn ids_for( + &self, + style_id: StyleId, + ) -> Result<(VoiceModelId, ModelInnerId)> { + let ( + model_id, + LoadedModel { + session_sets_with_inner_ids, + .. + }, + ) = self + .0 + .iter() + .find(|(_, LoadedModel { metas, .. })| { + metas.iter().flat_map(SpeakerMeta::styles).any(|style| { + *style.id() == style_id && D::style_types().contains(style.r#type()) + }) + }) + .ok_or(ErrorRepr::StyleNotFound { + style_id, + style_types: D::style_types(), + })?; + + let model_inner_id = session_sets_with_inner_ids + .get::() + .as_ref() + .and_then(|(model_inner_ids, _)| model_inner_ids.get(&style_id).copied()) + .unwrap_or_else(|| ModelInnerId::new(style_id.raw_id())); + + Ok((model_id.clone(), model_inner_id)) + } + + /// # Panics + /// + /// 次の場合にパニックする。 + /// + /// - `self`が`model_id`を含んでいないとき + /// - 対応する`InferenceDomain`が欠けているとき + fn get(&self, model_id: &VoiceModelId) -> InferenceSessionCell + where + I: InferenceInputSignature, + ::Domain: InferenceDomainExt, + { + let (_, session_set) = self.0[model_id] + .session_sets_with_inner_ids + .get::<::Domain>() + .as_ref() + .unwrap_or_else(|| { + let type_name = any::type_name::<::Domain>() + .split("::") + .last() + .unwrap(); + panic!( + "missing session set for `{type_name}` (should be checked in \ + `VoiceModelHeader::new` and `ids_for`)", + ); + }); + session_set.get() + } + + fn contains_voice_model(&self, model_id: &VoiceModelId) -> bool { + self.0.contains_key(model_id) + } + + fn contains_style(&self, style_id: StyleId) -> bool { + self.styles().any(|style| *style.id() == style_id) + } + + /// 音声モデルを受け入れ可能かをチェックする。 + /// + /// # Errors + /// + /// 次の場合にエラーを返す。 + /// + /// - 現在持っている音声モデルIDかスタイルIDが`model_header`と重複するとき + /// - 必要であるはずの`InferenceDomain`のモデルデータが欠けているとき + // FIXME: コメントとテストを書く + // - https://github.com/VOICEVOX/voicevox_core/pull/761#discussion_r1589978521 + // - https://github.com/VOICEVOX/voicevox_core/pull/761#discussion_r1589976759 + fn ensure_acceptable(&self, model_header: &VoiceModelHeader) -> LoadModelResult<()> { + let error = |context| LoadModelError { + path: model_header.path.clone(), + context, + source: None, + }; + + if self.0.contains_key(&model_header.id) { + return Err(error(LoadModelErrorKind::ModelAlreadyLoaded { + id: model_header.id.clone(), + })); + } + + // FIXME: https://github.com/VOICEVOX/voicevox_core/pull/761#discussion_r1590200343 + + let loaded = self.speakers(); + let external = model_header.metas.iter(); + for (loaded, external) in iproduct!(loaded, external) { + if loaded.speaker_uuid() == external.speaker_uuid() { + loaded.warn_diff_except_styles(external); + } + } + + let loaded = self.styles(); + let external = model_header + .metas + .iter() + .flat_map(|speaker| speaker.styles()); + if let Some((style, _)) = + iproduct!(loaded, external).find(|(loaded, external)| loaded.id() == external.id()) + { + return Err(error(LoadModelErrorKind::StyleAlreadyLoaded { + id: *style.id(), + })); + } + Ok(()) + } + + fn insert( + &mut self, + model_header: &VoiceModelHeader, + session_sets_with_inner_ids: InferenceDomainMap>, + ) -> Result<()> { + self.ensure_acceptable(model_header)?; + + let prev = self.0.insert( + model_header.id.clone(), + LoadedModel { + metas: model_header.metas.clone(), + session_sets_with_inner_ids, + }, + ); + assert!(prev.is_none()); + Ok(()) + } + + fn remove(&mut self, model_id: &VoiceModelId) -> Result<()> { + if self.0.remove(model_id).is_none() { + return Err(ErrorRepr::ModelNotFound { + model_id: model_id.clone(), + } + .into()); + } + Ok(()) + } + + fn speakers(&self) -> impl Iterator + Clone { + self.0.values().flat_map(|LoadedModel { metas, .. }| metas) + } + + fn styles(&self) -> impl Iterator { + self.speakers().flat_map(|speaker| speaker.styles()) + } +} + +pub(crate) trait InferenceDomainExt: InferenceDomain { + fn visit( + map: &InferenceDomainMap>, + ) -> Option<&(StyleIdToModelInnerId, InferenceSessionSet)>; +} + +#[duplicate_item( + T field; + [ TalkDomain ] [ talk ]; +)] +impl InferenceDomainExt for T { + fn visit( + map: &InferenceDomainMap>, + ) -> Option<&(StyleIdToModelInnerId, InferenceSessionSet)> { + map.field.as_ref() + } +} + +impl InferenceDomainMap> { + fn get( + &self, + ) -> Option<&(StyleIdToModelInnerId, InferenceSessionSet)> { + D::visit(self) + } +} + +impl InferenceDomainMap { + fn create_session_sets( + &self, + session_options: &InferenceDomainMap, + ) -> anyhow::Result>> { + duplicate! { + [ + field; + [ talk ]; + ] + let field = self + .field + .as_ref() + .map(|(model_inner_ids, model_bytes)| { + let session_set = InferenceSessionSet::new(model_bytes, &session_options.field)?; + Ok::<_, anyhow::Error>((model_inner_ids.clone(), session_set)) + }) + .transpose()?; + } + + Ok(InferenceDomainMap { talk }) + } +} + +type SessionOptionsByDomain = (EnumMap,); + +type SessionSetsWithInnerIdsByDomain = + (Option<(StyleIdToModelInnerId, InferenceSessionSet)>,); + +#[cfg(test)] +mod tests { + use enum_map::enum_map; + use pretty_assertions::assert_eq; + use rstest::rstest; + + use crate::{ + infer::{ + domains::{InferenceDomainMap, TalkOperation}, + InferenceSessionOptions, + }, + macros::tests::assert_debug_fmt_eq, + synthesizer::InferenceRuntimeImpl, + }; + + use super::Status; + + #[rstest] + #[case(true, 0)] + #[case(true, 1)] + #[case(true, 8)] + #[case(false, 2)] + #[case(false, 4)] + #[case(false, 8)] + #[case(false, 0)] + fn status_new_works(#[case] use_gpu: bool, #[case] cpu_num_threads: u16) { + let light_session_options = InferenceSessionOptions::new(cpu_num_threads, false); + let heavy_session_options = InferenceSessionOptions::new(cpu_num_threads, use_gpu); + let session_options = InferenceDomainMap { + talk: enum_map! { + TalkOperation::PredictDuration + | TalkOperation::PredictIntonation => light_session_options, + TalkOperation::Decode => heavy_session_options, + }, + }; + let status = Status::::new(session_options); + + assert_eq!( + light_session_options, + status.session_options.talk[TalkOperation::PredictDuration], + ); + assert_eq!( + light_session_options, + status.session_options.talk[TalkOperation::PredictIntonation], + ); + assert_eq!( + heavy_session_options, + status.session_options.talk[TalkOperation::Decode], + ); + + assert!(status.loaded_models.lock().unwrap().0.is_empty()); + } + + #[rstest] + #[tokio::test] + async fn status_load_model_works() { + let status = Status::::new(InferenceDomainMap { + talk: enum_map!(_ => InferenceSessionOptions::new(0, false)), + }); + let model = &crate::tokio::VoiceModel::sample().await.unwrap(); + let model_contents = &model.read_inference_models().await.unwrap(); + let result = status.insert_model(model.header(), model_contents); + assert_debug_fmt_eq!(Ok(()), result); + assert_eq!(1, status.loaded_models.lock().unwrap().0.len()); + } + + #[rstest] + #[tokio::test] + async fn status_is_model_loaded_works() { + let status = Status::::new(InferenceDomainMap { + talk: enum_map!(_ => InferenceSessionOptions::new(0, false)), + }); + let vvm = &crate::tokio::VoiceModel::sample().await.unwrap(); + let model_header = vvm.header(); + let model_contents = &vvm.read_inference_models().await.unwrap(); + assert!( + !status.is_loaded_model(&model_header.id), + "model should not be loaded" + ); + let result = status.insert_model(model_header, model_contents); + assert_debug_fmt_eq!(Ok(()), result); + assert!( + status.is_loaded_model(&model_header.id), + "model should be loaded", + ); + } +} diff --git a/crates/voicevox_core/src/synthesizer.rs b/crates/voicevox_core/src/synthesizer.rs index b90139434..5e4894415 100644 --- a/crates/voicevox_core/src/synthesizer.rs +++ b/crates/voicevox_core/src/synthesizer.rs @@ -83,14 +83,14 @@ pub(crate) mod blocking { engine::{create_kana, mora_to_text, MoraModel, OjtPhoneme}, error::ErrorRepr, infer::{ - domain::{ - DecodeInput, DecodeOutput, InferenceDomainImpl, InferenceOperationImpl, - PredictDurationInput, PredictDurationOutput, PredictIntonationInput, - PredictIntonationOutput, + domains::{ + DecodeInput, DecodeOutput, InferenceDomainMap, PredictDurationInput, + PredictDurationOutput, PredictIntonationInput, PredictIntonationOutput, TalkDomain, + TalkOperation, }, - status::Status, InferenceSessionOptions, }, + status::Status, text_analyzer::{KanaAnalyzer, OpenJTalkAnalyzer, TextAnalyzer}, AccentPhraseModel, AudioQueryModel, FullcontextExtractor, Result, StyleId, SupportedDevices, SynthesisOptions, VoiceModelId, VoiceModelMeta, @@ -102,7 +102,7 @@ pub(crate) mod blocking { /// 音声シンセサイザ。 pub struct Synthesizer { - pub(super) status: Status, + pub(super) status: Status, open_jtalk_analyzer: OpenJTalkAnalyzer, kana_analyzer: KanaAnalyzer, use_gpu: bool, @@ -169,10 +169,12 @@ pub(crate) mod blocking { let heavy_session_options = InferenceSessionOptions::new(options.cpu_num_threads, use_gpu); - let status = Status::new(enum_map! { - InferenceOperationImpl::PredictDuration - | InferenceOperationImpl::PredictIntonation => light_session_options, - InferenceOperationImpl::Decode => heavy_session_options, + let status = Status::new(InferenceDomainMap { + talk: enum_map! { + TalkOperation::PredictDuration + | TalkOperation::PredictIntonation => light_session_options, + TalkOperation::Decode => heavy_session_options, + }, }); return Ok(Self { @@ -441,6 +443,7 @@ pub(crate) mod blocking { /// # async fn main() -> anyhow::Result<()> { /// # let synthesizer = /// # voicevox_core::__internal::doctest_fixtures::synthesizer_with_sample_voice_model( + /// # test_util::SAMPLE_VOICE_MODEL_FILE_PATH, /// # test_util::OPEN_JTALK_DIC_DIR, /// # ) /// # .await?; @@ -680,6 +683,7 @@ pub(crate) mod blocking { /// # async fn main() -> anyhow::Result<()> { /// # let synthesizer = /// # voicevox_core::__internal::doctest_fixtures::synthesizer_with_sample_voice_model( + /// # test_util::SAMPLE_VOICE_MODEL_FILE_PATH, /// # test_util::OPEN_JTALK_DIC_DIR, /// # ) /// # .await?; @@ -728,6 +732,7 @@ pub(crate) mod blocking { /// # async fn main() -> anyhow::Result<()> { /// # let synthesizer = /// # voicevox_core::__internal::doctest_fixtures::synthesizer_with_sample_voice_model( + /// # test_util::SAMPLE_VOICE_MODEL_FILE_PATH, /// # test_util::OPEN_JTALK_DIC_DIR, /// # ) /// # .await?; @@ -760,6 +765,7 @@ pub(crate) mod blocking { /// # async fn main() -> anyhow::Result<()> { /// # let synthesizer = /// # voicevox_core::__internal::doctest_fixtures::synthesizer_with_sample_voice_model( + /// # test_util::SAMPLE_VOICE_MODEL_FILE_PATH, /// # test_util::OPEN_JTALK_DIC_DIR, /// # ) /// # .await?; @@ -830,12 +836,7 @@ pub(crate) mod blocking { impl PerformInference for self::Synthesizer { fn predict_duration(&self, phoneme_vector: &[i64], style_id: StyleId) -> Result> { - // FIXME: `Status::ids_for`があるため、ここは不要なはず - if !self.status.validate_speaker_id(style_id) { - return Err(ErrorRepr::StyleNotFound { style_id }.into()); - } - - let (model_id, model_inner_id) = self.status.ids_for(style_id)?; + let (model_id, model_inner_id) = self.status.ids_for::(style_id)?; let PredictDurationOutput { phoneme_length: output, @@ -870,12 +871,7 @@ pub(crate) mod blocking { end_accent_phrase_vector: &[i64], style_id: StyleId, ) -> Result> { - // FIXME: `Status::ids_for`があるため、ここは不要なはず - if !self.status.validate_speaker_id(style_id) { - return Err(ErrorRepr::StyleNotFound { style_id }.into()); - } - - let (model_id, model_inner_id) = self.status.ids_for(style_id)?; + let (model_id, model_inner_id) = self.status.ids_for::(style_id)?; let PredictIntonationOutput { f0_list: output } = self.status.run_session( &model_id, @@ -902,12 +898,7 @@ pub(crate) mod blocking { phoneme_vector: &[f32], style_id: StyleId, ) -> Result> { - // FIXME: `Status::ids_for`があるため、ここは不要なはず - if !self.status.validate_speaker_id(style_id) { - return Err(ErrorRepr::StyleNotFound { style_id }.into()); - } - - let (model_id, model_inner_id) = self.status.ids_for(style_id)?; + let (model_id, model_inner_id) = self.status.ids_for::(style_id)?; // 音が途切れてしまうのを避けるworkaround処理が入っている // TODO: 改善したらここのpadding処理を取り除く @@ -1304,8 +1295,7 @@ mod tests { use super::{blocking::PerformInference as _, AccelerationMode, InitializeOptions}; use crate::{ - engine::MoraModel, macros::tests::assert_debug_fmt_eq, test_util::open_default_vvm_file, - AccentPhraseModel, Result, StyleId, + engine::MoraModel, macros::tests::assert_debug_fmt_eq, AccentPhraseModel, Result, StyleId, }; use ::test_util::OPEN_JTALK_DIC_DIR; use rstest::rstest; @@ -1324,7 +1314,7 @@ mod tests { .unwrap(); let result = syntesizer - .load_voice_model(&open_default_vvm_file().await) + .load_voice_model(&crate::tokio::VoiceModel::sample().await.unwrap()) .await; assert_debug_fmt_eq!( @@ -1366,7 +1356,7 @@ mod tests { "expected is_model_loaded to return false, but got true", ); syntesizer - .load_voice_model(&open_default_vvm_file().await) + .load_voice_model(&crate::tokio::VoiceModel::sample().await.unwrap()) .await .unwrap(); @@ -1391,7 +1381,7 @@ mod tests { .unwrap(); syntesizer - .load_voice_model(&open_default_vvm_file().await) + .load_voice_model(&crate::tokio::VoiceModel::sample().await.unwrap()) .await .unwrap(); @@ -1421,7 +1411,7 @@ mod tests { ) .unwrap(); syntesizer - .load_voice_model(&open_default_vvm_file().await) + .load_voice_model(&crate::tokio::VoiceModel::sample().await.unwrap()) .await .unwrap(); @@ -1460,7 +1450,7 @@ mod tests { ) .unwrap(); syntesizer - .load_voice_model(&open_default_vvm_file().await) + .load_voice_model(&crate::tokio::VoiceModel::sample().await.unwrap()) .await .unwrap(); diff --git a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/manifest.json b/crates/voicevox_core/src/test_data/model_sources/load_model_works1/manifest.json deleted file mode 100644 index a8a7adebf..000000000 --- a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/manifest.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "manifest_version": "0.0.0", - "metas_filename": "metas.json", - "decode_filename": "decode.onnx", - "predict_duration_filename": "predict_duration.onnx", - "predict_intonation_filename": "predict_intonation.onnx", - "style_id_to_model_inner_id": { - "302": 2, - "303": 3 - } -} diff --git a/crates/voicevox_core/src/test_util.rs b/crates/voicevox_core/src/test_util.rs index d60785246..5b97f21fc 100644 --- a/crates/voicevox_core/src/test_util.rs +++ b/crates/voicevox_core/src/test_util.rs @@ -1,27 +1,9 @@ -use std::path::PathBuf; +use ::test_util::SAMPLE_VOICE_MODEL_FILE_PATH; use crate::Result; -pub(crate) async fn open_default_vvm_file() -> crate::tokio::VoiceModel { - crate::tokio::VoiceModel::from_path( - ::test_util::convert_zip_vvm( - PathBuf::from(env!("CARGO_WORKSPACE_DIR")) - .join(file!()) - .parent() - .unwrap() - .join("test_data/model_sources") - .join("load_model_works1"), - ) - .await, - ) - .await - .unwrap() -} - impl crate::tokio::VoiceModel { pub(crate) async fn sample() -> Result { - return Self::from_path(PATH).await; - - static PATH: &str = concat!(env!("CARGO_WORKSPACE_DIR"), "/model/sample.vvm"); + Self::from_path(SAMPLE_VOICE_MODEL_FILE_PATH).await } } diff --git a/crates/voicevox_core/src/voice_model.rs b/crates/voicevox_core/src/voice_model.rs index 76f692eaa..364c8db0a 100644 --- a/crates/voicevox_core/src/voice_model.rs +++ b/crates/voicevox_core/src/voice_model.rs @@ -2,21 +2,33 @@ //! //! VVM ファイルの定義と形式は[ドキュメント](../../../docs/vvm.md)を参照。 +use anyhow::anyhow; use derive_getters::Getters; use derive_new::new; +use easy_ext::ext; +use enum_map::EnumMap; +use itertools::Itertools as _; use serde::Deserialize; use crate::{ - manifest::{Manifest, ModelInnerId}, - SpeakerMeta, StyleId, StyleMeta, VoiceModelMeta, + error::{LoadModelError, LoadModelErrorKind, LoadModelResult}, + infer::{ + domains::{TalkDomain, TalkOperation}, + InferenceDomain, + }, + manifest::{Manifest, ManifestDomains, StyleIdToModelInnerId}, + SpeakerMeta, StyleMeta, StyleType, VoiceModelMeta, }; -use std::{collections::BTreeMap, path::PathBuf}; +use std::path::{Path, PathBuf}; /// [`VoiceModelId`]の実体。 /// /// [`VoiceModelId`]: VoiceModelId pub type RawVoiceModelId = String; +pub(crate) type ModelBytesWithInnerIdsByDomain = + (Option<(StyleIdToModelInnerId, EnumMap>)>,); + /// 音声モデルID。 #[derive( PartialEq, @@ -45,29 +57,91 @@ pub(crate) struct VoiceModelHeader { pub(crate) id: VoiceModelId, manifest: Manifest, /// メタ情報。 + /// + /// `manifest`が対応していない`StyleType`のスタイルは含まれるべきではない。 pub(crate) metas: VoiceModelMeta, pub(crate) path: PathBuf, } impl VoiceModelHeader { - /// モデル内のすべてのスタイルに対するモデル内IDを取得する。 + fn new( + id: VoiceModelId, + manifest: Manifest, + metas: &[u8], + path: &Path, + ) -> LoadModelResult { + let metas = + serde_json::from_slice::(metas).map_err(|source| LoadModelError { + path: path.to_owned(), + context: LoadModelErrorKind::InvalidModelFormat, + source: Some( + anyhow::Error::from(source) + .context(format!("{}が不正です", manifest.metas_filename())), + ), + })?; + + manifest + .domains() + .check_acceptable(&metas) + .map_err(|style_type| LoadModelError { + path: path.to_owned(), + context: LoadModelErrorKind::InvalidModelFormat, + source: Some(anyhow!( + "{metas_filename}には`{style_type}`のスタイルが存在しますが、manifest.jsonでの\ + 対応がありません", + metas_filename = manifest.metas_filename(), + )), + })?; + + Ok(Self { + id, + manifest, + metas, + path: path.to_owned(), + }) + } +} + +impl ManifestDomains { + /// manifestとして対応していない`StyleType`に対してエラーを発する。 /// - /// モデル内IDのマッピングが存在しない場合はそのままスタイルIDを返す。 - pub(crate) fn model_inner_ids(&self) -> BTreeMap { - self.metas + /// `Status`はこのバリデーションを信頼し、`InferenceDomain`の不足時にパニックする。 + fn check_acceptable(&self, metas: &[SpeakerMeta]) -> std::result::Result<(), StyleType> { + let err = metas .iter() .flat_map(SpeakerMeta::styles) - .map(StyleMeta::id) - .map(|&style_id| { - let model_inner_id = self - .manifest - .style_id_to_model_inner_id() - .get(&style_id) - .copied() - .unwrap_or_else(|| ModelInnerId::new(style_id.raw_id())); - (style_id, model_inner_id) - }) - .collect() + .map(StyleMeta::r#type) + .copied() + .unique() + .find(|&style_type| !self.accepts(style_type)); + + match err { + Some(err) => Err(err), + None => Ok(()), + } + } + + /// メタ情報にタイプが`style_type`のスタイルが含まれることを許容するかどうか。 + /// + /// 例えば`self.talk`が`None`のとき、`StyleType::Talk`に対して`false`を返す。 + fn accepts(&self, style_type: StyleType) -> bool { + let Self { talk } = self; + + return TalkDomain::contains(style_type).implies(|| talk.is_some()); + + #[ext] + impl D { + fn contains(style_type: StyleType) -> bool { + Self::style_types().contains(&style_type) + } + } + + #[ext] + impl bool { + fn implies(self, other: impl FnOnce() -> Self) -> Self { + !self || other() + } + } } } @@ -85,12 +159,12 @@ pub(crate) mod blocking { use crate::{ error::{LoadModelError, LoadModelErrorKind, LoadModelResult}, - infer::domain::InferenceOperationImpl, - manifest::Manifest, + infer::domains::InferenceDomainMap, + manifest::{Manifest, TalkManifest}, VoiceModelMeta, }; - use super::{VoiceModelHeader, VoiceModelId}; + use super::{ModelBytesWithInnerIdsByDomain, VoiceModelHeader, VoiceModelId}; /// 音声モデル。 /// @@ -103,39 +177,52 @@ pub(crate) mod blocking { impl self::VoiceModel { pub(crate) fn read_inference_models( &self, - ) -> LoadModelResult>> { + ) -> LoadModelResult> { let reader = BlockingVvmEntryReader::open(&self.header.path)?; - let model_bytes = [ - self.header.manifest.predict_duration_filename(), - self.header.manifest.predict_intonation_filename(), - self.header.manifest.decode_filename(), - ] - .into_par_iter() - .map(|filename| reader.read_vvm_entry(filename)) - .collect::, _>>()? - .try_into() - .unwrap_or_else(|_| panic!("should be same length")); - - Ok(EnumMap::from_array(model_bytes)) + let talk = self + .header + .manifest + .domains() + .talk + .as_ref() + .map( + |TalkManifest { + predict_duration_filename, + predict_intonation_filename, + decode_filename, + style_id_to_model_inner_id, + }| { + let model_bytes = [ + predict_duration_filename, + predict_intonation_filename, + decode_filename, + ] + .into_par_iter() + .map(|filename| reader.read_vvm_entry(filename)) + .collect::, _>>()? + .try_into() + .unwrap_or_else(|_| panic!("should be same length")); + + let model_bytes = EnumMap::from_array(model_bytes); + + Ok((style_id_to_model_inner_id.clone(), model_bytes)) + }, + ) + .transpose()?; + + Ok(InferenceDomainMap { talk }) } /// VVMファイルから`VoiceModel`をコンストラクトする。 pub fn from_path(path: impl AsRef) -> crate::Result { - let path = path.as_ref().to_owned(); - let reader = BlockingVvmEntryReader::open(&path)?; + let path = path.as_ref(); + let reader = BlockingVvmEntryReader::open(path)?; let manifest = reader.read_vvm_json::("manifest.json")?; - let metas = reader.read_vvm_json(manifest.metas_filename())?; + let metas = &reader.read_vvm_entry(manifest.metas_filename())?; let id = VoiceModelId::new(nanoid!()); - - Ok(Self { - header: VoiceModelHeader { - id, - metas, - manifest, - path, - }, - }) + let header = VoiceModelHeader::new(id, manifest, metas, path)?; + Ok(Self { header }) } /// ID。 @@ -177,12 +264,13 @@ pub(crate) mod blocking { }) } + // FIXME: manifest.json専用になっているので、そういう関数名にする fn read_vvm_json(&self, filename: &str) -> LoadModelResult { let bytes = &self.read_vvm_entry(filename)?; serde_json::from_slice(bytes).map_err(|source| LoadModelError { path: self.borrow_path().clone(), - context: LoadModelErrorKind::OpenZipFile, - source: Some(source.into()), + context: LoadModelErrorKind::InvalidModelFormat, + source: Some(anyhow::Error::from(source).context(format!("{filename}が不正です"))), }) } @@ -208,18 +296,18 @@ pub(crate) mod tokio { use derive_new::new; use enum_map::EnumMap; - use futures::future::join3; + use futures::future::{join3, OptionFuture}; use nanoid::nanoid; use serde::de::DeserializeOwned; use crate::{ error::{LoadModelError, LoadModelErrorKind, LoadModelResult}, - infer::domain::InferenceOperationImpl, - manifest::Manifest, + infer::domains::InferenceDomainMap, + manifest::{Manifest, TalkManifest}, Result, VoiceModelMeta, }; - use super::{VoiceModelHeader, VoiceModelId}; + use super::{ModelBytesWithInnerIdsByDomain, VoiceModelHeader, VoiceModelId}; /// 音声モデル。 /// @@ -232,42 +320,49 @@ pub(crate) mod tokio { impl self::VoiceModel { pub(crate) async fn read_inference_models( &self, - ) -> LoadModelResult>> { + ) -> LoadModelResult> { let reader = AsyncVvmEntryReader::open(&self.header.path).await?; - let ( - decode_model_result, - predict_duration_model_result, - predict_intonation_model_result, - ) = join3( - reader.read_vvm_entry(self.header.manifest.decode_filename()), - reader.read_vvm_entry(self.header.manifest.predict_duration_filename()), - reader.read_vvm_entry(self.header.manifest.predict_intonation_filename()), - ) - .await; - - Ok(EnumMap::from_array([ - predict_duration_model_result?, - predict_intonation_model_result?, - decode_model_result?, - ])) + + let talk = OptionFuture::from(self.header.manifest.domains().talk.as_ref().map( + |TalkManifest { + predict_duration_filename, + predict_intonation_filename, + decode_filename, + style_id_to_model_inner_id, + }| async { + let ( + decode_model_result, + predict_duration_model_result, + predict_intonation_model_result, + ) = join3( + reader.read_vvm_entry(decode_filename), + reader.read_vvm_entry(predict_duration_filename), + reader.read_vvm_entry(predict_intonation_filename), + ) + .await; + + let model_bytes = EnumMap::from_array([ + predict_duration_model_result?, + predict_intonation_model_result?, + decode_model_result?, + ]); + + Ok((style_id_to_model_inner_id.clone(), model_bytes)) + }, + )) + .await + .transpose()?; + + Ok(InferenceDomainMap { talk }) } /// VVMファイルから`VoiceModel`をコンストラクトする。 pub async fn from_path(path: impl AsRef) -> Result { let reader = AsyncVvmEntryReader::open(path.as_ref()).await?; let manifest = reader.read_vvm_json::("manifest.json").await?; - let metas = reader - .read_vvm_json::(manifest.metas_filename()) - .await?; + let metas = &reader.read_vvm_entry(manifest.metas_filename()).await?; let id = VoiceModelId::new(nanoid!()); - - Ok(Self { - header: VoiceModelHeader { - id, - metas, - manifest, - path: path.as_ref().into(), - }, - }) + let header = VoiceModelHeader::new(id, manifest, metas, path.as_ref())?; + Ok(Self { header }) } /// ID。 @@ -324,14 +419,13 @@ pub(crate) mod tokio { .collect(); Ok(AsyncVvmEntryReader::new(path, reader, entry_map)) } + // FIXME: manifest.json専用になっているので、そういう関数名にする async fn read_vvm_json(&self, filename: &str) -> LoadModelResult { let bytes = self.read_vvm_entry(filename).await?; serde_json::from_slice(&bytes).map_err(|source| LoadModelError { path: self.path.to_owned(), - context: LoadModelErrorKind::ReadZipEntry { - filename: filename.to_owned(), - }, - source: Some(source.into()), + context: LoadModelErrorKind::InvalidModelFormat, + source: Some(anyhow::Error::from(source).context(format!("{filename}が不正です"))), }) } @@ -357,3 +451,102 @@ pub(crate) mod tokio { } } } + +#[cfg(test)] +mod tests { + use once_cell::sync::Lazy; + use rstest::{fixture, rstest}; + use serde_json::json; + + use crate::{ + manifest::{ManifestDomains, TalkManifest}, + SpeakerMeta, StyleType, + }; + + #[rstest] + #[case( + &ManifestDomains { + talk: None, + }, + &[], + Ok(()) + )] + #[case( + &ManifestDomains { + talk: Some(TALK_MANIFEST.clone()), + }, + &[speaker(&[StyleType::Talk])], + Ok(()) + )] + #[case( + &ManifestDomains { + talk: Some(TALK_MANIFEST.clone()), + }, + &[speaker(&[StyleType::Talk, StyleType::Sing])], + Ok(()) + )] + #[case( + &ManifestDomains { + talk: None, + }, + &[speaker(&[StyleType::Talk])], + Err(()) + )] + fn check_acceptable_works( + #[case] manifest: &ManifestDomains, + #[case] metas: &[SpeakerMeta], + #[case] expected: std::result::Result<(), ()>, + ) { + let actual = manifest.check_acceptable(metas).map_err(|_| ()); + assert_eq!(expected, actual); + } + + static TALK_MANIFEST: Lazy = Lazy::new(|| TalkManifest { + predict_duration_filename: "".to_owned(), + predict_intonation_filename: "".to_owned(), + decode_filename: "".to_owned(), + style_id_to_model_inner_id: Default::default(), + }); + + #[fixture] + fn talk_speaker() -> SpeakerMeta { + serde_json::from_value(json!({ + "name": "dummy", + "styles": [ + { + "id": 0, + "name": "style1", + "type": "talk", + "order": 0 + } + ], + "version": "0.0.1", + "speaker_uuid": "574bc678-8370-44be-b941-08e46e7b47d7", + "order": 0 + })) + .unwrap() + } + + fn speaker(style_types: &'static [StyleType]) -> SpeakerMeta { + let styles = style_types + .iter() + .map(|style_type| { + json!({ + "id": 0, + "name": "style1", + "type": style_type, + "order": null + }) + }) + .collect::>(); + + serde_json::from_value(json!({ + "name": "dummy", + "styles": styles, + "version": "0.0.1", + "speaker_uuid": "574bc678-8370-44be-b941-08e46e7b47d7", + "order": null + })) + .unwrap() + } +} diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index 3d950f0e8..a6314f105 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -49,7 +49,6 @@ ndarray-stats.workspace = true regex.workspace = true serde = { workspace = true, features = ["derive"] } serde_with.workspace = true -strum = { workspace = true, features = ["derive"] } tempfile.workspace = true test_util.workspace = true toml.workspace = true diff --git a/crates/voicevox_core_c_api/include/voicevox_core.h b/crates/voicevox_core_c_api/include/voicevox_core.h index 2275bd1d7..592ec8abb 100644 --- a/crates/voicevox_core_c_api/include/voicevox_core.h +++ b/crates/voicevox_core_c_api/include/voicevox_core.h @@ -142,6 +142,10 @@ enum VoicevoxResultCode * ZIP内のファイルが読めなかった */ VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR = 17, + /** + * モデルの形式が不正 + */ + VOICEVOX_RESULT_INVALID_MODEL_HEADER_ERROR = 28, /** * すでに読み込まれている音声モデルを読み込もうとした */ diff --git a/crates/voicevox_core_c_api/src/helpers.rs b/crates/voicevox_core_c_api/src/helpers.rs index 74177db9c..1c163a0d0 100644 --- a/crates/voicevox_core_c_api/src/helpers.rs +++ b/crates/voicevox_core_c_api/src/helpers.rs @@ -37,6 +37,7 @@ pub(crate) fn into_result_code_with_error(result: CApiResult<()>) -> VoicevoxRes GpuSupport => VOICEVOX_RESULT_GPU_SUPPORT_ERROR, OpenZipFile => VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, ReadZipEntry => VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, + InvalidModelFormat => VOICEVOX_RESULT_INVALID_MODEL_HEADER_ERROR, ModelAlreadyLoaded => VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, StyleAlreadyLoaded => VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, InvalidModelData => VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, diff --git a/crates/voicevox_core_c_api/src/result_code.rs b/crates/voicevox_core_c_api/src/result_code.rs index 65236ada4..0897dfa87 100644 --- a/crates/voicevox_core_c_api/src/result_code.rs +++ b/crates/voicevox_core_c_api/src/result_code.rs @@ -37,6 +37,8 @@ pub enum VoicevoxResultCode { VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR = 16, /// ZIP内のファイルが読めなかった VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR = 17, + /// モデルの形式が不正 + VOICEVOX_RESULT_INVALID_MODEL_HEADER_ERROR = 28, /// すでに読み込まれている音声モデルを読み込もうとした VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR = 18, /// すでに読み込まれているスタイルを読み込もうとした @@ -90,6 +92,7 @@ pub(crate) const fn error_result_to_message(result_code: VoicevoxResultCode) -> VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR => { cstr!("ZIP内のファイルを読むことができませんでした") } + VOICEVOX_RESULT_INVALID_MODEL_HEADER_ERROR => cstr!("モデルの形式が不正です"), VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR => cstr!("同じIDのモデルを読むことはできません"), VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR => { cstr!("同じIDのスタイルを読むことはできません") diff --git a/crates/voicevox_core_c_api/tests/e2e/assert_cdylib.rs b/crates/voicevox_core_c_api/tests/e2e/assert_cdylib.rs index 11da69437..1e4958eda 100644 --- a/crates/voicevox_core_c_api/tests/e2e/assert_cdylib.rs +++ b/crates/voicevox_core_c_api/tests/e2e/assert_cdylib.rs @@ -36,7 +36,7 @@ pub(crate) fn exec() -> anyhow::Result<()> { let exec_c_api_e2e_test = serde_json::from_str::>(&exec_c_api_e2e_test)?; return unsafe { - let lib = &Library::new(C::cdylib_path())?; + let lib = Library::new(C::cdylib_path())?; exec_c_api_e2e_test.exec(lib) }; } @@ -113,7 +113,7 @@ pub(crate) trait TestCase: Send { /// /// `exec`は独立したプロセスで実行されるため、stdout/stderrへの出力をしたりグローバルな状態に /// 依存してもよい。 - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()>; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()>; /// 別プロセスで実行された`exec`の結果をチェックする。 fn assert_output(&self, output: Utf8Output) -> AssertResult; diff --git a/crates/voicevox_core_c_api/tests/e2e/main.rs b/crates/voicevox_core_c_api/tests/e2e/main.rs index b8d3165c6..91f5e06e9 100644 --- a/crates/voicevox_core_c_api/tests/e2e/main.rs +++ b/crates/voicevox_core_c_api/tests/e2e/main.rs @@ -1,15 +1,14 @@ +use test_util::c_api::VV_MODELS_ROOT_DIR; + mod assert_cdylib; mod float_assert; mod log_mask; mod snapshots; -mod symbols; mod testcases; // voicevox_core_c_apiのcdylibを対象にテストを行う。 // -// C APIの定義を変更する場合: -// 1. symbols.rsの実装を変更する。 -// 2. 1.によってコンパイルが通らなくなったら、適宜修正する。 +// C APIの定義を変更した場合は、テスト実行前に`cargo xtask update-c-header`を実行すること。 // // テストを追加する場合: // 1. testcases/{テスト名}.rsを追加し、testcases.rsでマウントする。 @@ -36,6 +35,6 @@ fn main() -> anyhow::Result<()> { ("ORT_USE_CUDA", "0"), ]; const RUNTIME_ENVS: &'static [(&'static str, &'static str)] = - &[("VV_MODELS_ROOT_DIR", "../../model")]; + &[("VV_MODELS_ROOT_DIR", VV_MODELS_ROOT_DIR)]; } } diff --git a/crates/voicevox_core_c_api/tests/e2e/snapshots.toml b/crates/voicevox_core_c_api/tests/e2e/snapshots.toml index 25926487e..151074cb3 100644 --- a/crates/voicevox_core_c_api/tests/e2e/snapshots.toml +++ b/crates/voicevox_core_c_api/tests/e2e/snapshots.toml @@ -7,6 +7,7 @@ metas = ''' { "id": 0, "name": "style1", + "type": "talk", "order": null } ], @@ -20,6 +21,7 @@ metas = ''' { "id": 1, "name": "style2", + "type": "talk", "order": null } ], @@ -33,11 +35,13 @@ metas = ''' { "id": 302, "name": "style3-1", + "type": "talk", "order": null }, { "id": 303, "name": "style3-2", + "type": "talk", "order": null } ], @@ -97,6 +101,7 @@ metas = ''' { "id": 0, "name": "style1", + "type": "talk", "order": null } ], @@ -110,6 +115,7 @@ metas = ''' { "id": 1, "name": "style2", + "type": "talk", "order": null } ], @@ -123,11 +129,13 @@ metas = ''' { "id": 302, "name": "style3-1", + "type": "talk", "order": null }, { "id": 303, "name": "style3-2", + "type": "talk", "order": null } ], diff --git a/crates/voicevox_core_c_api/tests/e2e/symbols.rs b/crates/voicevox_core_c_api/tests/e2e/symbols.rs deleted file mode 100644 index f6ecd4a3b..000000000 --- a/crates/voicevox_core_c_api/tests/e2e/symbols.rs +++ /dev/null @@ -1,334 +0,0 @@ -use std::ffi::{c_char, c_int, c_void}; - -use libloading::{Library, Symbol}; -use strum::EnumIter; - -/// voicevox\_core\_c\_apiのcdylibのシンボルを集めたもの。 -#[allow(dead_code)] // TODO: WIP -pub(crate) struct Symbols<'lib> { - pub(crate) voicevox_open_jtalk_rc_new: Symbol< - 'lib, - unsafe extern "C" fn(*const c_char, *mut *mut OpenJtalkRc) -> VoicevoxResultCode, - >, - pub(crate) voicevox_open_jtalk_rc_use_user_dict: Symbol< - 'lib, - unsafe extern "C" fn(*mut OpenJtalkRc, *const VoicevoxUserDict) -> VoicevoxResultCode, - >, - pub(crate) voicevox_open_jtalk_rc_delete: Symbol<'lib, unsafe extern "C" fn(*mut OpenJtalkRc)>, - pub(crate) voicevox_make_default_initialize_options: - Symbol<'lib, unsafe extern "C" fn() -> VoicevoxInitializeOptions>, - pub(crate) voicevox_get_version: Symbol<'lib, unsafe extern "C" fn() -> *const c_char>, - pub(crate) voicevox_voice_model_new_from_path: Symbol< - 'lib, - unsafe extern "C" fn(*const c_char, *mut *mut VoicevoxVoiceModel) -> VoicevoxResultCode, - >, - pub(crate) voicevox_voice_model_id: - Symbol<'lib, unsafe extern "C" fn(*const VoicevoxVoiceModel) -> VoicevoxVoiceModelId>, - pub(crate) voicevox_voice_model_get_metas_json: - Symbol<'lib, unsafe extern "C" fn(*const VoicevoxVoiceModel) -> *const c_char>, - pub(crate) voicevox_voice_model_delete: - Symbol<'lib, unsafe extern "C" fn(*mut VoicevoxVoiceModel)>, - pub(crate) voicevox_synthesizer_new: Symbol< - 'lib, - unsafe extern "C" fn( - *const OpenJtalkRc, - VoicevoxInitializeOptions, - *mut *mut VoicevoxSynthesizer, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_synthesizer_delete: - Symbol<'lib, unsafe extern "C" fn(*mut VoicevoxSynthesizer)>, - pub(crate) voicevox_synthesizer_load_voice_model: Symbol< - 'lib, - unsafe extern "C" fn( - *mut VoicevoxSynthesizer, - *const VoicevoxVoiceModel, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_synthesizer_unload_voice_model: Symbol< - 'lib, - unsafe extern "C" fn(*mut VoicevoxSynthesizer, VoicevoxVoiceModelId) -> VoicevoxResultCode, - >, - pub(crate) voicevox_synthesizer_is_gpu_mode: - Symbol<'lib, unsafe extern "C" fn(*const VoicevoxSynthesizer) -> bool>, - pub(crate) voicevox_synthesizer_is_loaded_voice_model: Symbol< - 'lib, - unsafe extern "C" fn(*const VoicevoxSynthesizer, VoicevoxVoiceModelId) -> bool, - >, - pub(crate) voicevox_synthesizer_create_metas_json: - Symbol<'lib, unsafe extern "C" fn(*const VoicevoxSynthesizer) -> *mut c_char>, - pub(crate) voicevox_create_supported_devices_json: - Symbol<'lib, unsafe extern "C" fn(*mut *mut c_char) -> VoicevoxResultCode>, - pub(crate) voicevox_synthesizer_create_audio_query_from_kana: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxSynthesizer, - *const c_char, - VoicevoxStyleId, - *mut *mut c_char, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_synthesizer_create_audio_query: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxSynthesizer, - *const c_char, - VoicevoxStyleId, - *mut *mut c_char, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_make_default_synthesis_options: - Symbol<'lib, unsafe extern "C" fn() -> VoicevoxSynthesisOptions>, - pub(crate) voicevox_synthesizer_synthesis: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxSynthesizer, - *const c_char, - VoicevoxStyleId, - VoicevoxSynthesisOptions, - *mut usize, - *mut *mut u8, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_make_default_tts_options: - Symbol<'lib, unsafe extern "C" fn() -> VoicevoxTtsOptions>, - pub(crate) voicevox_synthesizer_tts_from_kana: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxSynthesizer, - *const c_char, - VoicevoxStyleId, - VoicevoxTtsOptions, - *mut usize, - *mut *mut u8, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_synthesizer_tts: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxSynthesizer, - *const c_char, - VoicevoxStyleId, - VoicevoxTtsOptions, - *mut usize, - *mut *mut u8, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_json_free: Symbol<'lib, unsafe extern "C" fn(*mut c_char)>, - pub(crate) voicevox_wav_free: Symbol<'lib, unsafe extern "C" fn(*mut u8)>, - pub(crate) voicevox_error_result_to_message: - Symbol<'lib, unsafe extern "C" fn(VoicevoxResultCode) -> *const c_char>, - - pub(crate) initialize: Symbol<'lib, unsafe extern "C" fn(bool, c_int, bool) -> bool>, - pub(crate) load_model: Symbol<'lib, unsafe extern "C" fn(i64) -> bool>, - pub(crate) is_model_loaded: Symbol<'lib, unsafe extern "C" fn(i64) -> bool>, - pub(crate) finalize: Symbol<'lib, unsafe extern "C" fn()>, - pub(crate) metas: Symbol<'lib, unsafe extern "C" fn() -> *const c_char>, - pub(crate) last_error_message: Symbol<'lib, unsafe extern "C" fn() -> *const c_char>, - pub(crate) supported_devices: Symbol<'lib, unsafe extern "C" fn() -> *const c_char>, - pub(crate) yukarin_s_forward: - Symbol<'lib, unsafe extern "C" fn(i64, *mut i64, *mut i64, *mut f32) -> bool>, - pub(crate) yukarin_sa_forward: Symbol< - 'lib, - unsafe extern "C" fn( - i64, - *mut i64, - *mut i64, - *mut i64, - *mut i64, - *mut i64, - *mut i64, - *mut i64, - *mut f32, - ) -> bool, - >, - pub(crate) decode_forward: Symbol< - 'lib, - unsafe extern "C" fn(i64, i64, *mut f32, *mut f32, *mut i64, *mut f32) -> bool, - >, - - pub(crate) voicevox_user_dict_word_make: - Symbol<'lib, unsafe extern "C" fn(*const c_char, *const c_char) -> VoicevoxUserDictWord>, - pub(crate) voicevox_user_dict_new: - Symbol<'lib, unsafe extern "C" fn() -> *mut VoicevoxUserDict>, - pub(crate) voicevox_user_dict_load: Symbol< - 'lib, - unsafe extern "C" fn(*const VoicevoxUserDict, *const c_char) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_add_word: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxUserDict, - *const VoicevoxUserDictWord, - *mut [u8; 16], - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_update_word: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxUserDict, - *const [u8; 16], - *const VoicevoxUserDictWord, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_remove_word: Symbol< - 'lib, - unsafe extern "C" fn(*const VoicevoxUserDict, *const [u8; 16]) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_to_json: Symbol< - 'lib, - unsafe extern "C" fn(*const VoicevoxUserDict, *mut *mut c_char) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_import: Symbol< - 'lib, - unsafe extern "C" fn( - *const VoicevoxUserDict, - *const VoicevoxUserDict, - ) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_save: Symbol< - 'lib, - unsafe extern "C" fn(*const VoicevoxUserDict, *const c_char) -> VoicevoxResultCode, - >, - pub(crate) voicevox_user_dict_delete: - Symbol<'lib, unsafe extern "C" fn(*mut VoicevoxUserDict) -> VoicevoxResultCode>, -} - -impl<'lib> Symbols<'lib> { - pub(crate) unsafe fn new(lib: &'lib Library) -> Result { - macro_rules! new(($($name:ident),* $(,)?) => { - Self { - $( - $name: lib.get(stringify!($name).as_ref())?, - )* - } - }); - - Ok(new!( - voicevox_open_jtalk_rc_new, - voicevox_open_jtalk_rc_use_user_dict, - voicevox_open_jtalk_rc_delete, - voicevox_make_default_initialize_options, - voicevox_get_version, - voicevox_voice_model_new_from_path, - voicevox_voice_model_id, - voicevox_voice_model_get_metas_json, - voicevox_voice_model_delete, - voicevox_synthesizer_new, - voicevox_synthesizer_delete, - voicevox_synthesizer_load_voice_model, - voicevox_synthesizer_unload_voice_model, - voicevox_synthesizer_is_gpu_mode, - voicevox_synthesizer_is_loaded_voice_model, - voicevox_synthesizer_create_metas_json, - voicevox_create_supported_devices_json, - voicevox_synthesizer_create_audio_query_from_kana, - voicevox_synthesizer_create_audio_query, - voicevox_make_default_synthesis_options, - voicevox_synthesizer_synthesis, - voicevox_make_default_tts_options, - voicevox_synthesizer_tts_from_kana, - voicevox_synthesizer_tts, - voicevox_json_free, - voicevox_wav_free, - voicevox_error_result_to_message, - initialize, - load_model, - is_model_loaded, - finalize, - metas, - last_error_message, - supported_devices, - yukarin_s_forward, - yukarin_sa_forward, - decode_forward, - voicevox_user_dict_word_make, - voicevox_user_dict_new, - voicevox_user_dict_load, - voicevox_user_dict_add_word, - voicevox_user_dict_update_word, - voicevox_user_dict_remove_word, - voicevox_user_dict_to_json, - voicevox_user_dict_import, - voicevox_user_dict_save, - voicevox_user_dict_delete, - )) - } -} - -type OpenJtalkRc = c_void; -type VoicevoxVoiceModel = c_void; -type VoicevoxVoiceModelId = *const c_char; -type VoicevoxSynthesizer = c_void; -type VoicevoxStyleId = u32; - -#[repr(i32)] -#[derive(Debug, PartialEq, Eq, Clone, Copy, EnumIter)] -#[allow(non_camel_case_types)] -pub(crate) enum VoicevoxResultCode { - VOICEVOX_RESULT_OK = 0, - VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR = 1, - VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR = 3, - VOICEVOX_RESULT_GPU_SUPPORT_ERROR = 4, - VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR = 6, - VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR = 7, - VOICEVOX_RESULT_INFERENCE_ERROR = 8, - VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR = 11, - VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR = 12, - VOICEVOX_RESULT_PARSE_KANA_ERROR = 13, - VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR = 14, - VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR = 15, - VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR = 16, - VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR = 17, - VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR = 18, - VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR = 26, - VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR = 27, - VOICEVOX_RESULT_LOAD_USER_DICT_ERROR = 20, - VOICEVOX_RESULT_SAVE_USER_DICT_ERROR = 21, - VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR = 22, - VOICEVOX_RESULT_USE_USER_DICT_ERROR = 23, - VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR = 24, - VOICEVOX_RESULT_INVALID_UUID_ERROR = 25, -} - -#[repr(i32)] -#[allow(non_camel_case_types)] -pub(crate) enum VoicevoxAccelerationMode { - VOICEVOX_ACCELERATION_MODE_CPU = 1, -} - -#[repr(C)] -pub(crate) struct VoicevoxInitializeOptions { - pub(crate) acceleration_mode: VoicevoxAccelerationMode, - pub(crate) _cpu_num_threads: u16, -} - -#[repr(C)] -pub(crate) struct VoicevoxSynthesisOptions { - _enable_interrogative_upspeak: bool, -} - -#[repr(C)] -pub(crate) struct VoicevoxTtsOptions { - _enable_interrogative_upspeak: bool, -} - -#[repr(C)] -pub(crate) struct VoicevoxUserDict { - _private: [u8; 0], -} - -#[repr(C)] -pub(crate) struct VoicevoxUserDictWord { - pub(crate) surface: *const c_char, - pub(crate) pronunciation: *const c_char, - pub(crate) accent_type: usize, - pub(crate) word_type: VoicevoxUserDictWordType, - pub(crate) priority: u32, -} - -#[repr(i32)] -#[allow(non_camel_case_types)] -pub(crate) enum VoicevoxUserDictWordType { - VOICEVOX_USER_DICT_WORD_TYPE_PROPER_NOUN = 0, -} diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine.rs index 41968aa8f..c2fc211c2 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine.rs @@ -8,12 +8,11 @@ use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use voicevox_core::SupportedDevices; -use test_util::EXAMPLE_DATA; +use test_util::{c_api::CApi, EXAMPLE_DATA}; use crate::{ assert_cdylib::{self, case, Utf8Output}, float_assert, snapshots, - symbols::Symbols, }; case!(TestCase); @@ -23,43 +22,32 @@ struct TestCase; #[typetag::serde(name = "compatible_engine")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - initialize, - load_model, - is_model_loaded, - finalize, - metas, - supported_devices, - yukarin_s_forward, - yukarin_sa_forward, - decode_forward, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; let metas_json = { - let metas_json = metas(); + let metas_json = lib.metas(); let metas_json = CStr::from_ptr(metas_json).to_str()?; serde_json::to_string_pretty(&metas_json.parse::()?).unwrap() }; let supported_devices = { - let supported_devices = supported_devices(); + let supported_devices = lib.supported_devices(); CStr::from_ptr(supported_devices) .to_str()? .parse::()? }; - assert!(initialize(false, 0, false)); + assert!(lib.initialize(false, 0, false)); - assert!(!is_model_loaded(EXAMPLE_DATA.speaker_id)); - assert!(load_model(EXAMPLE_DATA.speaker_id)); - assert!(is_model_loaded(EXAMPLE_DATA.speaker_id)); + assert!(!lib.is_model_loaded(EXAMPLE_DATA.speaker_id)); + assert!(lib.load_model(EXAMPLE_DATA.speaker_id)); + assert!(lib.is_model_loaded(EXAMPLE_DATA.speaker_id)); // テスト用テキストは"t e s u t o" let phoneme_length = { let mut phoneme_length = [0.; 8]; - assert!(yukarin_s_forward( + assert!(lib.yukarin_s_forward( EXAMPLE_DATA.duration.length, EXAMPLE_DATA.duration.phoneme_vector.as_ptr() as *mut i64, &mut { EXAMPLE_DATA.speaker_id } as *mut i64, @@ -70,7 +58,7 @@ impl assert_cdylib::TestCase for TestCase { let intonation_list = { let mut intonation_list = [0.; 5]; - assert!(yukarin_sa_forward( + assert!(lib.yukarin_sa_forward( EXAMPLE_DATA.intonation.length, EXAMPLE_DATA.intonation.vowel_phoneme_vector.as_ptr() as *mut i64, EXAMPLE_DATA.intonation.consonant_phoneme_vector.as_ptr() as *mut i64, @@ -86,7 +74,7 @@ impl assert_cdylib::TestCase for TestCase { let wave = { let mut wave = vec![0.; 256 * EXAMPLE_DATA.decode.f0_length as usize]; - assert!(decode_forward( + assert!(lib.decode_forward( EXAMPLE_DATA.decode.f0_length, EXAMPLE_DATA.decode.phoneme_size, EXAMPLE_DATA.decode.f0_vector.as_ptr() as *mut f32, @@ -108,7 +96,7 @@ impl assert_cdylib::TestCase for TestCase { assert!(wave.iter().copied().all(f32::is_normal)); - finalize(); + lib.finalize(); Ok(()) } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine_load_model_before_initialize.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine_load_model_before_initialize.rs index 4ea024a98..173e32f8c 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine_load_model_before_initialize.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/compatible_engine_load_model_before_initialize.rs @@ -6,11 +6,11 @@ use assert_cmd::assert::AssertResult; use libloading::Library; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; +use test_util::c_api::CApi; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::Symbols, }; case!(TestCase); @@ -20,15 +20,11 @@ struct TestCase; #[typetag::serde(name = "compatible_engine_load_model_before_initialize")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - load_model, - last_error_message, - .. - } = Symbols::new(lib)?; - - assert!(!load_model(0)); - let last_error_message = last_error_message(); + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; + + assert!(!lib.load_model(0)); + let last_error_message = lib.last_error_message(); let last_error_message = CStr::from_ptr(last_error_message).to_str()?; std::assert_eq!(SNAPSHOTS.last_error_message, last_error_message); diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/global_info.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/global_info.rs index 200477b02..c6ea390ed 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/global_info.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/global_info.rs @@ -5,13 +5,12 @@ use libloading::Library; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; -use strum::IntoEnumIterator; +use test_util::c_api::{self, CApi, VoicevoxResultCode}; use voicevox_core::SupportedDevices; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxResultCode}, }; case!(TestCase); @@ -21,25 +20,17 @@ struct TestCase; #[typetag::serde(name = "global_info")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_get_version, - voicevox_create_supported_devices_json, - voicevox_error_result_to_message, - voicevox_json_free, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; std::assert_eq!( env!("CARGO_PKG_VERSION"), - CStr::from_ptr(voicevox_get_version()).to_str()?, + CStr::from_ptr(lib.voicevox_get_version()).to_str()?, ); { let mut supported_devices = MaybeUninit::uninit(); - assert_ok(voicevox_create_supported_devices_json( - supported_devices.as_mut_ptr(), - )); + assert_ok(lib.voicevox_create_supported_devices_json(supported_devices.as_mut_ptr())); let supported_devices = supported_devices.assume_init(); std::assert_eq!( SupportedDevices::create()?.to_json(), @@ -47,21 +38,45 @@ impl assert_cdylib::TestCase for TestCase { .to_str()? .parse::()?, ); - voicevox_json_free(supported_devices); + lib.voicevox_json_free(supported_devices); } - for result_code in VoicevoxResultCode::iter() { + for result_code in [ + c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_GPU_SUPPORT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INFERENCE_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_PARSE_KANA_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_LOAD_USER_DICT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_SAVE_USER_DICT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_USE_USER_DICT_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR, + c_api::VoicevoxResultCode_VOICEVOX_RESULT_INVALID_UUID_ERROR, + ] { std::assert_eq!( - SNAPSHOTS.result_messages[&(result_code as _)], + SNAPSHOTS.result_messages[&result_code], str::from_utf8( - CStr::from_ptr(voicevox_error_result_to_message(result_code)).to_bytes() + CStr::from_ptr(lib.voicevox_error_result_to_message(result_code)).to_bytes() )?, ); } return Ok(()); fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/simple_tts.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/simple_tts.rs index 9631249fa..4ac4030e1 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/simple_tts.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/simple_tts.rs @@ -1,16 +1,17 @@ use std::{collections::HashMap, ffi::CString, mem::MaybeUninit}; use assert_cmd::assert::AssertResult; -use cstr::cstr; use libloading::Library; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use test_util::OPEN_JTALK_DIC_DIR; +use test_util::{ + c_api::{self, CApi, VoicevoxInitializeOptions, VoicevoxResultCode}, + OPEN_JTALK_DIC_DIR, +}; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxAccelerationMode, VoicevoxInitializeOptions, VoicevoxResultCode}, }; case!(TestCase { @@ -24,26 +25,13 @@ struct TestCase { #[typetag::serde(name = "simple_tts")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_open_jtalk_rc_new, - voicevox_open_jtalk_rc_delete, - voicevox_make_default_initialize_options, - voicevox_voice_model_new_from_path, - voicevox_voice_model_delete, - voicevox_synthesizer_new, - voicevox_synthesizer_delete, - voicevox_synthesizer_load_voice_model, - voicevox_make_default_tts_options, - voicevox_synthesizer_tts, - voicevox_wav_free, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; let model = { let mut model = MaybeUninit::uninit(); - assert_ok(voicevox_voice_model_new_from_path( - cstr!("../../model/sample.vvm").as_ptr(), + assert_ok(lib.voicevox_voice_model_new_from_path( + c_api::SAMPLE_VOICE_MODEL_FILE_PATH.as_ptr(), model.as_mut_ptr(), )); model.assume_init() @@ -52,37 +40,37 @@ impl assert_cdylib::TestCase for TestCase { let openjtalk = { let mut openjtalk = MaybeUninit::uninit(); let open_jtalk_dic_dir = CString::new(OPEN_JTALK_DIC_DIR).unwrap(); - assert_ok(voicevox_open_jtalk_rc_new( - open_jtalk_dic_dir.as_ptr(), - openjtalk.as_mut_ptr(), - )); + assert_ok( + lib.voicevox_open_jtalk_rc_new(open_jtalk_dic_dir.as_ptr(), openjtalk.as_mut_ptr()), + ); openjtalk.assume_init() }; let synthesizer = { let mut synthesizer = MaybeUninit::uninit(); - assert_ok(voicevox_synthesizer_new( + assert_ok(lib.voicevox_synthesizer_new( openjtalk, VoicevoxInitializeOptions { - acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + acceleration_mode: + c_api::VoicevoxAccelerationMode_VOICEVOX_ACCELERATION_MODE_CPU, + ..lib.voicevox_make_default_initialize_options() }, synthesizer.as_mut_ptr(), )); synthesizer.assume_init() }; - assert_ok(voicevox_synthesizer_load_voice_model(synthesizer, model)); + assert_ok(lib.voicevox_synthesizer_load_voice_model(synthesizer, model)); let (wav_length, wav) = { let mut wav_length = MaybeUninit::uninit(); let mut wav = MaybeUninit::uninit(); let text = CString::new(&*self.text).unwrap(); - assert_ok(voicevox_synthesizer_tts( + assert_ok(lib.voicevox_synthesizer_tts( synthesizer, text.as_ptr(), STYLE_ID, - voicevox_make_default_tts_options(), + lib.voicevox_make_default_tts_options(), wav_length.as_mut_ptr(), wav.as_mut_ptr(), )); @@ -91,17 +79,17 @@ impl assert_cdylib::TestCase for TestCase { std::assert_eq!(SNAPSHOTS.output[&self.text].wav_length, wav_length); - voicevox_voice_model_delete(model); - voicevox_open_jtalk_rc_delete(openjtalk); - voicevox_synthesizer_delete(synthesizer); - voicevox_wav_free(wav); + lib.voicevox_voice_model_delete(model); + lib.voicevox_open_jtalk_rc_delete(openjtalk); + lib.voicevox_synthesizer_delete(synthesizer); + lib.voicevox_wav_free(wav); return Ok(()); const STYLE_ID: u32 = 0; fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/synthesizer_new_output_json.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/synthesizer_new_output_json.rs index a836a409c..c27bd4703 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/synthesizer_new_output_json.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/synthesizer_new_output_json.rs @@ -4,17 +4,18 @@ use std::{ }; use assert_cmd::assert::AssertResult; -use cstr::cstr; use libloading::Library; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use test_util::OPEN_JTALK_DIC_DIR; +use test_util::{ + c_api::{self, CApi, VoicevoxInitializeOptions, VoicevoxResultCode}, + OPEN_JTALK_DIC_DIR, +}; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxAccelerationMode, VoicevoxInitializeOptions, VoicevoxResultCode}, }; case!(TestCase); @@ -24,37 +25,26 @@ struct TestCase; #[typetag::serde(name = "synthesizer_new_output_json")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_make_default_initialize_options, - voicevox_voice_model_new_from_path, - voicevox_open_jtalk_rc_new, - voicevox_open_jtalk_rc_delete, - voicevox_synthesizer_new, - voicevox_synthesizer_delete, - voicevox_synthesizer_create_metas_json, - voicevox_synthesizer_load_voice_model, - voicevox_json_free, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; let openjtalk = { let mut openjtalk = MaybeUninit::uninit(); let open_jtalk_dic_dir = CString::new(OPEN_JTALK_DIC_DIR).unwrap(); - assert_ok(voicevox_open_jtalk_rc_new( - open_jtalk_dic_dir.as_ptr(), - openjtalk.as_mut_ptr(), - )); + assert_ok( + lib.voicevox_open_jtalk_rc_new(open_jtalk_dic_dir.as_ptr(), openjtalk.as_mut_ptr()), + ); openjtalk.assume_init() }; let synthesizer = { let mut synthesizer = MaybeUninit::uninit(); - assert_ok(voicevox_synthesizer_new( + assert_ok(lib.voicevox_synthesizer_new( openjtalk, VoicevoxInitializeOptions { - acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + acceleration_mode: + c_api::VoicevoxAccelerationMode_VOICEVOX_ACCELERATION_MODE_CPU, + ..lib.voicevox_make_default_initialize_options() }, synthesizer.as_mut_ptr(), )); @@ -63,32 +53,32 @@ impl assert_cdylib::TestCase for TestCase { let model = { let mut model = MaybeUninit::uninit(); - assert_ok(voicevox_voice_model_new_from_path( - cstr!("../../model/sample.vvm").as_ptr(), + assert_ok(lib.voicevox_voice_model_new_from_path( + c_api::SAMPLE_VOICE_MODEL_FILE_PATH.as_ptr(), model.as_mut_ptr(), )); model.assume_init() }; - assert_ok(voicevox_synthesizer_load_voice_model(synthesizer, model)); + assert_ok(lib.voicevox_synthesizer_load_voice_model(synthesizer, model)); let metas_json = { - let raw = voicevox_synthesizer_create_metas_json(synthesizer); + let raw = lib.voicevox_synthesizer_create_metas_json(synthesizer); let metas_json = &CStr::from_ptr(raw).to_str()?.parse::()?; let metas_json = serde_json::to_string_pretty(metas_json).unwrap(); - voicevox_json_free(raw); + lib.voicevox_json_free(raw); metas_json }; std::assert_eq!(SNAPSHOTS.metas, metas_json); - voicevox_open_jtalk_rc_delete(openjtalk); - voicevox_synthesizer_delete(synthesizer); + lib.voicevox_open_jtalk_rc_delete(openjtalk); + lib.voicevox_synthesizer_delete(synthesizer); return Ok(()); fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/tts_via_audio_query.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/tts_via_audio_query.rs index 6cfe7994e..d380b71b2 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/tts_via_audio_query.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/tts_via_audio_query.rs @@ -1,16 +1,17 @@ use std::{collections::HashMap, ffi::CString, mem::MaybeUninit}; use assert_cmd::assert::AssertResult; -use cstr::cstr; use libloading::Library; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use test_util::OPEN_JTALK_DIC_DIR; +use test_util::{ + c_api::{self, CApi, VoicevoxInitializeOptions, VoicevoxResultCode}, + OPEN_JTALK_DIC_DIR, +}; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxAccelerationMode, VoicevoxInitializeOptions, VoicevoxResultCode}, }; case!(TestCase { @@ -24,28 +25,13 @@ struct TestCase { #[typetag::serde(name = "tts_via_audio_query")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_open_jtalk_rc_new, - voicevox_open_jtalk_rc_delete, - voicevox_make_default_initialize_options, - voicevox_voice_model_new_from_path, - voicevox_voice_model_delete, - voicevox_synthesizer_new, - voicevox_synthesizer_delete, - voicevox_synthesizer_load_voice_model, - voicevox_synthesizer_create_audio_query, - voicevox_make_default_synthesis_options, - voicevox_synthesizer_synthesis, - voicevox_json_free, - voicevox_wav_free, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; let model = { let mut model = MaybeUninit::uninit(); - assert_ok(voicevox_voice_model_new_from_path( - cstr!("../../model/sample.vvm").as_ptr(), + assert_ok(lib.voicevox_voice_model_new_from_path( + c_api::SAMPLE_VOICE_MODEL_FILE_PATH.as_ptr(), model.as_mut_ptr(), )); model.assume_init() @@ -54,32 +40,32 @@ impl assert_cdylib::TestCase for TestCase { let openjtalk = { let mut openjtalk = MaybeUninit::uninit(); let open_jtalk_dic_dir = CString::new(OPEN_JTALK_DIC_DIR).unwrap(); - assert_ok(voicevox_open_jtalk_rc_new( - open_jtalk_dic_dir.as_ptr(), - openjtalk.as_mut_ptr(), - )); + assert_ok( + lib.voicevox_open_jtalk_rc_new(open_jtalk_dic_dir.as_ptr(), openjtalk.as_mut_ptr()), + ); openjtalk.assume_init() }; let synthesizer = { let mut synthesizer = MaybeUninit::uninit(); - assert_ok(voicevox_synthesizer_new( + assert_ok(lib.voicevox_synthesizer_new( openjtalk, VoicevoxInitializeOptions { - acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + acceleration_mode: + c_api::VoicevoxAccelerationMode_VOICEVOX_ACCELERATION_MODE_CPU, + ..lib.voicevox_make_default_initialize_options() }, synthesizer.as_mut_ptr(), )); synthesizer.assume_init() }; - assert_ok(voicevox_synthesizer_load_voice_model(synthesizer, model)); + assert_ok(lib.voicevox_synthesizer_load_voice_model(synthesizer, model)); let audio_query = { let mut audio_query = MaybeUninit::uninit(); let text = CString::new(&*self.text).unwrap(); - assert_ok(voicevox_synthesizer_create_audio_query( + assert_ok(lib.voicevox_synthesizer_create_audio_query( synthesizer, text.as_ptr(), STYLE_ID, @@ -91,11 +77,11 @@ impl assert_cdylib::TestCase for TestCase { let (wav_length, wav) = { let mut wav_length = MaybeUninit::uninit(); let mut wav = MaybeUninit::uninit(); - assert_ok(voicevox_synthesizer_synthesis( + assert_ok(lib.voicevox_synthesizer_synthesis( synthesizer, audio_query, STYLE_ID, - voicevox_make_default_synthesis_options(), + lib.voicevox_make_default_synthesis_options(), wav_length.as_mut_ptr(), wav.as_mut_ptr(), )); @@ -104,18 +90,18 @@ impl assert_cdylib::TestCase for TestCase { std::assert_eq!(SNAPSHOTS.output[&self.text].wav_length, wav_length); - voicevox_voice_model_delete(model); - voicevox_open_jtalk_rc_delete(openjtalk); - voicevox_synthesizer_delete(synthesizer); - voicevox_json_free(audio_query); - voicevox_wav_free(wav); + lib.voicevox_voice_model_delete(model); + lib.voicevox_open_jtalk_rc_delete(openjtalk); + lib.voicevox_synthesizer_delete(synthesizer); + lib.voicevox_json_free(audio_query); + lib.voicevox_wav_free(wav); return Ok(()); const STYLE_ID: u32 = 0; fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_load.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_load.rs index 7c2e13afe..2e6875e97 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_load.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_load.rs @@ -1,7 +1,6 @@ // ユーザー辞書の登録によって読みが変化することを確認するテスト。 // 辞書ロード前後でAudioQueryのkanaが変化するかどうかで確認する。 -use crate::symbols::{VoicevoxInitializeOptions, VoicevoxResultCode}; use assert_cmd::assert::AssertResult; use once_cell::sync::Lazy; use std::ffi::{CStr, CString}; @@ -11,11 +10,11 @@ use test_util::OPEN_JTALK_DIC_DIR; use cstr::cstr; use libloading::Library; use serde::{Deserialize, Serialize}; +use test_util::c_api::{self, CApi, VoicevoxInitializeOptions, VoicevoxResultCode}; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxAccelerationMode, VoicevoxUserDictWordType}, }; case!(TestCase); @@ -25,46 +24,31 @@ struct TestCase; #[typetag::serde(name = "user_dict_load")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_user_dict_word_make, - voicevox_user_dict_new, - voicevox_user_dict_add_word, - voicevox_user_dict_delete, - voicevox_make_default_initialize_options, - voicevox_open_jtalk_rc_new, - voicevox_open_jtalk_rc_use_user_dict, - voicevox_open_jtalk_rc_delete, - voicevox_voice_model_new_from_path, - voicevox_voice_model_delete, - voicevox_synthesizer_new, - voicevox_synthesizer_delete, - voicevox_synthesizer_load_voice_model, - voicevox_synthesizer_create_audio_query, - .. - } = Symbols::new(lib)?; - - let dict = voicevox_user_dict_new(); + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; + + let dict = lib.voicevox_user_dict_new(); let mut word_uuid = [0u8; 16]; let word = { - let mut word = voicevox_user_dict_word_make( + let mut word = lib.voicevox_user_dict_word_make( cstr!("this_word_should_not_exist_in_default_dictionary").as_ptr(), cstr!("アイウエオ").as_ptr(), ); - word.word_type = VoicevoxUserDictWordType::VOICEVOX_USER_DICT_WORD_TYPE_PROPER_NOUN; + word.word_type = + c_api::VoicevoxUserDictWordType_VOICEVOX_USER_DICT_WORD_TYPE_PROPER_NOUN; word.priority = 10; word }; - assert_ok(voicevox_user_dict_add_word(dict, &word, &mut word_uuid)); + assert_ok(lib.voicevox_user_dict_add_word(dict, &word, &mut word_uuid)); let model = { let mut model = MaybeUninit::uninit(); - assert_ok(voicevox_voice_model_new_from_path( - cstr!("../../model/sample.vvm").as_ptr(), + assert_ok(lib.voicevox_voice_model_new_from_path( + c_api::SAMPLE_VOICE_MODEL_FILE_PATH.as_ptr(), model.as_mut_ptr(), )); model.assume_init() @@ -73,30 +57,30 @@ impl assert_cdylib::TestCase for TestCase { let openjtalk = { let mut openjtalk = MaybeUninit::uninit(); let open_jtalk_dic_dir = CString::new(OPEN_JTALK_DIC_DIR).unwrap(); - assert_ok(voicevox_open_jtalk_rc_new( - open_jtalk_dic_dir.as_ptr(), - openjtalk.as_mut_ptr(), - )); + assert_ok( + lib.voicevox_open_jtalk_rc_new(open_jtalk_dic_dir.as_ptr(), openjtalk.as_mut_ptr()), + ); openjtalk.assume_init() }; let synthesizer = { let mut synthesizer = MaybeUninit::uninit(); - assert_ok(voicevox_synthesizer_new( + assert_ok(lib.voicevox_synthesizer_new( openjtalk, VoicevoxInitializeOptions { - acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + acceleration_mode: + c_api::VoicevoxAccelerationMode_VOICEVOX_ACCELERATION_MODE_CPU, + ..lib.voicevox_make_default_initialize_options() }, synthesizer.as_mut_ptr(), )); synthesizer.assume_init() }; - assert_ok(voicevox_synthesizer_load_voice_model(synthesizer, model)); + assert_ok(lib.voicevox_synthesizer_load_voice_model(synthesizer, model)); let mut audio_query_without_dict = std::ptr::null_mut(); - assert_ok(voicevox_synthesizer_create_audio_query( + assert_ok(lib.voicevox_synthesizer_create_audio_query( synthesizer, cstr!("this_word_should_not_exist_in_default_dictionary").as_ptr(), STYLE_ID, @@ -106,10 +90,10 @@ impl assert_cdylib::TestCase for TestCase { CStr::from_ptr(audio_query_without_dict).to_str()?, )?; - assert_ok(voicevox_open_jtalk_rc_use_user_dict(openjtalk, dict)); + assert_ok(lib.voicevox_open_jtalk_rc_use_user_dict(openjtalk, dict)); let mut audio_query_with_dict = std::ptr::null_mut(); - assert_ok(voicevox_synthesizer_create_audio_query( + assert_ok(lib.voicevox_synthesizer_create_audio_query( synthesizer, cstr!("this_word_should_not_exist_in_default_dictionary").as_ptr(), STYLE_ID, @@ -125,15 +109,15 @@ impl assert_cdylib::TestCase for TestCase { audio_query_with_dict.get("kana") ); - voicevox_voice_model_delete(model); - voicevox_open_jtalk_rc_delete(openjtalk); - voicevox_synthesizer_delete(synthesizer); - voicevox_user_dict_delete(dict); + lib.voicevox_voice_model_delete(model); + lib.voicevox_open_jtalk_rc_delete(openjtalk); + lib.voicevox_synthesizer_delete(synthesizer); + lib.voicevox_user_dict_delete(dict); return Ok(()); fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } const STYLE_ID: u32 = 0; } diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_manipulate.rs b/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_manipulate.rs index 15b80686f..fd3d575e3 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_manipulate.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/user_dict_manipulate.rs @@ -12,11 +12,11 @@ use uuid::Uuid; use cstr::cstr; use libloading::Library; use serde::{Deserialize, Serialize}; +use test_util::c_api::{self, CApi, VoicevoxResultCode, VoicevoxUserDict, VoicevoxUserDictWord}; use crate::{ assert_cdylib::{self, case, Utf8Output}, snapshots, - symbols::{Symbols, VoicevoxResultCode, VoicevoxUserDict, VoicevoxUserDictWord}, }; case!(TestCase); @@ -26,35 +26,19 @@ struct TestCase; #[typetag::serde(name = "user_dict_manipulate")] impl assert_cdylib::TestCase for TestCase { - unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { - let Symbols { - voicevox_user_dict_word_make, - voicevox_user_dict_new, - voicevox_user_dict_add_word, - voicevox_user_dict_update_word, - voicevox_user_dict_remove_word, - voicevox_user_dict_to_json, - voicevox_user_dict_import, - voicevox_user_dict_load, - voicevox_user_dict_save, - voicevox_user_dict_delete, - voicevox_json_free, - .. - } = Symbols::new(lib)?; + unsafe fn exec(&self, lib: Library) -> anyhow::Result<()> { + let lib = CApi::from_library(lib)?; let get_json = |dict: &*mut VoicevoxUserDict| -> String { let mut json = MaybeUninit::uninit(); - assert_ok(voicevox_user_dict_to_json( - (*dict) as *const _, - json.as_mut_ptr(), - )); + assert_ok(lib.voicevox_user_dict_to_json((*dict) as *const _, json.as_mut_ptr())); let ret = CStr::from_ptr(json.assume_init()) .to_str() .unwrap() .to_string(); - voicevox_json_free(json.assume_init()); + lib.voicevox_json_free(json.assume_init()); serde_json::from_str::(&ret).expect("invalid json"); @@ -64,20 +48,16 @@ impl assert_cdylib::TestCase for TestCase { let add_word = |dict: *const VoicevoxUserDict, word: &VoicevoxUserDictWord| -> Uuid { let mut word_uuid = [0u8; 16]; - assert_ok(voicevox_user_dict_add_word( - dict, - word as *const _, - &mut word_uuid, - )); + assert_ok(lib.voicevox_user_dict_add_word(dict, word as *const _, &mut word_uuid)); Uuid::from_slice(&word_uuid).expect("invalid uuid") }; // テスト用の辞書ファイルを作成 - let dict = voicevox_user_dict_new(); + let dict = lib.voicevox_user_dict_new(); // 単語の追加のテスト - let word = voicevox_user_dict_word_make(cstr!("hoge").as_ptr(), cstr!("ホゲ").as_ptr()); + let word = lib.voicevox_user_dict_word_make(cstr!("hoge").as_ptr(), cstr!("ホゲ").as_ptr()); let word_uuid = add_word(dict, &word); @@ -88,13 +68,9 @@ impl assert_cdylib::TestCase for TestCase { assert_contains_uuid(&json, &word_uuid); // 単語の変更のテスト - let word = voicevox_user_dict_word_make(cstr!("fuga").as_ptr(), cstr!("フガ").as_ptr()); + let word = lib.voicevox_user_dict_word_make(cstr!("fuga").as_ptr(), cstr!("フガ").as_ptr()); - assert_ok(voicevox_user_dict_update_word( - dict, - &word_uuid.into_bytes(), - &word, - )); + assert_ok(lib.voicevox_user_dict_update_word(dict, &word_uuid.into_bytes(), &word)); let json = get_json(&dict); @@ -105,14 +81,14 @@ impl assert_cdylib::TestCase for TestCase { assert_contains_uuid(&json, &word_uuid); // 辞書のインポートのテスト。 - let other_dict = voicevox_user_dict_new(); + let other_dict = lib.voicevox_user_dict_new(); let other_word = - voicevox_user_dict_word_make(cstr!("piyo").as_ptr(), cstr!("ピヨ").as_ptr()); + lib.voicevox_user_dict_word_make(cstr!("piyo").as_ptr(), cstr!("ピヨ").as_ptr()); let other_word_uuid = add_word(other_dict, &other_word); - assert_ok(voicevox_user_dict_import(dict, other_dict)); + assert_ok(lib.voicevox_user_dict_import(dict, other_dict)); let json = get_json(&dict); assert!(json.contains("fuga")); @@ -123,10 +99,7 @@ impl assert_cdylib::TestCase for TestCase { assert_contains_uuid(&json, &other_word_uuid); // 単語の削除のテスト - assert_ok(voicevox_user_dict_remove_word( - dict, - &word_uuid.into_bytes(), - )); + assert_ok(lib.voicevox_user_dict_remove_word(dict, &word_uuid.into_bytes())); let json = get_json(&dict); assert_not_contains_uuid(&json, &word_uuid); @@ -136,23 +109,23 @@ impl assert_cdylib::TestCase for TestCase { // 辞書のセーブ・ロードのテスト let temp_path = NamedTempFile::new().unwrap().into_temp_path(); let temp_path = CString::new(temp_path.to_str().unwrap()).unwrap(); - let word = voicevox_user_dict_word_make(cstr!("hoge").as_ptr(), cstr!("ホゲ").as_ptr()); + let word = lib.voicevox_user_dict_word_make(cstr!("hoge").as_ptr(), cstr!("ホゲ").as_ptr()); let word_uuid = add_word(dict, &word); - assert_ok(voicevox_user_dict_save(dict, temp_path.as_ptr())); - assert_ok(voicevox_user_dict_load(other_dict, temp_path.as_ptr())); + assert_ok(lib.voicevox_user_dict_save(dict, temp_path.as_ptr())); + assert_ok(lib.voicevox_user_dict_load(other_dict, temp_path.as_ptr())); let json = get_json(&other_dict); assert_contains_uuid(&json, &word_uuid); assert_contains_uuid(&json, &other_word_uuid); - voicevox_user_dict_delete(dict); - voicevox_user_dict_delete(other_dict); + lib.voicevox_user_dict_delete(dict); + lib.voicevox_user_dict_delete(other_dict); return Ok(()); fn assert_ok(result_code: VoicevoxResultCode) { - std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + std::assert_eq!(c_api::VoicevoxResultCode_VOICEVOX_RESULT_OK, result_code); } fn assert_contains_uuid(text: &str, pattern: &Uuid) { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java index ba4881566..576629515 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java @@ -103,6 +103,12 @@ public static class StyleMeta { @Expose public final int id; + /** スタイルに対応するモデルの種類。 */ + @SerializedName("type") + @Expose + @Nonnull + public final StyleType type; + /** * 話者の順番。 * @@ -116,7 +122,16 @@ public static class StyleMeta { private StyleMeta() { this.name = ""; this.id = 0; + this.type = StyleType.TALK; this.order = null; } } + + /** スタイル(style)に対応するモデルの種類。 */ + public static enum StyleType { + /** 音声合成クエリの作成と音声合成が可能。 */ + @SerializedName("talk") + @Expose + TALK, + } } diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/exceptions/InvalidModelFormatException.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/exceptions/InvalidModelFormatException.java new file mode 100644 index 000000000..b82016164 --- /dev/null +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/exceptions/InvalidModelFormatException.java @@ -0,0 +1,14 @@ +package jp.hiroshiba.voicevoxcore.exceptions; + +import java.io.IOException; + +/** モデルの形式が不正。 */ +public class InvalidModelFormatException extends IOException { + public InvalidModelFormatException(String message) { + super(message); + } + + public InvalidModelFormatException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/MetaTest.java b/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/MetaTest.java index 741f84e79..60df7359f 100644 --- a/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/MetaTest.java +++ b/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/MetaTest.java @@ -13,7 +13,7 @@ class MetaTest { void checkLoad() { // cwdはvoicevox_core/crates/voicevox_core_java_api/lib String cwd = System.getProperty("user.dir"); - File path = new File(cwd + "/../../../model/sample.vvm"); + File path = new File(cwd + "/../../test_util/data/model/sample.vvm"); VoiceModel model = new VoiceModel(path.getAbsolutePath()); assertNotNull(model.metas); } diff --git a/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/TestUtils.java b/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/TestUtils.java index 670eddbdb..032c38a3d 100644 --- a/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/TestUtils.java +++ b/crates/voicevox_core_java_api/lib/src/test/java/jp/hiroshiba/voicevoxcore/TestUtils.java @@ -6,7 +6,7 @@ class TestUtils { VoiceModel loadModel() { // cwdはvoicevox_core/crates/voicevox_core_java_api/lib String cwd = System.getProperty("user.dir"); - File path = new File(cwd + "/../../../model/sample.vvm"); + File path = new File(cwd + "/../../test_util/data/model/sample.vvm"); try { return new VoiceModel(path.getCanonicalPath()); diff --git a/crates/voicevox_core_java_api/src/common.rs b/crates/voicevox_core_java_api/src/common.rs index 71a60f5f3..bdb37f4ff 100644 --- a/crates/voicevox_core_java_api/src/common.rs +++ b/crates/voicevox_core_java_api/src/common.rs @@ -69,6 +69,7 @@ where GpuSupport, OpenZipFile, ReadZipEntry, + InvalidModelFormat, ModelAlreadyLoaded, StyleAlreadyLoaded, InvalidModelData, diff --git a/crates/voicevox_core_macros/src/lib.rs b/crates/voicevox_core_macros/src/lib.rs index 5f2f26809..98a2fdc5c 100644 --- a/crates/voicevox_core_macros/src/lib.rs +++ b/crates/voicevox_core_macros/src/lib.rs @@ -17,17 +17,18 @@ use syn::parse_macro_input; /// use enum_map::Enum; /// use macros::InferenceOperation; /// -/// pub(crate) enum InferenceDomainImpl {} +/// pub(crate) enum TalkDomain {} /// -/// impl InferenceDomain for InferenceDomainImpl { -/// type Operation = InferenceOperationImpl; +/// impl InferenceDomain for TalkDomain { +/// type Operation = TalkOperation; +/// // ... /// } /// /// #[derive(Clone, Copy, Enum, InferenceOperation)] /// #[inference_operation( -/// type Domain = InferenceDomainImpl; +/// type Domain = TalkDomain; /// )] -/// pub(crate) enum InferenceOperationImpl { +/// pub(crate) enum TalkOperation { /// #[inference_operation( /// type Input = PredictDurationInput; /// type Output = PredictDurationOutput; diff --git a/crates/voicevox_core_python_api/python/test/conftest.py b/crates/voicevox_core_python_api/python/test/conftest.py index 628f4dc56..eec642cb9 100644 --- a/crates/voicevox_core_python_api/python/test/conftest.py +++ b/crates/voicevox_core_python_api/python/test/conftest.py @@ -10,7 +10,9 @@ open_jtalk_dic_dir = ( root_dir.parent.parent.parent / "test_util" / "data" / "open_jtalk_dic_utf_8-1.11" ) -model_dir = root_dir.parent.parent.parent.parent / "model" / "sample.vvm" +model_dir = ( + root_dir.parent.parent.parent / "test_util" / "data" / "model" / "sample.vvm" +) class DurationExampleData(TypedDict): diff --git a/crates/voicevox_core_python_api/python/test/test_asyncio_metas.py b/crates/voicevox_core_python_api/python/test/test_asyncio_metas.py new file mode 100644 index 000000000..ec69032b1 --- /dev/null +++ b/crates/voicevox_core_python_api/python/test/test_asyncio_metas.py @@ -0,0 +1,26 @@ +""" +メタ情報の出力が可能かどうかをテストする。 + +``test_blocking_metas`` と対になる。 +""" + +import conftest +import pytest +import pytest_asyncio +from voicevox_core.asyncio import OpenJtalk, Synthesizer, VoiceModel + + +def test_voice_model_metas_works(voice_model: VoiceModel) -> None: + _ = voice_model.metas + + +@pytest.mark.asyncio +async def test_synthesizer_metas_works(voice_model: VoiceModel) -> None: + synthesizer = Synthesizer(await OpenJtalk.new(conftest.open_jtalk_dic_dir)) + await synthesizer.load_voice_model(voice_model) + _ = synthesizer.metas + + +@pytest_asyncio.fixture +async def voice_model() -> VoiceModel: + return await VoiceModel.from_path(conftest.model_dir) diff --git a/crates/voicevox_core_python_api/python/test/test_blocking_metas.py b/crates/voicevox_core_python_api/python/test/test_blocking_metas.py new file mode 100644 index 000000000..c305e2cdb --- /dev/null +++ b/crates/voicevox_core_python_api/python/test/test_blocking_metas.py @@ -0,0 +1,24 @@ +""" +メタ情報の出力が可能かどうかをテストする。 + +``test_asyncio_metas`` と対になる。 +""" + +import conftest +import pytest +from voicevox_core.blocking import OpenJtalk, Synthesizer, VoiceModel + + +def test_voice_model_metas_works(voice_model: VoiceModel) -> None: + _ = voice_model.metas + + +def test_synthesizer_metas_works(voice_model: VoiceModel) -> None: + synthesizer = Synthesizer(OpenJtalk(conftest.open_jtalk_dic_dir)) + synthesizer.load_voice_model(voice_model) + _ = synthesizer.metas + + +@pytest.fixture +def voice_model() -> VoiceModel: + return VoiceModel.from_path(conftest.model_dir) diff --git a/crates/voicevox_core_python_api/python/voicevox_core/_models.py b/crates/voicevox_core_python_api/python/voicevox_core/_models.py index c72bbcbf0..21a2016fe 100644 --- a/crates/voicevox_core_python_api/python/voicevox_core/_models.py +++ b/crates/voicevox_core_python_api/python/voicevox_core/_models.py @@ -34,6 +34,13 @@ """ +class StyleType(str, Enum): + """**スタイル** (_style_)に対応するモデルの種類。""" + + TALK = "talk" + """音声合成クエリの作成と音声合成が可能。""" + + @pydantic.dataclasses.dataclass class StyleMeta: """**スタイル** (_style_)のメタ情報。""" @@ -44,6 +51,9 @@ class StyleMeta: id: StyleId """スタイルID。""" + type: StyleType = dataclasses.field(default=StyleType.TALK) + """スタイルに対応するモデルの種類。""" + order: Optional[int] = None """ 話者の順番。 diff --git a/crates/voicevox_core_python_api/python/voicevox_core/_rust/__init__.pyi b/crates/voicevox_core_python_api/python/voicevox_core/_rust/__init__.pyi index 3a47ef02b..89a50d230 100644 --- a/crates/voicevox_core_python_api/python/voicevox_core/_rust/__init__.pyi +++ b/crates/voicevox_core_python_api/python/voicevox_core/_rust/__init__.pyi @@ -37,6 +37,11 @@ class ReadZipEntryError(Exception): ... +class InvalidModelFormatError(Exception): + """モデルの形式が不正。""" + + ... + class ModelAlreadyLoadedError(Exception): """すでに読み込まれている音声モデルを読み込もうとした。""" diff --git a/crates/voicevox_core_python_api/src/convert.rs b/crates/voicevox_core_python_api/src/convert.rs index 3f629f90e..3cee4186b 100644 --- a/crates/voicevox_core_python_api/src/convert.rs +++ b/crates/voicevox_core_python_api/src/convert.rs @@ -16,10 +16,10 @@ use voicevox_core::{ use crate::{ ExtractFullContextLabelError, GetSupportedDevicesError, GpuSupportError, InferenceFailedError, - InvalidModelDataError, InvalidWordError, LoadUserDictError, ModelAlreadyLoadedError, - ModelNotFoundError, NotLoadedOpenjtalkDictError, OpenZipFileError, ParseKanaError, - ReadZipEntryError, SaveUserDictError, StyleAlreadyLoadedError, StyleNotFoundError, - UseUserDictError, WordNotFoundError, + InvalidModelDataError, InvalidModelFormatError, InvalidWordError, LoadUserDictError, + ModelAlreadyLoadedError, ModelNotFoundError, NotLoadedOpenjtalkDictError, OpenZipFileError, + ParseKanaError, ReadZipEntryError, SaveUserDictError, StyleAlreadyLoadedError, + StyleNotFoundError, UseUserDictError, WordNotFoundError, }; pub(crate) fn from_acceleration_mode(ob: &PyAny) -> PyResult { @@ -194,6 +194,7 @@ pub(crate) impl voicevox_core::Result { ErrorKind::ReadZipEntry => ReadZipEntryError::new_err(msg), ErrorKind::ModelAlreadyLoaded => ModelAlreadyLoadedError::new_err(msg), ErrorKind::StyleAlreadyLoaded => StyleAlreadyLoadedError::new_err(msg), + ErrorKind::InvalidModelFormat => InvalidModelFormatError::new_err(msg), ErrorKind::InvalidModelData => InvalidModelDataError::new_err(msg), ErrorKind::GetSupportedDevices => GetSupportedDevicesError::new_err(msg), ErrorKind::StyleNotFound => StyleNotFoundError::new_err(msg), diff --git a/crates/voicevox_core_python_api/src/lib.rs b/crates/voicevox_core_python_api/src/lib.rs index 4d190333d..492d18f0e 100644 --- a/crates/voicevox_core_python_api/src/lib.rs +++ b/crates/voicevox_core_python_api/src/lib.rs @@ -71,6 +71,7 @@ exceptions! { ReadZipEntryError: PyException; ModelAlreadyLoadedError: PyException; StyleAlreadyLoadedError: PyException; + InvalidModelFormatError: PyException; InvalidModelDataError: PyException; GetSupportedDevicesError: PyException; StyleNotFoundError: PyKeyError; diff --git a/docs/vvm.md b/docs/vvm.md index c2de7fb41..cc7b9232e 100644 --- a/docs/vvm.md +++ b/docs/vvm.md @@ -14,7 +14,7 @@ model は `.onnx` や `.bin` など様々ある。例えば `sample.vvm` は `predict_duration.onnx` / `predict_intonation.onnx` / `decode.onnx` を含む。 -VOICEVOX OSS が提供する VVM には [`sample.vvm`](https://github.com/VOICEVOX/voicevox_core/tree/main/model) がある。 +VOICEVOX OSS が提供する VVM には `sample.vvm` がある(ビルドを行うと `crates/test_util/data/model/sample.vvm` が生成される)。 製品版 VOICEVOX で利用される VVM は [こちらのレポジトリ](https://github.com/VOICEVOX/voicevox_fat_resource/tree/main/core/model) で確認できる。 ## マニフェストファイル diff --git a/example/kotlin/README.md b/example/kotlin/README.md index 908bdd51f..3bcdafc94 100644 --- a/example/kotlin/README.md +++ b/example/kotlin/README.md @@ -57,9 +57,9 @@ Options: ## 実行例 ```console -❯ ./gradlew run --args="--vvm ../../model/sample.vvm" +❯ ./gradlew run --args="--vvm ../../crates/test_util/data/model/sample.vvm" Inititalizing: AUTO, ./open_jtalk_dic_utf_8-1.11 -Loading: ../../model/sample.vvm +Loading: ../../crates/test_util/data/model/sample.vvm Creating an AudioQuery from the text: この音声は、ボイスボックスを使用して、出力されています。 Synthesizing... Saving the audio to ./output.wav diff --git a/example/python/README.md b/example/python/README.md index 392896030..97303eb81 100644 --- a/example/python/README.md +++ b/example/python/README.md @@ -69,12 +69,12 @@ optional arguments: ## 実行例 ```console -❯ python ./run.py ../../model/sample.vvm +❯ python ./run.py ../../crates/test_util/data/model/sample.vvm [DEBUG] __main__: voicevox_core.supported_devices()=SupportedDevices(cpu=True, cuda=False, dml=False) [INFO] __main__: Initializing (acceleration_mode=, open_jtalk_dict_dir=PosixPath('open_jtalk_dic_utf_8-1.11')) [DEBUG] __main__: synthesizer.metas=[] [DEBUG] __main__: synthesizer.is_gpu_mode=False -[INFO] __main__: Loading `../../model/sample.vvm` +[INFO] __main__: Loading `../../crates/test_util/data/model/sample.vvm` [INFO] __main__: Creating an AudioQuery from 'この音声は、ボイスボックスを使用して、出力されています。' [INFO] __main__: Synthesizing with {"accent_phrases": [{"moras": [{"text": "コ", "consonant": "k", "consonant_length": 0.0556899, "vowel": "o", "vowel_length": 0.075180575, "pitch": 5.542309}, {"text": "ノ", "consonant": "n", "consonant_length": 0.06551014, "vowel": "o", "vowel_length": 0.09984577, "pitch": 5.6173983}], "accent": 2, "pause_mora": null, "is_interrogative": false}, {"moras": [{"text": "オ", "consonant": null, "consonant_length": null, "vowel": "o", "vowel_length": 0.116150305, "pitch": 5.7063766}, {"text": "ン", "consonant": null, "consonant_length": null, "vowel": "N", "vowel_length": 0.044380233, "pitch": 5.785717}, {"text": "セ", "consonant": "s", "consonant_length": 0.07719758, "vowel": "e", "vowel_length": 0.08653869, "pitch": 5.662092}, {"text": "エ", "consonant": null, "consonant_length": null, "vowel": "e", "vowel_length": 0.08311573, "pitch": 5.532917}, {"text": "ワ", "consonant": "w", "consonant_length": 0.06373148, "vowel": "a", "vowel_length": 0.16219379, "pitch": 5.293258}], "accent": 1, "pause_mora": {"text": "、", "consonant": null, "consonant_length": null, "vowel": "pau", "vowel_length": 0.35826492, "pitch": 0.0}, "is_interrogative": false}, {"moras": [{"text": "ボ", "consonant": "b", "consonant_length": 0.047082342, "vowel": "o", "vowel_length": 0.12611786, "pitch": 5.583892}, {"text": "イ", "consonant": null, "consonant_length": null, "vowel": "i", "vowel_length": 0.059451744, "pitch": 5.7947493}, {"text": "ス", "consonant": "s", "consonant_length": 0.089278996, "vowel": "u", "vowel_length": 0.11847979, "pitch": 5.818695}, {"text": "ボ", "consonant": "b", "consonant_length": 0.06535433, "vowel": "o", "vowel_length": 0.120458946, "pitch": 5.7965107}, {"text": "ッ", "consonant": null, "consonant_length": null, "vowel": "cl", "vowel_length": 0.06940381, "pitch": 0.0}, {"text": "ク", "consonant": "k", "consonant_length": 0.053739145, "vowel": "U", "vowel_length": 0.05395376, "pitch": 0.0}, {"text": "ス", "consonant": "s", "consonant_length": 0.10222931, "vowel": "u", "vowel_length": 0.071811065, "pitch": 5.8024883}, {"text": "オ", "consonant": null, "consonant_length": null, "vowel": "o", "vowel_length": 0.11092262, "pitch": 5.5036163}], "accent": 4, "pause_mora": null, "is_interrogative": false}, {"moras": [{"text": "シ", "consonant": "sh", "consonant_length": 0.09327768, "vowel": "i", "vowel_length": 0.09126951, "pitch": 5.369444}, {"text": "ヨ", "consonant": "y", "consonant_length": 0.06251812, "vowel": "o", "vowel_length": 0.07805054, "pitch": 5.5021667}, {"text": "オ", "consonant": null, "consonant_length": null, "vowel": "o", "vowel_length": 0.09904325, "pitch": 5.5219536}], "accent": 3, "pause_mora": null, "is_interrogative": false}, {"moras": [{"text": "シ", "consonant": "sh", "consonant_length": 0.04879771, "vowel": "I", "vowel_length": 0.06514315, "pitch": 0.0}, {"text": "テ", "consonant": "t", "consonant_length": 0.0840496, "vowel": "e", "vowel_length": 0.19438823, "pitch": 5.4875555}], "accent": 2, "pause_mora": {"text": "、", "consonant": null, "consonant_length": null, "vowel": "pau", "vowel_length": 0.35208154, "pitch": 0.0}, "is_interrogative": false}, {"moras": [{"text": "シュ", "consonant": "sh", "consonant_length": 0.05436731, "vowel": "U", "vowel_length": 0.06044446, "pitch": 0.0}, {"text": "ツ", "consonant": "ts", "consonant_length": 0.102865085, "vowel": "u", "vowel_length": 0.057028636, "pitch": 5.6402535}, {"text": "リョ", "consonant": "ry", "consonant_length": 0.058293864, "vowel": "o", "vowel_length": 0.080050275, "pitch": 5.6997967}, {"text": "ク", "consonant": "k", "consonant_length": 0.054767884, "vowel": "U", "vowel_length": 0.042932786, "pitch": 0.0}], "accent": 2, "pause_mora": null, "is_interrogative": false}, {"moras": [{"text": "サ", "consonant": "s", "consonant_length": 0.08067487, "vowel": "a", "vowel_length": 0.07377973, "pitch": 5.652378}, {"text": "レ", "consonant": "r", "consonant_length": 0.040600352, "vowel": "e", "vowel_length": 0.079322875, "pitch": 5.6290326}, {"text": "テ", "consonant": "t", "consonant_length": 0.06773268, "vowel": "e", "vowel_length": 0.08347456, "pitch": 5.6427326}], "accent": 3, "pause_mora": null, "is_interrogative": false}, {"moras": [{"text": "イ", "consonant": null, "consonant_length": null, "vowel": "i", "vowel_length": 0.07542324, "pitch": 5.641289}, {"text": "マ", "consonant": "m", "consonant_length": 0.066299975, "vowel": "a", "vowel_length": 0.107257664, "pitch": 5.6201453}, {"text": "ス", "consonant": "s", "consonant_length": 0.07186453, "vowel": "U", "vowel_length": 0.1163103, "pitch": 0.0}], "accent": 2, "pause_mora": null, "is_interrogative": false}], "speed_scale": 1.0, "pitch_scale": 0.0, "intonation_scale": 1.0, "volume_scale": 1.0, "pre_phoneme_length": 0.1, "post_phoneme_length": 0.1, "output_sampling_rate": 24000, "output_stereo": false, "kana": "コノ'/オ'ンセエワ、ボイスボ'ッ_クスオ/シヨオ'/_シテ'、_シュツ' リョ_ク/サレテ'/イマ'_ス"} [INFO] __main__: Wrote `output.wav` diff --git a/model/sample.vvm b/model/sample.vvm deleted file mode 100644 index 48d23745d..000000000 Binary files a/model/sample.vvm and /dev/null differ diff --git a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/decode.onnx b/model/sample.vvm/decode.onnx similarity index 100% rename from crates/voicevox_core/src/test_data/model_sources/load_model_works1/decode.onnx rename to model/sample.vvm/decode.onnx diff --git a/model/sample.vvm/manifest.json b/model/sample.vvm/manifest.json new file mode 100644 index 000000000..2c6721d08 --- /dev/null +++ b/model/sample.vvm/manifest.json @@ -0,0 +1,13 @@ +{ + "manifest_version": "0.0.0", + "metas_filename": "metas.json", + "talk": { + "predict_duration_filename": "predict_duration.onnx", + "predict_intonation_filename": "predict_intonation.onnx", + "decode_filename": "decode.onnx", + "style_id_to_model_inner_id": { + "302": 2, + "303": 3 + } + } +} diff --git a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/metas.json b/model/sample.vvm/metas.json similarity index 100% rename from crates/voicevox_core/src/test_data/model_sources/load_model_works1/metas.json rename to model/sample.vvm/metas.json diff --git a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/predict_duration.onnx b/model/sample.vvm/predict_duration.onnx similarity index 100% rename from crates/voicevox_core/src/test_data/model_sources/load_model_works1/predict_duration.onnx rename to model/sample.vvm/predict_duration.onnx diff --git a/crates/voicevox_core/src/test_data/model_sources/load_model_works1/predict_intonation.onnx b/model/sample.vvm/predict_intonation.onnx similarity index 100% rename from crates/voicevox_core/src/test_data/model_sources/load_model_works1/predict_intonation.onnx rename to model/sample.vvm/predict_intonation.onnx diff --git a/renovate.json b/renovate.json index 3e6f4eae4..5704cd5f4 100644 --- a/renovate.json +++ b/renovate.json @@ -8,12 +8,12 @@ { "groupSlug": "rust", "groupName": "Rust", - "matchPackagePatterns": "^Rust$" + "matchDepPatterns": "^Rust$" }, { "groupSlug": "others", "groupName": "Others", - "excludePackagePatterns": "^Rust$", + "excludeDepPatterns": "^Rust$", "dependencyDashboardApproval": true } ], diff --git a/rust-toolchain b/rust-toolchain index 369f9966f..54227249d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.77.2 +1.78.0