diff --git a/Cargo.lock b/Cargo.lock index df10b409e..004815351 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,7 +413,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 +429,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" @@ -446,6 +469,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "block-buffer" version = "0.9.0" @@ -636,9 +665,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 +681,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 +696,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", @@ -774,7 +803,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", ] @@ -2526,7 +2555,7 @@ name = "open_jtalk-sys" version = "0.16.111" source = "git+https://github.com/VOICEVOX/open_jtalk-rs.git?rev=e1940f3fd61a48bed5bbec8cd2645e13923b1f80#e1940f3fd61a48bed5bbec8cd2645e13923b1f80" dependencies = [ - "bindgen", + "bindgen 0.62.0", "cmake", "link-cplusplus", ] @@ -2833,6 +2862,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" @@ -3082,7 +3121,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 +3130,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3272,7 +3311,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 +3325,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", @@ -3880,9 +3919,12 @@ dependencies = [ "anyhow", "async-std", "async_zip", + "bindgen 0.69.4", + "camino", "flate2", "fs-err", "futures-lite 2.2.0", + "libloading", "once_cell", "serde", "serde_json", @@ -4435,7 +4477,6 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", "tempfile", "test_util", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 4cc54b196..8bdd888eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ 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" diff --git a/crates/test_util/Cargo.toml b/crates/test_util/Cargo.toml index bea6e4d4e..dc873b7e8 100644 --- a/crates/test_util/Cargo.toml +++ b/crates/test_util/Cargo.toml @@ -5,6 +5,7 @@ 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 @@ -13,6 +14,8 @@ tokio = { workspace = true, features = ["fs", "io-util", "sync"] } [build-dependencies] anyhow.workspace = true async-std = { workspace = true, features = ["attributes"] } +bindgen.workspace = true +camino.workspace = true flate2.workspace = true fs-err.workspace = true serde = { workspace = true, features = ["derive"] } @@ -21,5 +24,5 @@ surf.workspace = true tar.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..9a2e0f1e5 100644 --- a/crates/test_util/build.rs +++ b/crates/test_util/build.rs @@ -5,6 +5,7 @@ use std::{ use anyhow::ensure; use async_std::io::ReadExt as _; +use camino::Utf8PathBuf; use flate2::read::GzDecoder; use tar::Archive; @@ -28,7 +29,8 @@ async fn main() -> anyhow::Result<()> { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=src/typing.rs"); - Ok(()) + + generate_c_api_rs_bindings() } /// OpenJTalkの辞書をダウンロードして展開する。 @@ -120,3 +122,20 @@ fn generate_example_data_json(dist: &Path) -> anyhow::Result<()> { Ok(()) } + +fn generate_c_api_rs_bindings() -> anyhow::Result<()> { + static C_BINDINGS_PATH: &str = "../voicevox_core_c_api/include/voicevox_core.h"; + static ADDITIONAL_C_BINDINGS_PATH: &str = "./compatible_engine.h"; + + let out_dir = Utf8PathBuf::from(env::var("OUT_DIR").unwrap()); + 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..c80f3d575 100644 --- a/crates/test_util/src/lib.rs +++ b/crates/test_util/src/lib.rs @@ -1,5 +1,17 @@ mod typing; +#[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")); +} + use async_zip::{base::write::ZipFileWriter, Compression, ZipEntryBuilder}; use futures_lite::AsyncWriteExt as _; use once_cell::sync::Lazy; 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/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..5e8e19a9c 100644 --- a/crates/voicevox_core_c_api/tests/e2e/main.rs +++ b/crates/voicevox_core_c_api/tests/e2e/main.rs @@ -2,14 +2,11 @@ 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でマウントする。 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..85709d2bf 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 @@ -5,12 +5,14 @@ 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,25 +26,12 @@ 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( + assert_ok(lib.voicevox_voice_model_new_from_path( cstr!("../../model/sample.vvm").as_ptr(), model.as_mut_ptr(), )); @@ -52,37 +41,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 +80,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..4727a3c06 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 @@ -9,12 +9,14 @@ 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 +26,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 +54,32 @@ impl assert_cdylib::TestCase for TestCase { let model = { let mut model = MaybeUninit::uninit(); - assert_ok(voicevox_voice_model_new_from_path( + assert_ok(lib.voicevox_voice_model_new_from_path( cstr!("../../model/sample.vvm").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..606e82aeb 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 @@ -5,12 +5,14 @@ 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,27 +26,12 @@ 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( + assert_ok(lib.voicevox_voice_model_new_from_path( cstr!("../../model/sample.vvm").as_ptr(), model.as_mut_ptr(), )); @@ -54,32 +41,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 +78,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 +91,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..dfbb5ca3c 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,45 +24,30 @@ 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( + assert_ok(lib.voicevox_voice_model_new_from_path( cstr!("../../model/sample.vvm").as_ptr(), model.as_mut_ptr(), )); @@ -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) {