diff --git a/Cargo.lock b/Cargo.lock index 56c0a14ab..a9f33a1e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -718,6 +718,27 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" +dependencies = [ + "const-default-derive", +] + +[[package]] +name = "const-default-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f814dd8cbb812233751ff6857b7fa86d9f52e88ac64e8f54e7a1ca0168f03da" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.102", +] + [[package]] name = "const_fn" version = "0.4.9" @@ -1039,6 +1060,16 @@ dependencies = [ "shared_child", ] +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "easy-ext" version = "1.0.1" @@ -2480,6 +2511,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3859,8 +3900,10 @@ dependencies = [ "anyhow", "async_zip", "cfg-if", + "const-default", "derive-getters", "derive-new", + "duplicate", "easy-ext", "flate2", "fs-err", @@ -3877,6 +3920,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "strum", "tar", "test_util", "thiserror", @@ -3893,6 +3937,7 @@ dependencies = [ "assert_cmd", "chrono", "clap 4.0.10", + "const-default", "derive-getters", "duct", "easy-ext", @@ -3910,6 +3955,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "strum", "test_util", "thiserror", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 4a81b36dc..88c026901 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ publish = false [workspace.dependencies] anyhow = "1.0.65" clap = { version = "4.0.10", features = ["derive"] } +const-default = { version = "1.0.0", features = ["derive"] } easy-ext = "1.0.1" fs-err = { version = "2.9.0", features = ["tokio"] } once_cell = "1.15.0" @@ -24,6 +25,7 @@ process_path = { git = "https://github.com/VOICEVOX/process_path.git", rev = "de regex = "1.6.0" serde = { version = "1.0.145", features = ["derive"] } serde_json = { version = "1.0.85", features = ["preserve_order"] } +strum = { version = "0.24.1", features = ["derive"] } test_util = { path = "crates/test_util" } thiserror = "1.0.37" tracing = { version = "0.1.37", features = ["log"] } diff --git a/crates/download/Cargo.toml b/crates/download/Cargo.toml index a14a1e066..16a81978f 100644 --- a/crates/download/Cargo.toml +++ b/crates/download/Cargo.toml @@ -20,7 +20,7 @@ once_cell.workspace = true platforms = "3.0.2" rayon = "1.6.1" reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls", "stream"] } -strum = { version = "0.24.1", features = ["derive"] } +strum.workspace = true tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/crates/voicevox_core/Cargo.toml b/crates/voicevox_core/Cargo.toml index 4d98fe352..2f0fa3ee5 100644 --- a/crates/voicevox_core/Cargo.toml +++ b/crates/voicevox_core/Cargo.toml @@ -12,8 +12,10 @@ directml = ["onnxruntime/directml"] [dependencies] anyhow.workspace = true cfg-if = "1.0.0" +const-default.workspace = true derive-getters.workspace = true derive-new = "0.5.9" +duplicate = "1.0.0" easy-ext.workspace = true fs-err.workspace = true once_cell.workspace = true @@ -21,6 +23,7 @@ onnxruntime = { git = "https://github.com/VOICEVOX/onnxruntime-rs.git", rev="ebb process_path.workspace = true serde.workspace = true serde_json.workspace = true +strum.workspace = true thiserror.workspace = true tracing.workspace = true open_jtalk = { git = "https://github.com/VOICEVOX/open_jtalk-rs.git", rev="d766a52bad4ccafe18597e57bd6842f59dca881e" } diff --git a/crates/voicevox_core/src/result_code.rs b/crates/voicevox_core/src/result_code.rs index aac908295..55f59ab2f 100644 --- a/crates/voicevox_core/src/result_code.rs +++ b/crates/voicevox_core/src/result_code.rs @@ -1,6 +1,8 @@ +use strum::EnumIter; + /// 処理結果を示す結果コード #[repr(i32)] -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, EnumIter)] #[allow(non_camel_case_types)] pub enum VoicevoxResultCode { // C でのenum定義に合わせて大文字で定義している diff --git a/crates/voicevox_core/src/version.rs b/crates/voicevox_core/src/version.rs index 2944ef034..a89875a30 100644 --- a/crates/voicevox_core/src/version.rs +++ b/crates/voicevox_core/src/version.rs @@ -1,6 +1,8 @@ -pub const fn get_version() -> &'static str { - env!("CARGO_PKG_VERSION") -} +/// 本クレートの`package.version`。 +/// +/// C APIやPython API側からこの値が使われるべきではない。 +/// 現在はまだRust APIを外部提供していないため、この定数はどこからも参照されていないはずである。 +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg(test)] mod tests { @@ -8,6 +10,6 @@ mod tests { use crate::*; #[rstest] fn get_version_works() { - assert_eq!("0.0.0", get_version()); + assert_eq!("0.0.0", VERSION); } } diff --git a/crates/voicevox_core/src/voice_synthesizer.rs b/crates/voicevox_core/src/voice_synthesizer.rs index 174d3782e..86b91ce83 100644 --- a/crates/voicevox_core/src/voice_synthesizer.rs +++ b/crates/voicevox_core/src/voice_synthesizer.rs @@ -1,5 +1,8 @@ use std::sync::Arc; +use const_default::ConstDefault; +use duplicate::duplicate_item; + use crate::engine::{create_kana, parse_kana, AccentPhraseModel, OpenJtalk, SynthesisEngine}; use super::*; @@ -22,12 +25,12 @@ impl From<&TtsOptions> for SynthesisOptions { } } -#[derive(Default)] +#[derive(ConstDefault)] pub struct AccentPhrasesOptions { pub kana: bool, } -#[derive(Default)] +#[derive(ConstDefault)] pub struct AudioQueryOptions { pub kana: bool, } @@ -49,30 +52,45 @@ impl AsRef for TtsOptions { } } -impl Default for TtsOptions { - fn default() -> Self { - Self { - enable_interrogative_upspeak: true, - kana: Default::default(), - } - } +impl ConstDefault for TtsOptions { + const DEFAULT: Self = Self { + enable_interrogative_upspeak: true, + kana: ConstDefault::DEFAULT, + }; } -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum AccelerationMode { - #[default] Auto, Cpu, Gpu, } -#[derive(Default)] +impl ConstDefault for AccelerationMode { + const DEFAULT: Self = Self::Auto; +} + +#[derive(ConstDefault)] pub struct InitializeOptions { pub acceleration_mode: AccelerationMode, pub cpu_num_threads: u16, pub load_all_models: bool, } +#[duplicate_item( + T; + [ AccentPhrasesOptions ]; + [ AudioQueryOptions ]; + [ TtsOptions ]; + [ AccelerationMode ]; + [ InitializeOptions ]; +)] +impl Default for T { + fn default() -> Self { + Self::DEFAULT + } +} + /// 音声シンセサイザ pub struct Synthesizer { synthesis_engine: SynthesisEngine, diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index 6c6e2e63a..1f239d9ca 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -18,6 +18,7 @@ directml = ["voicevox_core/directml"] [dependencies] voicevox_core.workspace = true chrono = { version = "0.4.23", default-features = false, features = ["clock"] } # https://github.com/chronotope/chrono/issues/602 +const-default.workspace = true is-terminal = "0.4.2" libc = "0.2.134" once_cell.workspace = true @@ -42,6 +43,7 @@ ndarray-stats = "0.5.1" process_path.workspace = true regex.workspace = true serde.workspace = true +strum.workspace = true test_util.workspace = true toml = "0.7.2" typetag = "0.2.5" diff --git a/crates/voicevox_core_c_api/include/voicevox_core.h b/crates/voicevox_core_c_api/include/voicevox_core.h index eebbc2d41..4b57ee819 100644 --- a/crates/voicevox_core_c_api/include/voicevox_core.h +++ b/crates/voicevox_core_c_api/include/voicevox_core.h @@ -125,6 +125,18 @@ typedef int32_t VoicevoxResultCode; */ typedef struct OpenJtalkRc OpenJtalkRc; +/** + * 音声モデル + */ +typedef struct VoicevoxVoiceModel { + +} VoicevoxVoiceModel; + +/** + * 音声モデルID + */ +typedef const char *VoicevoxVoiceModelId; + /** * 初期化オプション */ @@ -144,21 +156,14 @@ typedef struct VoicevoxInitializeOptions { bool load_all_models; } VoicevoxInitializeOptions; -/** - * 音声モデル - */ -typedef struct VoicevoxVoiceModel { +typedef struct VoicevoxSynthesizer { -} VoicevoxVoiceModel; +} VoicevoxSynthesizer; /** - * 音声モデルID + * スタイルID */ -typedef const char *VoicevoxVoiceModelId; - -typedef struct VoicevoxSynthesizer { - -} VoicevoxSynthesizer; +typedef uint32_t VoicevoxStyleId; /** * Audio query のオプション @@ -170,11 +175,6 @@ typedef struct VoicevoxAudioQueryOptions { bool kana; } VoicevoxAudioQueryOptions; -/** - * スタイルID - */ -typedef uint32_t VoicevoxStyleId; - /** * `accent_phrases` のオプション */ @@ -213,6 +213,18 @@ typedef struct VoicevoxTtsOptions { extern "C" { #endif // __cplusplus +extern const struct VoicevoxInitializeOptions voicevox_default_initialize_options; + +extern const char *voicevox_version; + +extern const struct VoicevoxAudioQueryOptions voicevox_default_audio_query_options; + +extern const struct VoicevoxAccentPhrasesOptions voicevox_default_accent_phrases_options; + +extern const struct VoicevoxSynthesisOptions voicevox_default_synthesis_options; + +extern const struct VoicevoxTtsOptions voicevox_default_tts_options; + /** * 参照カウントで管理されたOpenJtalkを生成する * @@ -239,25 +251,6 @@ __declspec(dllimport) void voicevox_open_jtalk_rc_delete(struct OpenJtalkRc *open_jtalk); -/** - * デフォルトの初期化オプションを生成する - * @return デフォルト値が設定された初期化オプション - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - -struct VoicevoxInitializeOptions voicevox_make_default_initialize_options(void); - -/** - * voicevoxのバージョンを取得する - * @return SemVerでフォーマットされたバージョン - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - const char *voicevox_get_version(void); - /** * vvmファイルパスから音声モデルを生成する * @param [in] path vvmファイルパス @@ -440,16 +433,6 @@ __declspec(dllimport) VoicevoxResultCode voicevox_create_supported_devices_json(char **output_supported_devices_json); -/** - * デフォルトの AudioQuery のオプションを生成する - * @return デフォルト値が設定された AudioQuery オプション - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - -struct VoicevoxAudioQueryOptions voicevox_make_default_audio_query_options(void); - /** * AudioQuery を実行する * @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -473,16 +456,6 @@ VoicevoxResultCode voicevox_synthesizer_audio_query(const struct VoicevoxSynthes struct VoicevoxAudioQueryOptions options, char **output_audio_query_json); -/** - * デフォルトの `accent_phrases` のオプションを生成する - * @return デフォルト値が設定された `accent_phrases` のオプション - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - -struct VoicevoxAccentPhrasesOptions voicevox_make_default_accent_phrases_options(void); - /** * create_accent_phrases を実行する * @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -564,16 +537,6 @@ VoicevoxResultCode voicevox_synthesizer_replace_mora_pitch(const struct Voicevox VoicevoxStyleId style_id, char **output_accent_phrases_json); -/** - * デフォルトの `voicevox_synthesizer_synthesis` のオプションを生成する - * @return デフォルト値が設定された `voicevox_synthesizer_synthesis` のオプション - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - -struct VoicevoxSynthesisOptions voicevox_make_default_synthesis_options(void); - /** * AudioQuery から音声合成する * @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -599,16 +562,6 @@ VoicevoxResultCode voicevox_synthesizer_synthesis(const struct VoicevoxSynthesiz uintptr_t *output_wav_length, uint8_t **output_wav); -/** - * デフォルトのテキスト音声合成オプションを生成する - * @return テキスト音声合成オプション - */ -#ifdef _WIN32 -__declspec(dllimport) -#endif - -struct VoicevoxTtsOptions voicevox_make_default_tts_options(void); - /** * テキスト音声合成を実行する * @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer diff --git a/crates/voicevox_core_c_api/src/helpers.rs b/crates/voicevox_core_c_api/src/helpers.rs index f51305b22..cbb7e3fd9 100644 --- a/crates/voicevox_core_c_api/src/helpers.rs +++ b/crates/voicevox_core_c_api/src/helpers.rs @@ -2,6 +2,7 @@ use std::alloc::Layout; use std::collections::BTreeMap; use std::fmt::Debug; +use const_default::ConstDefault; use thiserror::Error; use super::*; @@ -73,10 +74,11 @@ pub(crate) fn ensure_utf8(s: &CStr) -> CApiResult<&str> { s.to_str().map_err(|_| CApiError::InvalidUtf8Input) } -impl From for VoicevoxAudioQueryOptions { - fn from(options: voicevox_core::AudioQueryOptions) -> Self { +impl ConstDefault for VoicevoxAudioQueryOptions { + const DEFAULT: Self = { + let options = voicevox_core::AudioQueryOptions::DEFAULT; Self { kana: options.kana } - } + }; } impl From for voicevox_core::AudioQueryOptions { fn from(options: VoicevoxAudioQueryOptions) -> Self { @@ -84,10 +86,11 @@ impl From for voicevox_core::AudioQueryOptions { } } -impl From for VoicevoxAccentPhrasesOptions { - fn from(options: voicevox_core::AccentPhrasesOptions) -> Self { +impl ConstDefault for VoicevoxAccentPhrasesOptions { + const DEFAULT: Self = { + let options = voicevox_core::AccentPhrasesOptions::DEFAULT; Self { kana: options.kana } - } + }; } impl From for voicevox_core::AccentPhrasesOptions { fn from(options: VoicevoxAccentPhrasesOptions) -> Self { @@ -103,9 +106,10 @@ impl From for voicevox_core::SynthesisOptions { } } -impl From for VoicevoxAccelerationMode { - fn from(mode: voicevox_core::AccelerationMode) -> Self { +impl VoicevoxAccelerationMode { + const fn from_rust(mode: voicevox_core::AccelerationMode) -> Self { use voicevox_core::AccelerationMode::*; + match mode { Auto => Self::VOICEVOX_ACCELERATION_MODE_AUTO, Cpu => Self::VOICEVOX_ACCELERATION_MODE_CPU, @@ -113,10 +117,10 @@ impl From for VoicevoxAccelerationMode { } } } - impl From for voicevox_core::AccelerationMode { fn from(mode: VoicevoxAccelerationMode) -> Self { use VoicevoxAccelerationMode::*; + match mode { VOICEVOX_ACCELERATION_MODE_AUTO => Self::Auto, VOICEVOX_ACCELERATION_MODE_CPU => Self::Cpu, @@ -125,15 +129,15 @@ impl From for voicevox_core::AccelerationMode { } } -impl Default for VoicevoxInitializeOptions { - fn default() -> Self { - let options = voicevox_core::InitializeOptions::default(); +impl ConstDefault for VoicevoxInitializeOptions { + const DEFAULT: Self = { + let options = voicevox_core::InitializeOptions::DEFAULT; Self { - acceleration_mode: options.acceleration_mode.into(), + acceleration_mode: VoicevoxAccelerationMode::from_rust(options.acceleration_mode), cpu_num_threads: options.cpu_num_threads, load_all_models: options.load_all_models, } - } + }; } impl From for voicevox_core::InitializeOptions { @@ -146,13 +150,14 @@ impl From for voicevox_core::InitializeOptions { } } -impl From for VoicevoxTtsOptions { - fn from(options: voicevox_core::TtsOptions) -> Self { +impl ConstDefault for VoicevoxTtsOptions { + const DEFAULT: Self = { + let options = voicevox_core::TtsOptions::DEFAULT; Self { kana: options.kana, enable_interrogative_upspeak: options.enable_interrogative_upspeak, } - } + }; } impl From for voicevox_core::TtsOptions { @@ -164,13 +169,13 @@ impl From for voicevox_core::TtsOptions { } } -impl Default for VoicevoxSynthesisOptions { - fn default() -> Self { - let options = voicevox_core::TtsOptions::default(); +impl ConstDefault for VoicevoxSynthesisOptions { + const DEFAULT: Self = { + let options = voicevox_core::TtsOptions::DEFAULT; Self { enable_interrogative_upspeak: options.enable_interrogative_upspeak, } - } + }; } // libcのmallocで追加のアロケーションを行うことなく、`Vec`や`Vec`の内容を直接Cの世界に貸し出す。 diff --git a/crates/voicevox_core_c_api/src/lib.rs b/crates/voicevox_core_c_api/src/lib.rs index f592e72e4..93f5df60a 100644 --- a/crates/voicevox_core_c_api/src/lib.rs +++ b/crates/voicevox_core_c_api/src/lib.rs @@ -5,6 +5,7 @@ mod helpers; use self::helpers::*; use c_impls::*; use chrono::SecondsFormat; +use const_default::ConstDefault; use is_terminal::IsTerminal; use once_cell::sync::Lazy; use std::env; @@ -131,22 +132,21 @@ pub struct VoicevoxInitializeOptions { load_all_models: bool, } -/// デフォルトの初期化オプションを生成する -/// @return デフォルト値が設定された初期化オプション +/// デフォルトの初期化オプション #[no_mangle] -pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitializeOptions { - VoicevoxInitializeOptions::default() -} - -static VOICEVOX_VERSION: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(|| CString::new(env!("CARGO_PKG_VERSION")).unwrap()); +pub static voicevox_default_initialize_options: VoicevoxInitializeOptions = ConstDefault::DEFAULT; -/// voicevoxのバージョンを取得する -/// @return SemVerでフォーマットされたバージョン +/// voicevoxのバージョン #[no_mangle] -pub extern "C" fn voicevox_get_version() -> *const c_char { - VOICEVOX_VERSION.as_ptr() -} +pub static voicevox_version: &c_char = { + const VOICEVOX_VERSION: &CStr = unsafe { + // SAFETY: The package version is a SemVer, so it should not contain '\0' + CStr::from_bytes_with_nul_unchecked(concat!(env!("CARGO_PKG_VERSION"), '\0').as_bytes()) + }; + + // SAFETY: `CStr::as_ptr` always returns a valid pointer. + unsafe { &*VOICEVOX_VERSION.as_ptr() } +}; /// 音声モデル #[repr(C)] @@ -371,12 +371,9 @@ pub struct VoicevoxAudioQueryOptions { kana: bool, } -/// デフォルトの AudioQuery のオプションを生成する -/// @return デフォルト値が設定された AudioQuery オプション +/// デフォルトの AudioQuery のオプション #[no_mangle] -pub extern "C" fn voicevox_make_default_audio_query_options() -> VoicevoxAudioQueryOptions { - voicevox_core::AudioQueryOptions::default().into() -} +pub static voicevox_default_audio_query_options: VoicevoxAudioQueryOptions = ConstDefault::DEFAULT; /// AudioQuery を実行する /// @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -420,12 +417,10 @@ pub struct VoicevoxAccentPhrasesOptions { kana: bool, } -/// デフォルトの `accent_phrases` のオプションを生成する -/// @return デフォルト値が設定された `accent_phrases` のオプション +/// デフォルトの `accent_phrases` のオプション #[no_mangle] -pub extern "C" fn voicevox_make_default_accent_phrases_options() -> VoicevoxAccentPhrasesOptions { - voicevox_core::AccentPhrasesOptions::default().into() -} +pub static voicevox_default_accent_phrases_options: VoicevoxAccentPhrasesOptions = + ConstDefault::DEFAULT; /// create_accent_phrases を実行する /// @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -565,12 +560,9 @@ pub struct VoicevoxSynthesisOptions { enable_interrogative_upspeak: bool, } -/// デフォルトの `voicevox_synthesizer_synthesis` のオプションを生成する -/// @return デフォルト値が設定された `voicevox_synthesizer_synthesis` のオプション +/// デフォルトの `voicevox_synthesizer_synthesis` のオプション #[no_mangle] -pub extern "C" fn voicevox_make_default_synthesis_options() -> VoicevoxSynthesisOptions { - VoicevoxSynthesisOptions::default() -} +pub static voicevox_default_synthesis_options: VoicevoxSynthesisOptions = ConstDefault::DEFAULT; /// AudioQuery から音声合成する /// @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer @@ -621,12 +613,9 @@ pub struct VoicevoxTtsOptions { enable_interrogative_upspeak: bool, } -/// デフォルトのテキスト音声合成オプションを生成する -/// @return テキスト音声合成オプション +/// デフォルトのテキスト音声合成オプション #[no_mangle] -pub extern "C" fn voicevox_make_default_tts_options() -> VoicevoxTtsOptions { - voicevox_core::TtsOptions::default().into() -} +pub static voicevox_default_tts_options: VoicevoxTtsOptions = ConstDefault::DEFAULT; /// テキスト音声合成を実行する /// @param [in] synthesizer 音声シンセサイザ #VoicevoxSynthesizer diff --git a/crates/voicevox_core_c_api/tests/e2e/snapshots.toml b/crates/voicevox_core_c_api/tests/e2e/snapshots.toml index 0fc8a0c53..6351bff92 100644 --- a/crates/voicevox_core_c_api/tests/e2e/snapshots.toml +++ b/crates/voicevox_core_c_api/tests/e2e/snapshots.toml @@ -50,6 +50,9 @@ stderr.unix = "" last_error_message = "Statusが初期化されていません" stderr = "" +[global_info] +stderr = "" + [simple_tts] output."こんにちは、音声合成の世界へようこそ".wav_length = 176172 stderr.windows = ''' diff --git a/crates/voicevox_core_c_api/tests/e2e/symbols.rs b/crates/voicevox_core_c_api/tests/e2e/symbols.rs index 7c5e0b1b7..dc98c2f2c 100644 --- a/crates/voicevox_core_c_api/tests/e2e/symbols.rs +++ b/crates/voicevox_core_c_api/tests/e2e/symbols.rs @@ -6,14 +6,16 @@ use voicevox_core::result_code::VoicevoxResultCode; /// voicevox\_core\_c\_apiのcdylibのシンボルを集めたもの。 #[allow(dead_code)] // TODO: WIP pub(crate) struct Symbols<'lib> { + pub(crate) voicevox_version: Symbol<'lib, &'lib &'lib c_char>, + pub(crate) voicevox_default_initialize_options: Symbol<'lib, &'lib VoicevoxInitializeOptions>, + pub(crate) voicevox_default_audio_query_options: Symbol<'lib, &'lib VoicevoxAudioQueryOptions>, + pub(crate) voicevox_default_synthesis_options: Symbol<'lib, &'lib VoicevoxSynthesisOptions>, + pub(crate) voicevox_default_tts_options: Symbol<'lib, &'lib VoicevoxTtsOptions>, 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_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, @@ -54,9 +56,7 @@ pub(crate) struct Symbols<'lib> { pub(crate) voicevox_synthesizer_get_metas_json: Symbol<'lib, unsafe extern "C" fn(*const VoicevoxSynthesizer) -> *const c_char>, pub(crate) voicevox_create_supported_devices_json: - Symbol<'lib, unsafe extern "C" fn() -> *const c_char>, - pub(crate) voicevox_make_default_audio_query_options: - Symbol<'lib, unsafe extern "C" fn() -> VoicevoxAudioQueryOptions>, + Symbol<'lib, unsafe extern "C" fn(*mut *mut c_char) -> VoicevoxResultCode>, pub(crate) voicevox_synthesizer_audio_query: Symbol< 'lib, unsafe extern "C" fn( @@ -67,8 +67,6 @@ pub(crate) struct Symbols<'lib> { *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( @@ -80,8 +78,6 @@ pub(crate) struct Symbols<'lib> { *mut *mut u8, ) -> VoicevoxResultCode, >, - pub(crate) voicevox_make_default_tts_options: - Symbol<'lib, unsafe extern "C" fn() -> VoicevoxTtsOptions>, pub(crate) voicevox_synthesizer_tts: Symbol< 'lib, unsafe extern "C" fn( @@ -138,10 +134,13 @@ impl<'lib> Symbols<'lib> { }); Ok(new!( + voicevox_version, + voicevox_default_initialize_options, + voicevox_default_audio_query_options, + voicevox_default_synthesis_options, + voicevox_default_tts_options, voicevox_open_jtalk_rc_new, 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, @@ -154,11 +153,8 @@ impl<'lib> Symbols<'lib> { voicevox_is_loaded_voice_model, voicevox_synthesizer_get_metas_json, voicevox_create_supported_devices_json, - voicevox_make_default_audio_query_options, voicevox_synthesizer_audio_query, - voicevox_make_default_synthesis_options, voicevox_synthesizer_synthesis, - voicevox_make_default_tts_options, voicevox_synthesizer_tts, voicevox_json_free, voicevox_wav_free, @@ -196,16 +192,19 @@ pub(crate) struct VoicevoxInitializeOptions { pub(crate) _load_all_models: bool, } +#[derive(Clone, Copy)] #[repr(C)] pub(crate) struct VoicevoxAudioQueryOptions { _kana: bool, } +#[derive(Clone, Copy)] #[repr(C)] pub(crate) struct VoicevoxSynthesisOptions { _enable_interrogative_upspeak: bool, } +#[derive(Clone, Copy)] #[repr(C)] pub(crate) struct VoicevoxTtsOptions { _kana: bool, diff --git a/crates/voicevox_core_c_api/tests/e2e/testcases.rs b/crates/voicevox_core_c_api/tests/e2e/testcases.rs index e244a428f..8a02bdcad 100644 --- a/crates/voicevox_core_c_api/tests/e2e/testcases.rs +++ b/crates/voicevox_core_c_api/tests/e2e/testcases.rs @@ -1,4 +1,5 @@ mod compatible_engine; mod compatible_engine_load_model_before_initialize; +mod global_info; mod simple_tts; mod tts_via_audio_query; 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 new file mode 100644 index 000000000..d81b79117 --- /dev/null +++ b/crates/voicevox_core_c_api/tests/e2e/testcases/global_info.rs @@ -0,0 +1,81 @@ +use std::{ffi::CStr, mem::MaybeUninit}; + +use assert_cmd::assert::AssertResult; +use libloading::Library; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +use strum::IntoEnumIterator; +use voicevox_core::{result_code::VoicevoxResultCode, SupportedDevices}; + +use crate::{ + assert_cdylib::{self, case, Utf8Output}, + snapshots, + symbols::Symbols, +}; + +case!(TestCase); + +#[derive(Serialize, Deserialize)] +struct TestCase; + +#[typetag::serde(name = "global_info")] +impl assert_cdylib::TestCase for TestCase { + unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { + let Symbols { + voicevox_version, + voicevox_create_supported_devices_json, + voicevox_error_result_to_message, + voicevox_json_free, + .. + } = Symbols::new(lib)?; + + std::assert_eq!( + env!("CARGO_PKG_VERSION"), + CStr::from_ptr(**voicevox_version).to_str()?, + ); + + { + let mut supported_devices = MaybeUninit::uninit(); + assert_ok(voicevox_create_supported_devices_json( + supported_devices.as_mut_ptr(), + )); + let supported_devices = supported_devices.assume_init(); + std::assert_eq!( + SupportedDevices::create()?.to_json(), + CStr::from_ptr(supported_devices) + .to_str()? + .parse::()?, + ); + voicevox_json_free(supported_devices); + } + + for result_code in VoicevoxResultCode::iter() { + std::assert_eq!( + voicevox_core::result_code::error_result_to_message(result_code).as_bytes(), + CStr::from_ptr(voicevox_error_result_to_message(result_code)).to_bytes_with_nul(), + ); + } + return Ok(()); + + fn assert_ok(result_code: VoicevoxResultCode) { + std::assert_eq!(VoicevoxResultCode::VOICEVOX_RESULT_OK, result_code); + } + } + + fn assert_output(&self, output: Utf8Output) -> AssertResult { + output + .mask_timestamps() + .mask_windows_video_cards() + .assert() + .try_success()? + .try_stdout("")? + .try_stderr(&*SNAPSHOTS.stderr) + } +} + +static SNAPSHOTS: Lazy = snapshots::section!(global_info); + +#[derive(Deserialize)] +struct Snapshots { + stderr: String, +} 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 70a16ea1c..2e691100f 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 @@ -36,15 +36,15 @@ struct TestCase { impl assert_cdylib::TestCase for TestCase { unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { let Symbols { + voicevox_default_initialize_options, + voicevox_default_tts_options, 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_with_initialize, voicevox_synthesizer_delete, voicevox_synthesizer_load_voice_model, - voicevox_make_default_tts_options, voicevox_synthesizer_tts, voicevox_wav_free, .. @@ -75,7 +75,7 @@ impl assert_cdylib::TestCase for TestCase { openjtalk, VoicevoxInitializeOptions { acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + ..**voicevox_default_initialize_options }, synthesizer.as_mut_ptr(), )); @@ -92,7 +92,7 @@ impl assert_cdylib::TestCase for TestCase { synthesizer, text.as_ptr(), STYLE_ID, - voicevox_make_default_tts_options(), + **voicevox_default_tts_options, wav_length.as_mut_ptr(), wav.as_mut_ptr(), )); 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 79bb27ff7..024d68b0f 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 @@ -36,17 +36,17 @@ struct TestCase { impl assert_cdylib::TestCase for TestCase { unsafe fn exec(&self, lib: &Library) -> anyhow::Result<()> { let Symbols { + voicevox_default_initialize_options, + voicevox_default_audio_query_options, + voicevox_default_synthesis_options, 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_with_initialize, voicevox_synthesizer_delete, voicevox_synthesizer_load_voice_model, - voicevox_make_default_audio_query_options, voicevox_synthesizer_audio_query, - voicevox_make_default_synthesis_options, voicevox_synthesizer_synthesis, voicevox_json_free, voicevox_wav_free, @@ -78,7 +78,7 @@ impl assert_cdylib::TestCase for TestCase { openjtalk, VoicevoxInitializeOptions { acceleration_mode: VoicevoxAccelerationMode::VOICEVOX_ACCELERATION_MODE_CPU, - ..voicevox_make_default_initialize_options() + ..**voicevox_default_initialize_options }, synthesizer.as_mut_ptr(), )); @@ -94,7 +94,7 @@ impl assert_cdylib::TestCase for TestCase { synthesizer, text.as_ptr(), STYLE_ID, - voicevox_make_default_audio_query_options(), + **voicevox_default_audio_query_options, audio_query.as_mut_ptr(), )); audio_query.assume_init() @@ -107,7 +107,7 @@ impl assert_cdylib::TestCase for TestCase { synthesizer, audio_query, STYLE_ID, - voicevox_make_default_synthesis_options(), + **voicevox_default_synthesis_options, wav_length.as_mut_ptr(), wav.as_mut_ptr(), )); diff --git a/example/cpp/unix/simple_tts.cpp b/example/cpp/unix/simple_tts.cpp index 3fb61742a..1c9fa00ca 100644 --- a/example/cpp/unix/simple_tts.cpp +++ b/example/cpp/unix/simple_tts.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { std::cout << "coreの初期化中..." << std::endl; - auto initialize_options = voicevox_make_default_initialize_options(); + auto initialize_options = voicevox_default_initialize_options; initialize_options.load_all_models = true; OpenJtalkRc* open_jtalk; auto result = voicevox_open_jtalk_rc_new(open_jtalk_dict_path.c_str(),&open_jtalk); @@ -40,7 +40,7 @@ int main(int argc, char *argv[]) { uint8_t *output_wav = nullptr; result = voicevox_synthesizer_tts(synthesizer,text.c_str(), speaker_id, - voicevox_make_default_tts_options(), + voicevox_default_tts_options, &output_wav_size, &output_wav); if (result != VOICEVOX_RESULT_OK) { std::cerr << voicevox_error_result_to_message(result) << std::endl; diff --git a/example/cpp/windows/simple_tts/simple_tts.cpp b/example/cpp/windows/simple_tts/simple_tts.cpp index b22ba067f..4905b09d2 100644 --- a/example/cpp/windows/simple_tts/simple_tts.cpp +++ b/example/cpp/windows/simple_tts/simple_tts.cpp @@ -28,7 +28,7 @@ int main() { std::wcin >> speak_words; std::wcout << L"coreの初期化中" << std::endl; - VoicevoxInitializeOptions initializeOptions = voicevox_make_default_initialize_options(); + VoicevoxInitializeOptions initializeOptions = voicevox_default_initialize_options; std::string dict = GetOpenJTalkDict(); initializeOptions.load_all_models = true; @@ -50,7 +50,7 @@ int main() { int32_t speaker_id = 0; uintptr_t output_binary_size = 0; uint8_t* output_wav = nullptr; - VoicevoxTtsOptions ttsOptions = voicevox_make_default_tts_options(); + VoicevoxTtsOptions ttsOptions = voicevox_default_tts_options; result = voicevox_synthesizer_tts(synthesizer,wide_to_utf8_cppapi(speak_words).c_str(), speaker_id, ttsOptions, &output_binary_size, &output_wav); if (result != VoicevoxResultCode::VOICEVOX_RESULT_OK) {