From f8f56ae9d7558f1040491a0cbbb52da6dbb67216 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Wed, 18 Oct 2023 12:46:02 +0900 Subject: [PATCH] =?UTF-8?q?`VoiceModel::get=5Fall=5Fmodels`=E3=82=92C=20AP?= =?UTF-8?q?I=E3=81=AB=E7=A7=BB=E5=8B=95=20(#649)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 6 +-- crates/voicevox_core/Cargo.toml | 3 +- crates/voicevox_core/src/voice_model.rs | 36 +------------ crates/voicevox_core_c_api/Cargo.toml | 7 ++- .../src/compatible_engine.rs | 50 ++++++++++++++++--- 6 files changed, 54 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3beb67d70..e96ad5dbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4293,7 +4293,6 @@ dependencies = [ "onnxruntime", "open_jtalk", "pretty_assertions", - "process_path", "regex", "rstest", "serde", @@ -4324,6 +4323,7 @@ dependencies = [ "derive-getters", "duct", "easy-ext", + "futures", "inventory", "itertools", "libc", diff --git a/Cargo.toml b/Cargo.toml index 789d35a51..73e6f5cd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ async_zip = { version = "0.0.11", features = ["full"] } clap = { version = "4.0.10", features = ["derive"] } easy-ext = "1.0.1" fs-err = { version = "2.9.0", features = ["tokio"] } +futures = "0.3.26" itertools = "0.10.5" once_cell = "1.18.0" regex = "1.10.0" @@ -33,11 +34,6 @@ voicevox_core = { path = "crates/voicevox_core" } tokio = { version = "1.25.0", features = ["rt", "rt-multi-thread", "macros", "sync"] } derive-getters = "0.2.0" -# FIXME: iOS対応のpull request(https://github.com/wesleywiser/process_path/pull/16)がマージされる見込みが無いため -[workspace.dependencies.process_path] -git = "https://github.com/VOICEVOX/process_path.git" -rev = "de226a26e8e18edbdb1d6f986afe37bbbf35fbf4" - [workspace.package] version = "0.0.0" edition = "2021" diff --git a/crates/voicevox_core/Cargo.toml b/crates/voicevox_core/Cargo.toml index 5e46fe653..988d694cf 100644 --- a/crates/voicevox_core/Cargo.toml +++ b/crates/voicevox_core/Cargo.toml @@ -18,12 +18,11 @@ derive_more = "0.99.17" duplicate = "1.0.0" easy-ext.workspace = true fs-err.workspace = true -futures = "0.3.26" +futures.workspace = true indexmap = { version = "2.0.0", features = ["serde"] } itertools.workspace = true nanoid = "0.4.0" once_cell.workspace = true -process_path.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/voicevox_core/src/voice_model.rs b/crates/voicevox_core/src/voice_model.rs index 8a86a4399..45e7dad17 100644 --- a/crates/voicevox_core/src/voice_model.rs +++ b/crates/voicevox_core/src/voice_model.rs @@ -1,11 +1,11 @@ use async_zip::{read::fs::ZipFileReader, ZipEntry}; -use futures::future::{join3, join_all}; +use futures::future::join3; use serde::{de::DeserializeOwned, Deserialize}; use super::*; use std::{ collections::{BTreeMap, HashMap}, - env, io, + io, path::{Path, PathBuf}, }; @@ -76,38 +76,6 @@ impl VoiceModel { }) } - // FIXME: C APIに移動する - /// # Panics - /// - /// 失敗したらパニックする - pub async fn get_all_models() -> Vec { - let root_dir = if let Some(root_dir) = env::var_os(Self::ROOT_DIR_ENV_NAME) { - root_dir.into() - } else { - process_path::get_dylib_path() - .or_else(process_path::get_executable_path) - .unwrap() - .parent() - .unwrap_or_else(|| "".as_ref()) - .join("model") - }; - - let vvm_paths = root_dir - .read_dir() - .and_then(|entries| entries.collect::, _>>()) - .unwrap_or_else(|e| panic!("{}が読めませんでした: {e}", root_dir.display())) - .into_iter() - .filter(|entry| entry.path().extension().map_or(false, |ext| ext == "vvm")) - .map(|entry| Self::from_path(entry.path())); - - join_all(vvm_paths) - .await - .into_iter() - .collect::>() - .unwrap() - } - const ROOT_DIR_ENV_NAME: &str = "VV_MODELS_ROOT_DIR"; - /// モデル内のすべてのスタイルに対するモデル内IDを取得する。 /// /// モデル内IDのマッピングが存在しない場合はそのままスタイルIDを返す。 diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index ae691c99b..f187f0001 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -21,6 +21,7 @@ anstyle-query = "1.0.0" colorchoice = "1.0.0" cstr = "0.2.11" derive-getters.workspace = true +futures.workspace = true itertools.workspace = true libc = "0.2.134" once_cell.workspace = true @@ -37,6 +38,11 @@ version = "0.4.23" default-features = false features = ["clock"] +# FIXME: iOS対応のpull request(https://github.com/wesleywiser/process_path/pull/16)がマージされる見込みが無いため +[dependencies.process_path] +git = "https://github.com/VOICEVOX/process_path.git" +rev = "de226a26e8e18edbdb1d6f986afe37bbbf35fbf4" + [dev-dependencies] anyhow.workspace = true assert_cmd = { version = "2.0.8", features = ["color-auto"] } @@ -48,7 +54,6 @@ libloading = "0.7.3" libtest-mimic = "0.6.0" ndarray = "0.15.6" ndarray-stats = "0.5.1" -process_path.workspace = true regex.workspace = true serde.workspace = true serde_with = "3.3.0" diff --git a/crates/voicevox_core_c_api/src/compatible_engine.rs b/crates/voicevox_core_c_api/src/compatible_engine.rs index 64470c7bf..6d0c94fd2 100644 --- a/crates/voicevox_core_c_api/src/compatible_engine.rs +++ b/crates/voicevox_core_c_api/src/compatible_engine.rs @@ -20,13 +20,14 @@ macro_rules! ensure_initialized { static ERROR_MESSAGE: Lazy> = Lazy::new(|| Mutex::new(String::new())); struct VoiceModelSet { + all_vvms: Vec, all_metas_json: CString, style_model_map: BTreeMap, model_map: BTreeMap, } -static VOICE_MODEL_SET: Lazy> = Lazy::new(|| { - let all_vvms = RUNTIME.block_on(VoiceModel::get_all_models()); +static VOICE_MODEL_SET: Lazy = Lazy::new(|| { + let all_vvms = RUNTIME.block_on(get_all_models()); let model_map: BTreeMap<_, _> = all_vvms .iter() .map(|vvm| (vvm.id().clone(), vvm.clone())) @@ -41,15 +42,50 @@ static VOICE_MODEL_SET: Lazy> = Lazy::new(|| { } } - Mutex::new(VoiceModelSet { + return VoiceModelSet { all_metas_json: CString::new(serde_json::to_string(&metas).unwrap()).unwrap(), + all_vvms, style_model_map, model_map, - }) + }; + + /// # Panics + /// + /// 失敗したらパニックする + async fn get_all_models() -> Vec { + let root_dir = if let Some(root_dir) = env::var_os(ROOT_DIR_ENV_NAME) { + root_dir.into() + } else { + process_path::get_dylib_path() + .or_else(process_path::get_executable_path) + .unwrap() + .parent() + .unwrap_or_else(|| "".as_ref()) + .join("model") + }; + + let vvm_paths = root_dir + .read_dir() + .and_then(|entries| entries.collect::, _>>()) + .unwrap_or_else(|e| panic!("{}が読めませんでした: {e}", root_dir.display())) + .into_iter() + .filter(|entry| entry.path().extension().map_or(false, |ext| ext == "vvm")) + .map(|entry| VoiceModel::from_path(entry.path())); + + futures::future::join_all(vvm_paths) + .await + .into_iter() + .collect::>() + .unwrap() + } + + const ROOT_DIR_ENV_NAME: &str = "VV_MODELS_ROOT_DIR"; }); -fn voice_model_set() -> MutexGuard<'static, VoiceModelSet> { - VOICE_MODEL_SET.lock().unwrap() +// FIXME: この関数を消して直接`VOICE_MODEL_SET`を参照するか、あるいは`once_cell::sync::OnceCell` +// 経由でエラーをエンジンに伝達するようにする +fn voice_model_set() -> &'static VoiceModelSet { + &VOICE_MODEL_SET } static SYNTHESIZER: Lazy>> = @@ -83,7 +119,7 @@ pub extern "C" fn initialize(use_gpu: bool, cpu_num_threads: c_int, load_all_mod .await?; if load_all_models { - for model in &VoiceModel::get_all_models().await { + for model in &voice_model_set().all_vvms { synthesizer.load_voice_model(model).await?; } }