From f0384697a074bb90431972a9085103b332691f69 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Tue, 5 Dec 2023 02:50:59 +0900 Subject: [PATCH 1/9] =?UTF-8?q?C=E3=81=A8Java=E3=81=AE=E3=83=96=E3=83=AD?= =?UTF-8?q?=E3=83=83=E3=82=AD=E3=83=B3=E3=82=B0API=E3=82=92=E5=AE=9F?= =?UTF-8?q?=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + crates/voicevox_core/src/synthesizer.rs | 3 +- crates/voicevox_core_c_api/Cargo.toml | 1 + crates/voicevox_core_c_api/src/c_impls.rs | 20 +- .../src/compatible_engine.rs | 244 ++++++++------- crates/voicevox_core_c_api/src/helpers.rs | 161 +++++++--- crates/voicevox_core_c_api/src/lib.rs | 291 ++++++++---------- 7 files changed, 375 insertions(+), 346 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index deba74398..1067a4d42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4395,6 +4395,7 @@ dependencies = [ "cstr", "derive-getters", "duct", + "duplicate", "easy-ext", "futures", "inventory", diff --git a/crates/voicevox_core/src/synthesizer.rs b/crates/voicevox_core/src/synthesizer.rs index c178a0ddd..c2bb1af5f 100644 --- a/crates/voicevox_core/src/synthesizer.rs +++ b/crates/voicevox_core/src/synthesizer.rs @@ -357,7 +357,8 @@ impl self::blocking::Synthesizer { self.status.is_loaded_model(voice_model_id) } - fn is_loaded_model_by_style_id(&self, style_id: StyleId) -> bool { + #[doc(hidden)] + pub fn is_loaded_model_by_style_id(&self, style_id: StyleId) -> bool { self.status.is_loaded_model_by_style_id(style_id) } diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index fe5ef243b..5a55d0637 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -22,6 +22,7 @@ chrono = { workspace = true, default-features = false, features = ["clock"] } colorchoice.workspace = true cstr.workspace = true derive-getters.workspace = true +duplicate.workspace = true futures.workspace = true itertools.workspace = true libc.workspace = true diff --git a/crates/voicevox_core_c_api/src/c_impls.rs b/crates/voicevox_core_c_api/src/c_impls.rs index 61665f48f..4a839e68b 100644 --- a/crates/voicevox_core_c_api/src/c_impls.rs +++ b/crates/voicevox_core_c_api/src/c_impls.rs @@ -5,29 +5,25 @@ use voicevox_core::{InitializeOptions, Result, VoiceModelId}; use crate::{CApiResult, OpenJtalkRc, VoicevoxSynthesizer, VoicevoxVoiceModel}; impl OpenJtalkRc { - pub(crate) async fn new(open_jtalk_dic_dir: impl AsRef) -> Result { + pub(crate) fn new(open_jtalk_dic_dir: impl AsRef) -> Result { Ok(Self { - open_jtalk: voicevox_core::tokio::OpenJtalk::new(open_jtalk_dic_dir).await?, + open_jtalk: voicevox_core::blocking::OpenJtalk::new(open_jtalk_dic_dir)?, }) } } impl VoicevoxSynthesizer { pub(crate) fn new(open_jtalk: &OpenJtalkRc, options: &InitializeOptions) -> Result { - // ロガーを起動 - // FIXME: `into_result_code_with_error`を`run`とかに改名し、`init_logger`をその中に移動 - let _ = *crate::RUNTIME; - let synthesizer = - voicevox_core::tokio::Synthesizer::new(open_jtalk.open_jtalk.clone(), options)?; + voicevox_core::blocking::Synthesizer::new(open_jtalk.open_jtalk.clone(), options)?; Ok(Self { synthesizer }) } - pub(crate) async fn load_voice_model( + pub(crate) fn load_voice_model( &self, - model: &voicevox_core::tokio::VoiceModel, + model: &voicevox_core::blocking::VoiceModel, ) -> CApiResult<()> { - self.synthesizer.load_voice_model(model).await?; + self.synthesizer.load_voice_model(model)?; Ok(()) } @@ -43,8 +39,8 @@ impl VoicevoxSynthesizer { } impl VoicevoxVoiceModel { - pub(crate) async fn from_path(path: impl AsRef) -> Result { - let model = voicevox_core::tokio::VoiceModel::from_path(path).await?; + pub(crate) fn from_path(path: impl AsRef) -> Result { + let model = voicevox_core::blocking::VoiceModel::from_path(path)?; let id = CString::new(model.id().raw_voice_model_id().as_str()).unwrap(); let metas = CString::new(serde_json::to_string(model.metas()).unwrap()).unwrap(); Ok(Self { model, id, metas }) diff --git a/crates/voicevox_core_c_api/src/compatible_engine.rs b/crates/voicevox_core_c_api/src/compatible_engine.rs index 694753827..4a24e0e1e 100644 --- a/crates/voicevox_core_c_api/src/compatible_engine.rs +++ b/crates/voicevox_core_c_api/src/compatible_engine.rs @@ -20,14 +20,14 @@ macro_rules! ensure_initialized { static ERROR_MESSAGE: Lazy> = Lazy::new(|| Mutex::new(String::new())); struct VoiceModelSet { - all_vvms: Vec, + all_vvms: Vec, all_metas_json: CString, style_model_map: BTreeMap, - model_map: BTreeMap, + model_map: BTreeMap, } static VOICE_MODEL_SET: Lazy = Lazy::new(|| { - let all_vvms = RUNTIME.block_on(get_all_models()); + let all_vvms = get_all_models(); let model_map: BTreeMap<_, _> = all_vvms .iter() .map(|vvm| (vvm.id().clone(), vvm.clone())) @@ -52,7 +52,7 @@ static VOICE_MODEL_SET: Lazy = Lazy::new(|| { /// # Panics /// /// 失敗したらパニックする - async fn get_all_models() -> Vec { + fn get_all_models() -> Vec { let root_dir = if let Some(root_dir) = env::var_os(ROOT_DIR_ENV_NAME) { root_dir.into() } else { @@ -64,17 +64,13 @@ static VOICE_MODEL_SET: Lazy = Lazy::new(|| { .join("model") }; - let vvm_paths = root_dir + 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| voicevox_core::tokio::VoiceModel::from_path(entry.path())); - - futures::future::join_all(vvm_paths) - .await - .into_iter() + .map(|entry| voicevox_core::blocking::VoiceModel::from_path(entry.path())) .collect::>() .unwrap() } @@ -88,10 +84,10 @@ fn voice_model_set() -> &'static VoiceModelSet { &VOICE_MODEL_SET } -static SYNTHESIZER: Lazy>>> = +static SYNTHESIZER: Lazy>>> = Lazy::new(|| Mutex::new(None)); -fn lock_synthesizer() -> MutexGuard<'static, Option>> { +fn lock_synthesizer() -> MutexGuard<'static, Option>> { SYNTHESIZER.lock().unwrap() } @@ -104,87 +100,93 @@ fn set_message(message: &str) { #[no_mangle] pub extern "C" fn initialize(use_gpu: bool, cpu_num_threads: c_int, load_all_models: bool) -> bool { - // FIXME: ここはもう`RUNTIME.block_on`で包む必要は無くなっているのだが、ロガーの設定を`RUNTIME` - // で行っているという構造になってしまっているので、外すとロガーの初期化が遅れてしまでう - let result = RUNTIME.block_on(async { - let synthesizer = voicevox_core::tokio::Synthesizer::new( - (), - &voicevox_core::InitializeOptions { - acceleration_mode: if use_gpu { - voicevox_core::AccelerationMode::Gpu - } else { - voicevox_core::AccelerationMode::Cpu + run(|| { + let result = (|| { + let synthesizer = voicevox_core::blocking::Synthesizer::new( + (), + &voicevox_core::InitializeOptions { + acceleration_mode: if use_gpu { + voicevox_core::AccelerationMode::Gpu + } else { + voicevox_core::AccelerationMode::Cpu + }, + cpu_num_threads: cpu_num_threads as u16, }, - cpu_num_threads: cpu_num_threads as u16, - }, - )?; + )?; - if load_all_models { - for model in &voice_model_set().all_vvms { - synthesizer.load_voice_model(model).await?; + if load_all_models { + for model in &voice_model_set().all_vvms { + synthesizer.load_voice_model(model)?; + } } - } - Ok::<_, voicevox_core::Error>(synthesizer) - }); + Ok::<_, voicevox_core::Error>(synthesizer) + })(); - match result { - Ok(synthesizer) => { - *lock_synthesizer() = Some(synthesizer); - true - } - Err(err) => { - set_message(&format!("{err}")); - false + match result { + Ok(synthesizer) => { + *lock_synthesizer() = Some(synthesizer); + true + } + Err(err) => { + set_message(&format!("{err}")); + false + } } - } + }) } #[no_mangle] pub extern "C" fn load_model(style_id: i64) -> bool { - let style_id = StyleId::new(style_id as u32); - let model_set = voice_model_set(); - if let Some(model_id) = model_set.style_model_map.get(&style_id) { - let vvm = model_set.model_map.get(model_id).unwrap(); - let synthesizer = &mut *lock_synthesizer(); - let result = RUNTIME.block_on(ensure_initialized!(synthesizer).load_voice_model(vvm)); - if let Some(err) = result.err() { - set_message(&format!("{err}")); - false + run(|| { + let style_id = StyleId::new(style_id as u32); + let model_set = voice_model_set(); + if let Some(model_id) = model_set.style_model_map.get(&style_id) { + let vvm = model_set.model_map.get(model_id).unwrap(); + let synthesizer = &mut *lock_synthesizer(); + let result = ensure_initialized!(synthesizer).load_voice_model(vvm); + if let Some(err) = result.err() { + set_message(&format!("{err}")); + false + } else { + true + } } else { - true + set_message(&format!("{}は無効なStyle IDです", style_id)); + false } - } else { - set_message(&format!("{}は無効なStyle IDです", style_id)); - false - } + }) } #[no_mangle] pub extern "C" fn is_model_loaded(speaker_id: i64) -> bool { - ensure_initialized!(&*lock_synthesizer()) - .is_loaded_model_by_style_id(StyleId::new(speaker_id as u32)) + run(|| { + ensure_initialized!(&*lock_synthesizer()) + .is_loaded_model_by_style_id(StyleId::new(speaker_id as u32)) + }) } #[no_mangle] pub extern "C" fn finalize() { - *lock_synthesizer() = None; + run(|| *lock_synthesizer() = None); } #[no_mangle] pub extern "C" fn metas() -> *const c_char { - let model_set = voice_model_set(); - model_set.all_metas_json.as_ptr() + run(|| { + let model_set = voice_model_set(); + model_set.all_metas_json.as_ptr() + }) } #[no_mangle] pub extern "C" fn last_error_message() -> *const c_char { - ERROR_MESSAGE.lock().unwrap().as_ptr() as *const c_char + run(|| ERROR_MESSAGE.lock().unwrap().as_ptr() as *const c_char) } #[no_mangle] pub extern "C" fn supported_devices() -> *const c_char { - return SUPPORTED_DEVICES.as_ptr(); + return run(|| SUPPORTED_DEVICES.as_ptr()); static SUPPORTED_DEVICES: Lazy = Lazy::new(|| { CString::new(SupportedDevices::create().unwrap().to_json().to_string()).unwrap() @@ -198,22 +200,25 @@ pub extern "C" fn yukarin_s_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).predict_duration( - unsafe { std::slice::from_raw_parts_mut(phoneme_list, length as usize) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false + run(|| { + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).predict_duration( + unsafe { std::slice::from_raw_parts_mut(phoneme_list, length as usize) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = + unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; + output_slice.clone_from_slice(&output_vec); + true + } + Err(err) => { + set_message(&format!("{err}")); + false + } } - } + }) } #[no_mangle] @@ -228,28 +233,31 @@ pub extern "C" fn yukarin_sa_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).predict_intonation( - length as usize, - unsafe { std::slice::from_raw_parts(vowel_phoneme_list, length as usize) }, - unsafe { std::slice::from_raw_parts(consonant_phoneme_list, length as usize) }, - unsafe { std::slice::from_raw_parts(start_accent_list, length as usize) }, - unsafe { std::slice::from_raw_parts(end_accent_list, length as usize) }, - unsafe { std::slice::from_raw_parts(start_accent_phrase_list, length as usize) }, - unsafe { std::slice::from_raw_parts(end_accent_phrase_list, length as usize) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false + run(|| { + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).predict_intonation( + length as usize, + unsafe { std::slice::from_raw_parts(vowel_phoneme_list, length as usize) }, + unsafe { std::slice::from_raw_parts(consonant_phoneme_list, length as usize) }, + unsafe { std::slice::from_raw_parts(start_accent_list, length as usize) }, + unsafe { std::slice::from_raw_parts(end_accent_list, length as usize) }, + unsafe { std::slice::from_raw_parts(start_accent_phrase_list, length as usize) }, + unsafe { std::slice::from_raw_parts(end_accent_phrase_list, length as usize) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = + unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; + output_slice.clone_from_slice(&output_vec); + true + } + Err(err) => { + set_message(&format!("{err}")); + false + } } - } + }) } #[no_mangle] @@ -261,25 +269,27 @@ pub extern "C" fn decode_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let length = length as usize; - let phoneme_size = phoneme_size as usize; - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).decode( - length, - phoneme_size, - unsafe { std::slice::from_raw_parts(f0, length) }, - unsafe { std::slice::from_raw_parts(phoneme, phoneme_size * length) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length * 256) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false + run(|| { + let length = length as usize; + let phoneme_size = phoneme_size as usize; + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).decode( + length, + phoneme_size, + unsafe { std::slice::from_raw_parts(f0, length) }, + unsafe { std::slice::from_raw_parts(phoneme, phoneme_size * length) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length * 256) }; + output_slice.clone_from_slice(&output_vec); + true + } + Err(err) => { + set_message(&format!("{err}")); + false + } } - } + }) } diff --git a/crates/voicevox_core_c_api/src/helpers.rs b/crates/voicevox_core_c_api/src/helpers.rs index 698e89b45..f66710752 100644 --- a/crates/voicevox_core_c_api/src/helpers.rs +++ b/crates/voicevox_core_c_api/src/helpers.rs @@ -1,57 +1,128 @@ use std::{error::Error as _, fmt::Debug, iter}; use voicevox_core::UserDictWord; +use duplicate::duplicate_item; use thiserror::Error; use tracing::error; use super::*; use voicevox_core::AccentPhraseModel; -pub(crate) fn into_result_code_with_error(result: CApiResult<()>) -> VoicevoxResultCode { - if let Err(err) = &result { - display_error(err); - } - return into_result_code(result); - - fn display_error(err: &CApiError) { - itertools::chain( - [err.to_string()], - iter::successors(err.source(), |&e| e.source()).map(|e| format!("Caused by: {e}")), - ) - .for_each(|msg| error!("{msg}")); - } - - fn into_result_code(result: CApiResult<()>) -> VoicevoxResultCode { - use voicevox_core::ErrorKind::*; - use CApiError::*; - use VoicevoxResultCode::*; - - match result { - Ok(()) => VOICEVOX_RESULT_OK, - Err(RustApi(err)) => match err.kind() { - NotLoadedOpenjtalkDict => VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR, - GpuSupport => VOICEVOX_RESULT_GPU_SUPPORT_ERROR, - OpenZipFile => VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, - ReadZipEntry => VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, - ModelAlreadyLoaded => VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, - StyleAlreadyLoaded => VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, - InvalidModelData => VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, - GetSupportedDevices => VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR, - StyleNotFound => VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR, - ModelNotFound => VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR, - InferenceFailed => VOICEVOX_RESULT_INFERENCE_ERROR, - ExtractFullContextLabel => VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR, - ParseKana => VOICEVOX_RESULT_PARSE_KANA_ERROR, - LoadUserDict => VOICEVOX_RESULT_LOAD_USER_DICT_ERROR, - SaveUserDict => VOICEVOX_RESULT_SAVE_USER_DICT_ERROR, - WordNotFound => VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR, - UseUserDict => VOICEVOX_RESULT_USE_USER_DICT_ERROR, - InvalidWord => VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR, - }, - Err(InvalidUtf8Input) => VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR, - Err(InvalidAudioQuery(_)) => VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR, - Err(InvalidAccentPhrase(_)) => VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR, - Err(InvalidUuid(_)) => VOICEVOX_RESULT_INVALID_UUID_ERROR, +pub(crate) fn run O, O: Outcome>(f: F) -> O::Output { + let _ = init_logger(); + return f().convert_with_error(); + + fn init_logger() -> std::result::Result<(), impl Sized> { + let ansi = { + // anstyle系のクレートを利用して次の2つを行う。 + // + // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) + // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 + + assert_eq!( + ColorChoice::Auto, + ColorChoice::global(), + "`ColorChoice::write_global` should not have been called", + ); + + AutoStream::choice(&out()) != ColorChoice::Never + && anstyle_query::term_supports_ansi_color() + && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) + }; + + tracing_subscriber::fmt() + .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { + EnvFilter::from_default_env() + } else { + "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() + }) + .with_timer(local_time as fn(&mut Writer<'_>) -> _) + .with_ansi(ansi) + .with_writer(out) + .try_init() + } + + fn local_time(wtr: &mut Writer<'_>) -> fmt::Result { + // ローカル時刻で表示はするが、そのフォーマットはtracing-subscriber本来のものに近いようにする。 + // https://github.com/tokio-rs/tracing/blob/tracing-subscriber-0.3.16/tracing-subscriber/src/fmt/time/datetime.rs#L235-L241 + wtr.write_str(&chrono::Local::now().to_rfc3339_opts(SecondsFormat::Micros, false)) + } + + fn out() -> impl RawStream { + io::stderr() + } +} + +pub(crate) trait Outcome: Sized { + type Output; + fn convert_with_error(self) -> Self::Output; +} + +#[duplicate_item( + impl_generics T; + [] [ () ]; + [] [ bool ]; + [] [ *const c_char ]; + [] [ *mut c_char ]; + [ T ] [ Box ]; +)] +impl Outcome for T { + type Output = Self; + + fn convert_with_error(self) -> Self::Output { + self + } +} + +impl Outcome for CApiResult<()> { + type Output = VoicevoxResultCode; + + fn convert_with_error(self) -> Self::Output { + if let Err(err) = &self { + display_error(err); + } + return into_result_code(self); + + fn display_error(err: &CApiError) { + itertools::chain( + [err.to_string()], + iter::successors(err.source(), |&e| e.source()).map(|e| format!("Caused by: {e}")), + ) + .for_each(|msg| error!("{msg}")); + } + + fn into_result_code(this: CApiResult<()>) -> VoicevoxResultCode { + use voicevox_core::ErrorKind::*; + use CApiError::*; + use VoicevoxResultCode::*; + + match this { + Ok(()) => VOICEVOX_RESULT_OK, + Err(RustApi(err)) => match err.kind() { + NotLoadedOpenjtalkDict => VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR, + GpuSupport => VOICEVOX_RESULT_GPU_SUPPORT_ERROR, + OpenZipFile => VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, + ReadZipEntry => VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, + ModelAlreadyLoaded => VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, + StyleAlreadyLoaded => VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, + InvalidModelData => VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, + GetSupportedDevices => VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR, + StyleNotFound => VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR, + ModelNotFound => VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR, + InferenceFailed => VOICEVOX_RESULT_INFERENCE_ERROR, + ExtractFullContextLabel => VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR, + ParseKana => VOICEVOX_RESULT_PARSE_KANA_ERROR, + LoadUserDict => VOICEVOX_RESULT_LOAD_USER_DICT_ERROR, + SaveUserDict => VOICEVOX_RESULT_SAVE_USER_DICT_ERROR, + WordNotFound => VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR, + UseUserDict => VOICEVOX_RESULT_USE_USER_DICT_ERROR, + InvalidWord => VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR, + }, + Err(InvalidUtf8Input) => VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR, + Err(InvalidAudioQuery(_)) => VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR, + Err(InvalidAccentPhrase(_)) => VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR, + Err(InvalidUuid(_)) => VOICEVOX_RESULT_INVALID_UUID_ERROR, + } } } } diff --git a/crates/voicevox_core_c_api/src/lib.rs b/crates/voicevox_core_c_api/src/lib.rs index 1be2cafc6..5f274f15b 100644 --- a/crates/voicevox_core_c_api/src/lib.rs +++ b/crates/voicevox_core_c_api/src/lib.rs @@ -25,59 +25,12 @@ use std::io; use std::os::raw::c_char; use std::ptr::NonNull; use std::sync::{Arc, Mutex, MutexGuard}; -use tokio::runtime::Runtime; use tracing_subscriber::fmt::format::Writer; use tracing_subscriber::EnvFilter; use uuid::Uuid; use voicevox_core::{AccentPhraseModel, AudioQueryModel, TtsOptions, UserDictWord, VoiceModelId}; use voicevox_core::{StyleId, SupportedDevices, SynthesisOptions}; -static RUNTIME: Lazy = Lazy::new(|| { - let _ = init_logger(); - - fn init_logger() -> std::result::Result<(), impl Sized> { - let ansi = { - // anstyle系のクレートを利用して次の2つを行う。 - // - // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) - // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 - - assert_eq!( - ColorChoice::Auto, - ColorChoice::global(), - "`ColorChoice::write_global` should not have been called", - ); - - AutoStream::choice(&out()) != ColorChoice::Never - && anstyle_query::term_supports_ansi_color() - && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) - }; - - tracing_subscriber::fmt() - .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { - EnvFilter::from_default_env() - } else { - "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() - }) - .with_timer(local_time as fn(&mut Writer<'_>) -> _) - .with_ansi(ansi) - .with_writer(out) - .try_init() - } - - fn local_time(wtr: &mut Writer<'_>) -> fmt::Result { - // ローカル時刻で表示はするが、そのフォーマットはtracing-subscriber本来のものに近いようにする。 - // https://github.com/tokio-rs/tracing/blob/tracing-subscriber-0.3.16/tracing-subscriber/src/fmt/time/datetime.rs#L235-L241 - wtr.write_str(&chrono::Local::now().to_rfc3339_opts(SecondsFormat::Micros, false)) - } - - fn out() -> impl RawStream { - io::stderr() - } - - Runtime::new().unwrap() -}); - /* * Cの関数として公開するための型や関数を定義するこれらの実装はvoicevox_core/publish.rsに定義してある対応する関数にある * この関数ではvoicevox_core/publish.rsにある対応する関数の呼び出しと、その戻り値をCの形式に変換する処理のみとする @@ -101,7 +54,7 @@ static RUNTIME: Lazy = Lazy::new(|| { /// ``` /// } pub struct OpenJtalkRc { - open_jtalk: voicevox_core::tokio::OpenJtalk, + open_jtalk: voicevox_core::blocking::OpenJtalk, } /// ::OpenJtalkRc を構築(_construct_)する。 @@ -129,14 +82,12 @@ pub unsafe extern "C" fn voicevox_open_jtalk_rc_new( open_jtalk_dic_dir: *const c_char, out_open_jtalk: NonNull>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let open_jtalk_dic_dir = ensure_utf8(CStr::from_ptr(open_jtalk_dic_dir))?; - let open_jtalk = RUNTIME - .block_on(OpenJtalkRc::new(open_jtalk_dic_dir))? - .into(); + let open_jtalk = OpenJtalkRc::new(open_jtalk_dic_dir)?.into(); out_open_jtalk.as_ptr().write_unaligned(open_jtalk); Ok(()) - })()) + }) } /// OpenJtalkの使うユーザー辞書を設定する。 @@ -155,10 +106,10 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( open_jtalk: &OpenJtalkRc, user_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { - RUNTIME.block_on(open_jtalk.open_jtalk.use_user_dict(&user_dict.dict))?; + run(|| { + open_jtalk.open_jtalk.use_user_dict(&user_dict.dict)?; Ok(()) - })()) + }) } /// ::OpenJtalkRc を破棄(_destruct_)する。 @@ -177,7 +128,7 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( /// } #[no_mangle] pub extern "C" fn voicevox_open_jtalk_rc_delete(open_jtalk: Box) { - drop(open_jtalk); + run(|| drop(open_jtalk)); } /// ハードウェアアクセラレーションモードを設定する設定値。 @@ -207,6 +158,7 @@ pub struct VoicevoxInitializeOptions { /// @return デフォルト値が設定された初期化オプション #[no_mangle] pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitializeOptions { + // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し VoicevoxInitializeOptions::default() } @@ -214,7 +166,7 @@ pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitiali /// @return SemVerでフォーマットされたバージョン。 #[no_mangle] pub extern "C" fn voicevox_get_version() -> *const c_char { - return C_STRING_DROP_CHECKER.blacklist(VERSION).as_ptr(); + return run(|| C_STRING_DROP_CHECKER.blacklist(VERSION).as_ptr()); const VERSION: &CStr = unsafe { // SAFETY: The package version is a SemVer, so it should not contain '\0' @@ -228,7 +180,7 @@ pub extern "C" fn voicevox_get_version() -> *const c_char { /// 構築(_construction_)は ::voicevox_voice_model_new_from_path で行い、破棄(_destruction_)は ::voicevox_voice_model_delete で行う。 #[derive(Getters)] pub struct VoicevoxVoiceModel { - model: voicevox_core::tokio::VoiceModel, + model: voicevox_core::blocking::VoiceModel, id: CString, metas: CString, } @@ -257,14 +209,12 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( path: *const c_char, out_model: NonNull>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let path = ensure_utf8(CStr::from_ptr(path))?; - let model = RUNTIME - .block_on(VoicevoxVoiceModel::from_path(path))? - .into(); + let model = VoicevoxVoiceModel::from_path(path)?.into(); out_model.as_ptr().write_unaligned(model); Ok(()) - })()) + }) } /// ::VoicevoxVoiceModel からIDを取得する。 @@ -278,7 +228,7 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> VoicevoxVoiceModelId { - model.id().as_ptr() + run(|| model.id().as_ptr()) } /// ::VoicevoxVoiceModel からメタ情報を取得する。 @@ -293,7 +243,7 @@ pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> Voicevo /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel) -> *const c_char { - model.metas().as_ptr() + run(|| model.metas().as_ptr()) } /// ::VoicevoxVoiceModel を破棄(_destruct_)する。 @@ -306,7 +256,7 @@ pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_delete(model: Box) { - drop(model); + run(|| drop(model)); } /// 音声シンセサイザ。 @@ -314,7 +264,7 @@ pub extern "C" fn voicevox_voice_model_delete(model: Box) { /// 構築(_construction_)は ::voicevox_synthesizer_new で行い、破棄(_destruction_)は ::voicevox_synthesizer_delete で行う。 #[derive(Getters)] pub struct VoicevoxSynthesizer { - synthesizer: voicevox_core::tokio::Synthesizer, + synthesizer: voicevox_core::blocking::Synthesizer, } /// ::VoicevoxSynthesizer を構築(_construct_)する。 @@ -335,13 +285,13 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( options: VoicevoxInitializeOptions, out_synthesizer: NonNull>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let options = options.into(); let synthesizer = VoicevoxSynthesizer::new(open_jtalk, &options)?.into(); out_synthesizer.as_ptr().write_unaligned(synthesizer); Ok(()) - })()) + }) } /// ::VoicevoxSynthesizer を破棄(_destruct_)する。 @@ -354,7 +304,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_delete(synthesizer: Box) { - drop(synthesizer); + run(|| drop(synthesizer)); } /// 音声モデルを読み込む。 @@ -373,7 +323,7 @@ pub extern "C" fn voicevox_synthesizer_load_voice_model( synthesizer: &VoicevoxSynthesizer, model: &VoicevoxVoiceModel, ) -> VoicevoxResultCode { - into_result_code_with_error(RUNTIME.block_on(synthesizer.load_voice_model(model.model()))) + run(|| synthesizer.load_voice_model(model.model())) } /// 音声モデルの読み込みを解除する。 @@ -392,12 +342,12 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) })?; synthesizer .unload_voice_model(&VoiceModelId::new(raw_model_id.to_string())) .map_err(Into::into) - })()) + }) } /// ハードウェアアクセラレーションがGPUモードか判定する。 @@ -411,7 +361,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_is_gpu_mode(synthesizer: &VoicevoxSynthesizer) -> bool { - synthesizer.synthesizer().is_gpu_mode() + run(|| synthesizer.synthesizer().is_gpu_mode()) } /// 指定したIDの音声モデルが読み込まれているか判定する。 @@ -430,10 +380,12 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> bool { - let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) }).unwrap(); - synthesizer - .synthesizer() - .is_loaded_voice_model(&VoiceModelId::new(raw_model_id.into())) + run(|| { + let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) }).unwrap(); + synthesizer + .synthesizer() + .is_loaded_voice_model(&VoiceModelId::new(raw_model_id.into())) + }) } /// 今読み込んでいる音声モデルのメタ情報を、JSONで取得する。 @@ -451,8 +403,10 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( pub extern "C" fn voicevox_synthesizer_create_metas_json( synthesizer: &VoicevoxSynthesizer, ) -> *mut c_char { - let metas = synthesizer.metas(); - C_STRING_DROP_CHECKER.whitelist(metas).into_raw() + run(|| { + let metas = synthesizer.metas(); + C_STRING_DROP_CHECKER.whitelist(metas).into_raw() + }) } /// このライブラリで利用可能なデバイスの情報を、JSONで取得する。 @@ -479,7 +433,7 @@ pub extern "C" fn voicevox_synthesizer_create_metas_json( pub unsafe extern "C" fn voicevox_create_supported_devices_json( output_supported_devices_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let supported_devices = CString::new(SupportedDevices::create()?.to_json().to_string()).unwrap(); output_supported_devices_json.as_ptr().write_unaligned( @@ -488,7 +442,7 @@ pub unsafe extern "C" fn voicevox_create_supported_devices_json( .into_raw(), ); Ok(()) - })()) + }) } /// AquesTalk風記法から、AudioQueryをJSONとして生成する。 @@ -523,21 +477,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query_from_kana( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let kana = CStr::from_ptr(kana); let kana = ensure_utf8(kana)?; - let audio_query = RUNTIME.block_on( - synthesizer - .synthesizer() - .audio_query_from_kana(kana, StyleId::new(style_id)), - )?; + + let audio_query = synthesizer + .synthesizer() + .audio_query_from_kana(kana, StyleId::new(style_id))?; let audio_query = CString::new(audio_query_model_to_json(&audio_query)) .expect("should not contain '\\0'"); output_audio_query_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw()); Ok(()) - })()) + }) } /// 日本語テキストから、AudioQueryをJSONとして生成する。 @@ -572,21 +525,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let text = CStr::from_ptr(text); let text = ensure_utf8(text)?; - let audio_query = RUNTIME.block_on( - synthesizer - .synthesizer() - .audio_query(text, StyleId::new(style_id)), - )?; + + let audio_query = synthesizer + .synthesizer() + .audio_query(text, StyleId::new(style_id))?; let audio_query = CString::new(audio_query_model_to_json(&audio_query)) .expect("should not contain '\\0'"); output_audio_query_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw()); Ok(()) - })()) + }) } /// AquesTalk風記法から、AccentPhrase (アクセント句)の配列をJSON形式で生成する。 @@ -622,20 +574,18 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases_from_kana( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; - let accent_phrases = RUNTIME.block_on( - synthesizer - .synthesizer() - .create_accent_phrases_from_kana(kana, StyleId::new(style_id)), - )?; + let accent_phrases = synthesizer + .synthesizer() + .create_accent_phrases_from_kana(kana, StyleId::new(style_id))?; let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases)) .expect("should not contain '\\0'"); output_accent_phrases_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - })()) + }) } /// 日本語テキストから、AccentPhrase (アクセント句)の配列をJSON形式で生成する。 @@ -670,20 +620,18 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let text = ensure_utf8(CStr::from_ptr(text))?; - let accent_phrases = RUNTIME.block_on( - synthesizer - .synthesizer() - .create_accent_phrases(text, StyleId::new(style_id)), - )?; + let accent_phrases = synthesizer + .synthesizer() + .create_accent_phrases(text, StyleId::new(style_id))?; let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases)) .expect("should not contain '\\0'"); output_accent_phrases_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - })()) + }) } /// AccentPhraseの配列の音高・音素長を、特定の声で生成しなおす。 @@ -709,22 +657,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; - let accent_phrases = RUNTIME.block_on( - synthesizer - .synthesizer() - .replace_mora_data(&accent_phrases, StyleId::new(style_id)), - )?; + let accent_phrases = synthesizer + .synthesizer() + .replace_mora_data(&accent_phrases, StyleId::new(style_id))?; let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases)) .expect("should not contain '\\0'"); output_accent_phrases_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - })()) + }) } /// AccentPhraseの配列の音素長を、特定の声で生成しなおす。 @@ -750,22 +696,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; - let accent_phrases = RUNTIME.block_on( - synthesizer - .synthesizer() - .replace_phoneme_length(&accent_phrases, StyleId::new(style_id)), - )?; + let accent_phrases = synthesizer + .synthesizer() + .replace_phoneme_length(&accent_phrases, StyleId::new(style_id))?; let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases)) .expect("should not contain '\\0'"); output_accent_phrases_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - })()) + }) } /// AccentPhraseの配列の音高を、特定の声で生成しなおす。 @@ -791,22 +735,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; - let accent_phrases = RUNTIME.block_on( - synthesizer - .synthesizer() - .replace_mora_pitch(&accent_phrases, StyleId::new(style_id)), - )?; + let accent_phrases = synthesizer + .synthesizer() + .replace_mora_pitch(&accent_phrases, StyleId::new(style_id))?; let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases)) .expect("should not contain '\\0'"); output_accent_phrases_json .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - })()) + }) } /// ::voicevox_synthesizer_synthesis のオプション。 @@ -820,6 +762,7 @@ pub struct VoicevoxSynthesisOptions { /// @return デフォルト値が設定された `voicevox_synthesizer_synthesis` のオプション #[no_mangle] pub extern "C" fn voicevox_make_default_synthesis_options() -> VoicevoxSynthesisOptions { + // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し VoicevoxSynthesisOptions::default() } @@ -851,20 +794,20 @@ pub unsafe extern "C" fn voicevox_synthesizer_synthesis( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let audio_query_json = CStr::from_ptr(audio_query_json) .to_str() .map_err(|_| CApiError::InvalidUtf8Input)?; let audio_query: AudioQueryModel = serde_json::from_str(audio_query_json).map_err(CApiError::InvalidAudioQuery)?; - let wav = RUNTIME.block_on(synthesizer.synthesizer().synthesis( + let wav = synthesizer.synthesizer().synthesis( &audio_query, StyleId::new(style_id), &SynthesisOptions::from(options), - ))?; + )?; U8_SLICE_OWNER.own_and_lend(wav, output_wav, output_wav_length); Ok(()) - })()) + }) } /// ::voicevox_synthesizer_tts のオプション。 @@ -878,6 +821,7 @@ pub struct VoicevoxTtsOptions { /// @return テキスト音声合成オプション #[no_mangle] pub extern "C" fn voicevox_make_default_tts_options() -> VoicevoxTtsOptions { + // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し voicevox_core::TtsOptions::default().into() } @@ -909,16 +853,16 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts_from_kana( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; - let output = RUNTIME.block_on(synthesizer.synthesizer().tts_from_kana( + let output = synthesizer.synthesizer().tts_from_kana( kana, StyleId::new(style_id), &TtsOptions::from(options), - ))?; + )?; U8_SLICE_OWNER.own_and_lend(output, output_wav, output_wav_length); Ok(()) - })()) + }) } /// 日本語テキストから音声合成を行う。 @@ -949,16 +893,16 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let text = ensure_utf8(CStr::from_ptr(text))?; - let output = RUNTIME.block_on(synthesizer.synthesizer().tts( + let output = synthesizer.synthesizer().tts( text, StyleId::new(style_id), &TtsOptions::from(options), - ))?; + )?; U8_SLICE_OWNER.own_and_lend(output, output_wav, output_wav_length); Ok(()) - })()) + }) } /// JSON文字列を解放する。 @@ -981,7 +925,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { - drop(CString::from_raw(C_STRING_DROP_CHECKER.check(json))); + run(|| drop(CString::from_raw(C_STRING_DROP_CHECKER.check(json)))); } /// WAVデータを解放する。 @@ -997,7 +941,7 @@ pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { /// } #[no_mangle] pub extern "C" fn voicevox_wav_free(wav: *mut u8) { - U8_SLICE_OWNER.drop_for(wav); + run(|| U8_SLICE_OWNER.drop_for(wav)); } /// 結果コードに対応したメッセージ文字列を取得する。 @@ -1024,14 +968,16 @@ pub extern "C" fn voicevox_wav_free(wav: *mut u8) { pub extern "C" fn voicevox_error_result_to_message( result_code: VoicevoxResultCode, ) -> *const c_char { - let message = result_code::error_result_to_message(result_code); - C_STRING_DROP_CHECKER.blacklist(message).as_ptr() + run(|| { + let message = result_code::error_result_to_message(result_code); + C_STRING_DROP_CHECKER.blacklist(message).as_ptr() + }) } /// ユーザー辞書。 #[derive(Default)] pub struct VoicevoxUserDict { - dict: Arc, + dict: Arc, } /// ユーザー辞書の単語。 @@ -1077,6 +1023,7 @@ pub extern "C" fn voicevox_user_dict_word_make( surface: *const c_char, pronunciation: *const c_char, ) -> VoicevoxUserDictWord { + // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し VoicevoxUserDictWord { surface, pronunciation, @@ -1091,7 +1038,7 @@ pub extern "C" fn voicevox_user_dict_word_make( /// @returns ::VoicevoxUserDict #[no_mangle] pub extern "C" fn voicevox_user_dict_new() -> Box { - Default::default() + run(Box::::default) } /// ユーザー辞書にファイルを読み込ませる。 @@ -1109,12 +1056,12 @@ pub unsafe extern "C" fn voicevox_user_dict_load( user_dict: &VoicevoxUserDict, dict_path: *const c_char, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let dict_path = ensure_utf8(unsafe { CStr::from_ptr(dict_path) })?; - RUNTIME.block_on(user_dict.dict.load(dict_path))?; + user_dict.dict.load(dict_path)?; Ok(()) - })()) + }) } /// ユーザー辞書に単語を追加する。 @@ -1138,13 +1085,13 @@ pub unsafe extern "C" fn voicevox_user_dict_add_word( word: *const VoicevoxUserDictWord, output_word_uuid: NonNull<[u8; 16]>, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let word = word.read_unaligned().try_into_word()?; let uuid = user_dict.dict.add_word(word)?; output_word_uuid.as_ptr().copy_from(uuid.as_bytes(), 16); Ok(()) - })()) + }) } /// ユーザー辞書の単語を更新する。 @@ -1165,13 +1112,13 @@ pub unsafe extern "C" fn voicevox_user_dict_update_word( word_uuid: &[u8; 16], word: *const VoicevoxUserDictWord, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; let word = word.read_unaligned().try_into_word()?; user_dict.dict.update_word(word_uuid, word)?; Ok(()) - })()) + }) } /// ユーザー辞書から単語を削除する。 @@ -1189,11 +1136,11 @@ pub extern "C" fn voicevox_user_dict_remove_word( user_dict: &VoicevoxUserDict, word_uuid: &[u8; 16], ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; user_dict.dict.remove_word(word_uuid)?; Ok(()) - })()) + }) } /// ユーザー辞書の単語をJSON形式で出力する。 @@ -1213,12 +1160,14 @@ pub unsafe extern "C" fn voicevox_user_dict_to_json( user_dict: &VoicevoxUserDict, output_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let json = user_dict.dict.to_json(); - let json = CString::new(json).expect("\\0を含まない文字列であることが保証されている"); - output_json - .as_ptr() - .write_unaligned(C_STRING_DROP_CHECKER.whitelist(json).into_raw()); - VoicevoxResultCode::VOICEVOX_RESULT_OK + run(|| { + let json = user_dict.dict.to_json(); + let json = CString::new(json).expect("\\0を含まない文字列であることが保証されている"); + output_json + .as_ptr() + .write_unaligned(C_STRING_DROP_CHECKER.whitelist(json).into_raw()); + Ok(()) + }) } /// 他のユーザー辞書をインポートする。 @@ -1235,10 +1184,10 @@ pub extern "C" fn voicevox_user_dict_import( user_dict: &VoicevoxUserDict, other_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { user_dict.dict.import(&other_dict.dict)?; Ok(()) - })()) + }) } /// ユーザー辞書をファイルに保存する。 @@ -1255,11 +1204,11 @@ pub unsafe extern "C" fn voicevox_user_dict_save( user_dict: &VoicevoxUserDict, path: *const c_char, ) -> VoicevoxResultCode { - into_result_code_with_error((|| { + run(|| { let path = ensure_utf8(CStr::from_ptr(path))?; - RUNTIME.block_on(user_dict.dict.save(path))?; + user_dict.dict.save(path)?; Ok(()) - })()) + }) } /// ユーザー辞書を破棄(_destruct_)する。 @@ -1271,5 +1220,5 @@ pub unsafe extern "C" fn voicevox_user_dict_save( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_user_dict_delete(user_dict: Box) { - drop(user_dict); + run(|| drop(user_dict)); } From 7c0e94128f1edfd10853c02e90663a0d03ee4df8 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 15:22:49 +0900 Subject: [PATCH 2/9] =?UTF-8?q?`init=5Flogger`=E3=82=92=E6=98=8E=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=E3=81=AB=E5=91=BC=E3=81=B6=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/compatible_engine.rs | 232 +++++++++-------- crates/voicevox_core_c_api/src/helpers.rs | 161 ++++-------- crates/voicevox_core_c_api/src/lib.rs | 236 ++++++++++++------ 3 files changed, 312 insertions(+), 317 deletions(-) diff --git a/crates/voicevox_core_c_api/src/compatible_engine.rs b/crates/voicevox_core_c_api/src/compatible_engine.rs index 4a24e0e1e..a3f2c615d 100644 --- a/crates/voicevox_core_c_api/src/compatible_engine.rs +++ b/crates/voicevox_core_c_api/src/compatible_engine.rs @@ -100,93 +100,92 @@ fn set_message(message: &str) { #[no_mangle] pub extern "C" fn initialize(use_gpu: bool, cpu_num_threads: c_int, load_all_models: bool) -> bool { - run(|| { - let result = (|| { - let synthesizer = voicevox_core::blocking::Synthesizer::new( - (), - &voicevox_core::InitializeOptions { - acceleration_mode: if use_gpu { - voicevox_core::AccelerationMode::Gpu - } else { - voicevox_core::AccelerationMode::Cpu - }, - cpu_num_threads: cpu_num_threads as u16, + let _ = init_logger(); + let result = (|| { + let synthesizer = voicevox_core::blocking::Synthesizer::new( + (), + &voicevox_core::InitializeOptions { + acceleration_mode: if use_gpu { + voicevox_core::AccelerationMode::Gpu + } else { + voicevox_core::AccelerationMode::Cpu }, - )?; + cpu_num_threads: cpu_num_threads as u16, + }, + )?; - if load_all_models { - for model in &voice_model_set().all_vvms { - synthesizer.load_voice_model(model)?; - } + if load_all_models { + for model in &voice_model_set().all_vvms { + synthesizer.load_voice_model(model)?; } + } - Ok::<_, voicevox_core::Error>(synthesizer) - })(); + Ok::<_, voicevox_core::Error>(synthesizer) + })(); - match result { - Ok(synthesizer) => { - *lock_synthesizer() = Some(synthesizer); - true - } - Err(err) => { - set_message(&format!("{err}")); - false - } + match result { + Ok(synthesizer) => { + *lock_synthesizer() = Some(synthesizer); + true } - }) + Err(err) => { + set_message(&format!("{err}")); + false + } + } } #[no_mangle] pub extern "C" fn load_model(style_id: i64) -> bool { - run(|| { - let style_id = StyleId::new(style_id as u32); - let model_set = voice_model_set(); - if let Some(model_id) = model_set.style_model_map.get(&style_id) { - let vvm = model_set.model_map.get(model_id).unwrap(); - let synthesizer = &mut *lock_synthesizer(); - let result = ensure_initialized!(synthesizer).load_voice_model(vvm); - if let Some(err) = result.err() { - set_message(&format!("{err}")); - false - } else { - true - } - } else { - set_message(&format!("{}は無効なStyle IDです", style_id)); + let _ = init_logger(); + let style_id = StyleId::new(style_id as u32); + let model_set = voice_model_set(); + if let Some(model_id) = model_set.style_model_map.get(&style_id) { + let vvm = model_set.model_map.get(model_id).unwrap(); + let synthesizer = &mut *lock_synthesizer(); + let result = ensure_initialized!(synthesizer).load_voice_model(vvm); + if let Some(err) = result.err() { + set_message(&format!("{err}")); false + } else { + true } - }) + } else { + set_message(&format!("{}は無効なStyle IDです", style_id)); + false + } } #[no_mangle] pub extern "C" fn is_model_loaded(speaker_id: i64) -> bool { - run(|| { - ensure_initialized!(&*lock_synthesizer()) - .is_loaded_model_by_style_id(StyleId::new(speaker_id as u32)) - }) + let _ = init_logger(); + ensure_initialized!(&*lock_synthesizer()) + .is_loaded_model_by_style_id(StyleId::new(speaker_id as u32)) } #[no_mangle] pub extern "C" fn finalize() { - run(|| *lock_synthesizer() = None); + let _ = init_logger(); + *lock_synthesizer() = None; } #[no_mangle] pub extern "C" fn metas() -> *const c_char { - run(|| { - let model_set = voice_model_set(); - model_set.all_metas_json.as_ptr() - }) + let _ = init_logger(); + let model_set = voice_model_set(); + model_set.all_metas_json.as_ptr() } #[no_mangle] pub extern "C" fn last_error_message() -> *const c_char { - run(|| ERROR_MESSAGE.lock().unwrap().as_ptr() as *const c_char) + let _ = init_logger(); + ERROR_MESSAGE.lock().unwrap().as_ptr() as *const c_char } #[no_mangle] pub extern "C" fn supported_devices() -> *const c_char { - return run(|| SUPPORTED_DEVICES.as_ptr()); + let _ = init_logger(); + return SUPPORTED_DEVICES.as_ptr(); static SUPPORTED_DEVICES: Lazy = Lazy::new(|| { CString::new(SupportedDevices::create().unwrap().to_json().to_string()).unwrap() @@ -200,25 +199,23 @@ pub extern "C" fn yukarin_s_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - run(|| { - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).predict_duration( - unsafe { std::slice::from_raw_parts_mut(phoneme_list, length as usize) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = - unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false - } + let _ = init_logger(); + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).predict_duration( + unsafe { std::slice::from_raw_parts_mut(phoneme_list, length as usize) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; + output_slice.clone_from_slice(&output_vec); + true } - }) + Err(err) => { + set_message(&format!("{err}")); + false + } + } } #[no_mangle] @@ -233,31 +230,29 @@ pub extern "C" fn yukarin_sa_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - run(|| { - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).predict_intonation( - length as usize, - unsafe { std::slice::from_raw_parts(vowel_phoneme_list, length as usize) }, - unsafe { std::slice::from_raw_parts(consonant_phoneme_list, length as usize) }, - unsafe { std::slice::from_raw_parts(start_accent_list, length as usize) }, - unsafe { std::slice::from_raw_parts(end_accent_list, length as usize) }, - unsafe { std::slice::from_raw_parts(start_accent_phrase_list, length as usize) }, - unsafe { std::slice::from_raw_parts(end_accent_phrase_list, length as usize) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = - unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false - } + let _ = init_logger(); + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).predict_intonation( + length as usize, + unsafe { std::slice::from_raw_parts(vowel_phoneme_list, length as usize) }, + unsafe { std::slice::from_raw_parts(consonant_phoneme_list, length as usize) }, + unsafe { std::slice::from_raw_parts(start_accent_list, length as usize) }, + unsafe { std::slice::from_raw_parts(end_accent_list, length as usize) }, + unsafe { std::slice::from_raw_parts(start_accent_phrase_list, length as usize) }, + unsafe { std::slice::from_raw_parts(end_accent_phrase_list, length as usize) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length as usize) }; + output_slice.clone_from_slice(&output_vec); + true + } + Err(err) => { + set_message(&format!("{err}")); + false } - }) + } } #[no_mangle] @@ -269,27 +264,26 @@ pub extern "C" fn decode_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - run(|| { - let length = length as usize; - let phoneme_size = phoneme_size as usize; - let synthesizer = &*lock_synthesizer(); - let result = ensure_initialized!(synthesizer).decode( - length, - phoneme_size, - unsafe { std::slice::from_raw_parts(f0, length) }, - unsafe { std::slice::from_raw_parts(phoneme, phoneme_size * length) }, - StyleId::new(unsafe { *speaker_id as u32 }), - ); - match result { - Ok(output_vec) => { - let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length * 256) }; - output_slice.clone_from_slice(&output_vec); - true - } - Err(err) => { - set_message(&format!("{err}")); - false - } + let _ = init_logger(); + let length = length as usize; + let phoneme_size = phoneme_size as usize; + let synthesizer = &*lock_synthesizer(); + let result = ensure_initialized!(synthesizer).decode( + length, + phoneme_size, + unsafe { std::slice::from_raw_parts(f0, length) }, + unsafe { std::slice::from_raw_parts(phoneme, phoneme_size * length) }, + StyleId::new(unsafe { *speaker_id as u32 }), + ); + match result { + Ok(output_vec) => { + let output_slice = unsafe { std::slice::from_raw_parts_mut(output, length * 256) }; + output_slice.clone_from_slice(&output_vec); + true } - }) + Err(err) => { + set_message(&format!("{err}")); + false + } + } } diff --git a/crates/voicevox_core_c_api/src/helpers.rs b/crates/voicevox_core_c_api/src/helpers.rs index f66710752..698e89b45 100644 --- a/crates/voicevox_core_c_api/src/helpers.rs +++ b/crates/voicevox_core_c_api/src/helpers.rs @@ -1,128 +1,57 @@ use std::{error::Error as _, fmt::Debug, iter}; use voicevox_core::UserDictWord; -use duplicate::duplicate_item; use thiserror::Error; use tracing::error; use super::*; use voicevox_core::AccentPhraseModel; -pub(crate) fn run O, O: Outcome>(f: F) -> O::Output { - let _ = init_logger(); - return f().convert_with_error(); - - fn init_logger() -> std::result::Result<(), impl Sized> { - let ansi = { - // anstyle系のクレートを利用して次の2つを行う。 - // - // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) - // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 - - assert_eq!( - ColorChoice::Auto, - ColorChoice::global(), - "`ColorChoice::write_global` should not have been called", - ); - - AutoStream::choice(&out()) != ColorChoice::Never - && anstyle_query::term_supports_ansi_color() - && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) - }; - - tracing_subscriber::fmt() - .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { - EnvFilter::from_default_env() - } else { - "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() - }) - .with_timer(local_time as fn(&mut Writer<'_>) -> _) - .with_ansi(ansi) - .with_writer(out) - .try_init() - } - - fn local_time(wtr: &mut Writer<'_>) -> fmt::Result { - // ローカル時刻で表示はするが、そのフォーマットはtracing-subscriber本来のものに近いようにする。 - // https://github.com/tokio-rs/tracing/blob/tracing-subscriber-0.3.16/tracing-subscriber/src/fmt/time/datetime.rs#L235-L241 - wtr.write_str(&chrono::Local::now().to_rfc3339_opts(SecondsFormat::Micros, false)) - } - - fn out() -> impl RawStream { - io::stderr() - } -} - -pub(crate) trait Outcome: Sized { - type Output; - fn convert_with_error(self) -> Self::Output; -} - -#[duplicate_item( - impl_generics T; - [] [ () ]; - [] [ bool ]; - [] [ *const c_char ]; - [] [ *mut c_char ]; - [ T ] [ Box ]; -)] -impl Outcome for T { - type Output = Self; - - fn convert_with_error(self) -> Self::Output { - self - } -} - -impl Outcome for CApiResult<()> { - type Output = VoicevoxResultCode; - - fn convert_with_error(self) -> Self::Output { - if let Err(err) = &self { - display_error(err); - } - return into_result_code(self); - - fn display_error(err: &CApiError) { - itertools::chain( - [err.to_string()], - iter::successors(err.source(), |&e| e.source()).map(|e| format!("Caused by: {e}")), - ) - .for_each(|msg| error!("{msg}")); - } - - fn into_result_code(this: CApiResult<()>) -> VoicevoxResultCode { - use voicevox_core::ErrorKind::*; - use CApiError::*; - use VoicevoxResultCode::*; - - match this { - Ok(()) => VOICEVOX_RESULT_OK, - Err(RustApi(err)) => match err.kind() { - NotLoadedOpenjtalkDict => VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR, - GpuSupport => VOICEVOX_RESULT_GPU_SUPPORT_ERROR, - OpenZipFile => VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, - ReadZipEntry => VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, - ModelAlreadyLoaded => VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, - StyleAlreadyLoaded => VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, - InvalidModelData => VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, - GetSupportedDevices => VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR, - StyleNotFound => VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR, - ModelNotFound => VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR, - InferenceFailed => VOICEVOX_RESULT_INFERENCE_ERROR, - ExtractFullContextLabel => VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR, - ParseKana => VOICEVOX_RESULT_PARSE_KANA_ERROR, - LoadUserDict => VOICEVOX_RESULT_LOAD_USER_DICT_ERROR, - SaveUserDict => VOICEVOX_RESULT_SAVE_USER_DICT_ERROR, - WordNotFound => VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR, - UseUserDict => VOICEVOX_RESULT_USE_USER_DICT_ERROR, - InvalidWord => VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR, - }, - Err(InvalidUtf8Input) => VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR, - Err(InvalidAudioQuery(_)) => VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR, - Err(InvalidAccentPhrase(_)) => VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR, - Err(InvalidUuid(_)) => VOICEVOX_RESULT_INVALID_UUID_ERROR, - } +pub(crate) fn into_result_code_with_error(result: CApiResult<()>) -> VoicevoxResultCode { + if let Err(err) = &result { + display_error(err); + } + return into_result_code(result); + + fn display_error(err: &CApiError) { + itertools::chain( + [err.to_string()], + iter::successors(err.source(), |&e| e.source()).map(|e| format!("Caused by: {e}")), + ) + .for_each(|msg| error!("{msg}")); + } + + fn into_result_code(result: CApiResult<()>) -> VoicevoxResultCode { + use voicevox_core::ErrorKind::*; + use CApiError::*; + use VoicevoxResultCode::*; + + match result { + Ok(()) => VOICEVOX_RESULT_OK, + Err(RustApi(err)) => match err.kind() { + NotLoadedOpenjtalkDict => VOICEVOX_RESULT_NOT_LOADED_OPENJTALK_DICT_ERROR, + GpuSupport => VOICEVOX_RESULT_GPU_SUPPORT_ERROR, + OpenZipFile => VOICEVOX_RESULT_OPEN_ZIP_FILE_ERROR, + ReadZipEntry => VOICEVOX_RESULT_READ_ZIP_ENTRY_ERROR, + ModelAlreadyLoaded => VOICEVOX_RESULT_MODEL_ALREADY_LOADED_ERROR, + StyleAlreadyLoaded => VOICEVOX_RESULT_STYLE_ALREADY_LOADED_ERROR, + InvalidModelData => VOICEVOX_RESULT_INVALID_MODEL_DATA_ERROR, + GetSupportedDevices => VOICEVOX_RESULT_GET_SUPPORTED_DEVICES_ERROR, + StyleNotFound => VOICEVOX_RESULT_STYLE_NOT_FOUND_ERROR, + ModelNotFound => VOICEVOX_RESULT_MODEL_NOT_FOUND_ERROR, + InferenceFailed => VOICEVOX_RESULT_INFERENCE_ERROR, + ExtractFullContextLabel => VOICEVOX_RESULT_EXTRACT_FULL_CONTEXT_LABEL_ERROR, + ParseKana => VOICEVOX_RESULT_PARSE_KANA_ERROR, + LoadUserDict => VOICEVOX_RESULT_LOAD_USER_DICT_ERROR, + SaveUserDict => VOICEVOX_RESULT_SAVE_USER_DICT_ERROR, + WordNotFound => VOICEVOX_RESULT_USER_DICT_WORD_NOT_FOUND_ERROR, + UseUserDict => VOICEVOX_RESULT_USE_USER_DICT_ERROR, + InvalidWord => VOICEVOX_RESULT_INVALID_USER_DICT_WORD_ERROR, + }, + Err(InvalidUtf8Input) => VOICEVOX_RESULT_INVALID_UTF8_INPUT_ERROR, + Err(InvalidAudioQuery(_)) => VOICEVOX_RESULT_INVALID_AUDIO_QUERY_ERROR, + Err(InvalidAccentPhrase(_)) => VOICEVOX_RESULT_INVALID_ACCENT_PHRASE_ERROR, + Err(InvalidUuid(_)) => VOICEVOX_RESULT_INVALID_UUID_ERROR, } } } diff --git a/crates/voicevox_core_c_api/src/lib.rs b/crates/voicevox_core_c_api/src/lib.rs index 5f274f15b..c80494012 100644 --- a/crates/voicevox_core_c_api/src/lib.rs +++ b/crates/voicevox_core_c_api/src/lib.rs @@ -31,6 +31,46 @@ use uuid::Uuid; use voicevox_core::{AccentPhraseModel, AudioQueryModel, TtsOptions, UserDictWord, VoiceModelId}; use voicevox_core::{StyleId, SupportedDevices, SynthesisOptions}; +fn init_logger() -> std::result::Result<(), impl Sized> { + let ansi = { + // anstyle系のクレートを利用して次の2つを行う。 + // + // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) + // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 + + assert_eq!( + ColorChoice::Auto, + ColorChoice::global(), + "`ColorChoice::write_global` should not have been called", + ); + + AutoStream::choice(&out()) != ColorChoice::Never + && anstyle_query::term_supports_ansi_color() + && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) + }; + + return tracing_subscriber::fmt() + .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { + EnvFilter::from_default_env() + } else { + "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() + }) + .with_timer(local_time as fn(&mut Writer<'_>) -> _) + .with_ansi(ansi) + .with_writer(out) + .try_init(); + + fn local_time(wtr: &mut Writer<'_>) -> fmt::Result { + // ローカル時刻で表示はするが、そのフォーマットはtracing-subscriber本来のものに近いようにする。 + // https://github.com/tokio-rs/tracing/blob/tracing-subscriber-0.3.16/tracing-subscriber/src/fmt/time/datetime.rs#L235-L241 + wtr.write_str(&chrono::Local::now().to_rfc3339_opts(SecondsFormat::Micros, false)) + } + + fn out() -> impl RawStream { + io::stderr() + } +} + /* * Cの関数として公開するための型や関数を定義するこれらの実装はvoicevox_core/publish.rsに定義してある対応する関数にある * この関数ではvoicevox_core/publish.rsにある対応する関数の呼び出しと、その戻り値をCの形式に変換する処理のみとする @@ -82,12 +122,13 @@ pub unsafe extern "C" fn voicevox_open_jtalk_rc_new( open_jtalk_dic_dir: *const c_char, out_open_jtalk: NonNull>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let open_jtalk_dic_dir = ensure_utf8(CStr::from_ptr(open_jtalk_dic_dir))?; let open_jtalk = OpenJtalkRc::new(open_jtalk_dic_dir)?.into(); out_open_jtalk.as_ptr().write_unaligned(open_jtalk); Ok(()) - }) + })()) } /// OpenJtalkの使うユーザー辞書を設定する。 @@ -106,10 +147,11 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( open_jtalk: &OpenJtalkRc, user_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { open_jtalk.open_jtalk.use_user_dict(&user_dict.dict)?; Ok(()) - }) + })()) } /// ::OpenJtalkRc を破棄(_destruct_)する。 @@ -128,7 +170,8 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( /// } #[no_mangle] pub extern "C" fn voicevox_open_jtalk_rc_delete(open_jtalk: Box) { - run(|| drop(open_jtalk)); + let _ = init_logger(); + drop(open_jtalk); } /// ハードウェアアクセラレーションモードを設定する設定値。 @@ -158,7 +201,7 @@ pub struct VoicevoxInitializeOptions { /// @return デフォルト値が設定された初期化オプション #[no_mangle] pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitializeOptions { - // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し + let _ = init_logger(); VoicevoxInitializeOptions::default() } @@ -166,7 +209,8 @@ pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitiali /// @return SemVerでフォーマットされたバージョン。 #[no_mangle] pub extern "C" fn voicevox_get_version() -> *const c_char { - return run(|| C_STRING_DROP_CHECKER.blacklist(VERSION).as_ptr()); + let _ = init_logger(); + return C_STRING_DROP_CHECKER.blacklist(VERSION).as_ptr(); const VERSION: &CStr = unsafe { // SAFETY: The package version is a SemVer, so it should not contain '\0' @@ -209,12 +253,13 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( path: *const c_char, out_model: NonNull>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let path = ensure_utf8(CStr::from_ptr(path))?; let model = VoicevoxVoiceModel::from_path(path)?.into(); out_model.as_ptr().write_unaligned(model); Ok(()) - }) + })()) } /// ::VoicevoxVoiceModel からIDを取得する。 @@ -228,7 +273,8 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> VoicevoxVoiceModelId { - run(|| model.id().as_ptr()) + let _ = init_logger(); + model.id().as_ptr() } /// ::VoicevoxVoiceModel からメタ情報を取得する。 @@ -243,7 +289,8 @@ pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> Voicevo /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel) -> *const c_char { - run(|| model.metas().as_ptr()) + let _ = init_logger(); + model.metas().as_ptr() } /// ::VoicevoxVoiceModel を破棄(_destruct_)する。 @@ -256,7 +303,8 @@ pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_delete(model: Box) { - run(|| drop(model)); + let _ = init_logger(); + drop(model); } /// 音声シンセサイザ。 @@ -285,13 +333,14 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( options: VoicevoxInitializeOptions, out_synthesizer: NonNull>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let options = options.into(); let synthesizer = VoicevoxSynthesizer::new(open_jtalk, &options)?.into(); out_synthesizer.as_ptr().write_unaligned(synthesizer); Ok(()) - }) + })()) } /// ::VoicevoxSynthesizer を破棄(_destruct_)する。 @@ -304,7 +353,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_delete(synthesizer: Box) { - run(|| drop(synthesizer)); + let _ = init_logger(); + drop(synthesizer); } /// 音声モデルを読み込む。 @@ -323,7 +373,8 @@ pub extern "C" fn voicevox_synthesizer_load_voice_model( synthesizer: &VoicevoxSynthesizer, model: &VoicevoxVoiceModel, ) -> VoicevoxResultCode { - run(|| synthesizer.load_voice_model(model.model())) + let _ = init_logger(); + into_result_code_with_error(synthesizer.load_voice_model(model.model())) } /// 音声モデルの読み込みを解除する。 @@ -342,12 +393,13 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) })?; synthesizer .unload_voice_model(&VoiceModelId::new(raw_model_id.to_string())) .map_err(Into::into) - }) + })()) } /// ハードウェアアクセラレーションがGPUモードか判定する。 @@ -361,7 +413,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_is_gpu_mode(synthesizer: &VoicevoxSynthesizer) -> bool { - run(|| synthesizer.synthesizer().is_gpu_mode()) + let _ = init_logger(); + synthesizer.synthesizer().is_gpu_mode() } /// 指定したIDの音声モデルが読み込まれているか判定する。 @@ -380,12 +433,12 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> bool { - run(|| { - let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) }).unwrap(); - synthesizer - .synthesizer() - .is_loaded_voice_model(&VoiceModelId::new(raw_model_id.into())) - }) + let _ = init_logger(); + // FIXME: 不正なUTF-8文字列に対し、正式なエラーとするか黙って`false`を返す + let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) }).unwrap(); + synthesizer + .synthesizer() + .is_loaded_voice_model(&VoiceModelId::new(raw_model_id.into())) } /// 今読み込んでいる音声モデルのメタ情報を、JSONで取得する。 @@ -403,10 +456,9 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( pub extern "C" fn voicevox_synthesizer_create_metas_json( synthesizer: &VoicevoxSynthesizer, ) -> *mut c_char { - run(|| { - let metas = synthesizer.metas(); - C_STRING_DROP_CHECKER.whitelist(metas).into_raw() - }) + let _ = init_logger(); + let metas = synthesizer.metas(); + C_STRING_DROP_CHECKER.whitelist(metas).into_raw() } /// このライブラリで利用可能なデバイスの情報を、JSONで取得する。 @@ -433,7 +485,8 @@ pub extern "C" fn voicevox_synthesizer_create_metas_json( pub unsafe extern "C" fn voicevox_create_supported_devices_json( output_supported_devices_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let supported_devices = CString::new(SupportedDevices::create()?.to_json().to_string()).unwrap(); output_supported_devices_json.as_ptr().write_unaligned( @@ -442,7 +495,7 @@ pub unsafe extern "C" fn voicevox_create_supported_devices_json( .into_raw(), ); Ok(()) - }) + })()) } /// AquesTalk風記法から、AudioQueryをJSONとして生成する。 @@ -477,7 +530,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query_from_kana( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let kana = CStr::from_ptr(kana); let kana = ensure_utf8(kana)?; @@ -490,7 +544,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query_from_kana( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw()); Ok(()) - }) + })()) } /// 日本語テキストから、AudioQueryをJSONとして生成する。 @@ -525,7 +579,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let text = CStr::from_ptr(text); let text = ensure_utf8(text)?; @@ -538,7 +593,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw()); Ok(()) - }) + })()) } /// AquesTalk風記法から、AccentPhrase (アクセント句)の配列をJSON形式で生成する。 @@ -574,7 +629,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases_from_kana( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; let accent_phrases = synthesizer .synthesizer() @@ -585,7 +641,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases_from_kana( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - }) + })()) } /// 日本語テキストから、AccentPhrase (アクセント句)の配列をJSON形式で生成する。 @@ -620,7 +676,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let text = ensure_utf8(CStr::from_ptr(text))?; let accent_phrases = synthesizer .synthesizer() @@ -631,7 +688,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - }) + })()) } /// AccentPhraseの配列の音高・音素長を、特定の声で生成しなおす。 @@ -657,7 +714,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; @@ -670,7 +728,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - }) + })()) } /// AccentPhraseの配列の音素長を、特定の声で生成しなおす。 @@ -696,7 +754,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; @@ -709,7 +768,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - }) + })()) } /// AccentPhraseの配列の音高を、特定の声で生成しなおす。 @@ -735,7 +794,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) .map_err(CApiError::InvalidAccentPhrase)?; @@ -748,7 +808,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch( .as_ptr() .write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw()); Ok(()) - }) + })()) } /// ::voicevox_synthesizer_synthesis のオプション。 @@ -762,7 +822,7 @@ pub struct VoicevoxSynthesisOptions { /// @return デフォルト値が設定された `voicevox_synthesizer_synthesis` のオプション #[no_mangle] pub extern "C" fn voicevox_make_default_synthesis_options() -> VoicevoxSynthesisOptions { - // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し + let _ = init_logger(); VoicevoxSynthesisOptions::default() } @@ -794,7 +854,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_synthesis( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let audio_query_json = CStr::from_ptr(audio_query_json) .to_str() .map_err(|_| CApiError::InvalidUtf8Input)?; @@ -807,7 +868,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_synthesis( )?; U8_SLICE_OWNER.own_and_lend(wav, output_wav, output_wav_length); Ok(()) - }) + })()) } /// ::voicevox_synthesizer_tts のオプション。 @@ -821,7 +882,7 @@ pub struct VoicevoxTtsOptions { /// @return テキスト音声合成オプション #[no_mangle] pub extern "C" fn voicevox_make_default_tts_options() -> VoicevoxTtsOptions { - // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し + let _ = init_logger(); voicevox_core::TtsOptions::default().into() } @@ -853,7 +914,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts_from_kana( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; let output = synthesizer.synthesizer().tts_from_kana( kana, @@ -862,7 +924,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts_from_kana( )?; U8_SLICE_OWNER.own_and_lend(output, output_wav, output_wav_length); Ok(()) - }) + })()) } /// 日本語テキストから音声合成を行う。 @@ -893,7 +955,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let text = ensure_utf8(CStr::from_ptr(text))?; let output = synthesizer.synthesizer().tts( text, @@ -902,7 +965,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( )?; U8_SLICE_OWNER.own_and_lend(output, output_wav, output_wav_length); Ok(()) - }) + })()) } /// JSON文字列を解放する。 @@ -925,7 +988,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { - run(|| drop(CString::from_raw(C_STRING_DROP_CHECKER.check(json)))); + let _ = init_logger(); + drop(CString::from_raw(C_STRING_DROP_CHECKER.check(json))); } /// WAVデータを解放する。 @@ -941,7 +1005,8 @@ pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { /// } #[no_mangle] pub extern "C" fn voicevox_wav_free(wav: *mut u8) { - run(|| U8_SLICE_OWNER.drop_for(wav)); + let _ = init_logger(); + U8_SLICE_OWNER.drop_for(wav); } /// 結果コードに対応したメッセージ文字列を取得する。 @@ -968,10 +1033,9 @@ pub extern "C" fn voicevox_wav_free(wav: *mut u8) { pub extern "C" fn voicevox_error_result_to_message( result_code: VoicevoxResultCode, ) -> *const c_char { - run(|| { - let message = result_code::error_result_to_message(result_code); - C_STRING_DROP_CHECKER.blacklist(message).as_ptr() - }) + let _ = init_logger(); + let message = result_code::error_result_to_message(result_code); + C_STRING_DROP_CHECKER.blacklist(message).as_ptr() } /// ユーザー辞書。 @@ -1023,7 +1087,7 @@ pub extern "C" fn voicevox_user_dict_word_make( surface: *const c_char, pronunciation: *const c_char, ) -> VoicevoxUserDictWord { - // その気になればconst化できるほどの処理であり、ロガーの起動は必要無し + let _ = init_logger(); VoicevoxUserDictWord { surface, pronunciation, @@ -1038,7 +1102,8 @@ pub extern "C" fn voicevox_user_dict_word_make( /// @returns ::VoicevoxUserDict #[no_mangle] pub extern "C" fn voicevox_user_dict_new() -> Box { - run(Box::::default) + let _ = init_logger(); + Default::default() } /// ユーザー辞書にファイルを読み込ませる。 @@ -1056,12 +1121,13 @@ pub unsafe extern "C" fn voicevox_user_dict_load( user_dict: &VoicevoxUserDict, dict_path: *const c_char, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let dict_path = ensure_utf8(unsafe { CStr::from_ptr(dict_path) })?; user_dict.dict.load(dict_path)?; Ok(()) - }) + })()) } /// ユーザー辞書に単語を追加する。 @@ -1085,13 +1151,14 @@ pub unsafe extern "C" fn voicevox_user_dict_add_word( word: *const VoicevoxUserDictWord, output_word_uuid: NonNull<[u8; 16]>, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let word = word.read_unaligned().try_into_word()?; let uuid = user_dict.dict.add_word(word)?; output_word_uuid.as_ptr().copy_from(uuid.as_bytes(), 16); Ok(()) - }) + })()) } /// ユーザー辞書の単語を更新する。 @@ -1112,13 +1179,14 @@ pub unsafe extern "C" fn voicevox_user_dict_update_word( word_uuid: &[u8; 16], word: *const VoicevoxUserDictWord, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; let word = word.read_unaligned().try_into_word()?; user_dict.dict.update_word(word_uuid, word)?; Ok(()) - }) + })()) } /// ユーザー辞書から単語を削除する。 @@ -1136,13 +1204,15 @@ pub extern "C" fn voicevox_user_dict_remove_word( user_dict: &VoicevoxUserDict, word_uuid: &[u8; 16], ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; user_dict.dict.remove_word(word_uuid)?; Ok(()) - }) + })()) } +// FIXME: infallibleなので、`char*`を戻り値にしてもよいはず /// ユーザー辞書の単語をJSON形式で出力する。 /// /// 生成したJSON文字列を解放するには ::voicevox_json_free を使う。 @@ -1160,14 +1230,13 @@ pub unsafe extern "C" fn voicevox_user_dict_to_json( user_dict: &VoicevoxUserDict, output_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - run(|| { - let json = user_dict.dict.to_json(); - let json = CString::new(json).expect("\\0を含まない文字列であることが保証されている"); - output_json - .as_ptr() - .write_unaligned(C_STRING_DROP_CHECKER.whitelist(json).into_raw()); - Ok(()) - }) + let _ = init_logger(); + let json = user_dict.dict.to_json(); + let json = CString::new(json).expect("\\0を含まない文字列であることが保証されている"); + output_json + .as_ptr() + .write_unaligned(C_STRING_DROP_CHECKER.whitelist(json).into_raw()); + VoicevoxResultCode::VOICEVOX_RESULT_OK } /// 他のユーザー辞書をインポートする。 @@ -1184,10 +1253,11 @@ pub extern "C" fn voicevox_user_dict_import( user_dict: &VoicevoxUserDict, other_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { user_dict.dict.import(&other_dict.dict)?; Ok(()) - }) + })()) } /// ユーザー辞書をファイルに保存する。 @@ -1204,11 +1274,12 @@ pub unsafe extern "C" fn voicevox_user_dict_save( user_dict: &VoicevoxUserDict, path: *const c_char, ) -> VoicevoxResultCode { - run(|| { + let _ = init_logger(); + into_result_code_with_error((|| { let path = ensure_utf8(CStr::from_ptr(path))?; user_dict.dict.save(path)?; Ok(()) - }) + })()) } /// ユーザー辞書を破棄(_destruct_)する。 @@ -1220,5 +1291,6 @@ pub unsafe extern "C" fn voicevox_user_dict_save( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_user_dict_delete(user_dict: Box) { - run(|| drop(user_dict)); + let _ = init_logger(); + drop(user_dict); } From e5873b826e412976d93eb2b44c020a221c90abe6 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 15:41:02 +0900 Subject: [PATCH 3/9] =?UTF-8?q?`init=5Flogger`=20=E2=86=92=20`init=5Flogge?= =?UTF-8?q?r=5Fonce`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/compatible_engine.rs | 20 +-- crates/voicevox_core_c_api/src/lib.rs | 147 +++++++++--------- 2 files changed, 86 insertions(+), 81 deletions(-) diff --git a/crates/voicevox_core_c_api/src/compatible_engine.rs b/crates/voicevox_core_c_api/src/compatible_engine.rs index a3f2c615d..2dcccbeb7 100644 --- a/crates/voicevox_core_c_api/src/compatible_engine.rs +++ b/crates/voicevox_core_c_api/src/compatible_engine.rs @@ -100,7 +100,7 @@ fn set_message(message: &str) { #[no_mangle] pub extern "C" fn initialize(use_gpu: bool, cpu_num_threads: c_int, load_all_models: bool) -> bool { - let _ = init_logger(); + init_logger_once(); let result = (|| { let synthesizer = voicevox_core::blocking::Synthesizer::new( (), @@ -137,7 +137,7 @@ pub extern "C" fn initialize(use_gpu: bool, cpu_num_threads: c_int, load_all_mod #[no_mangle] pub extern "C" fn load_model(style_id: i64) -> bool { - let _ = init_logger(); + init_logger_once(); let style_id = StyleId::new(style_id as u32); let model_set = voice_model_set(); if let Some(model_id) = model_set.style_model_map.get(&style_id) { @@ -158,33 +158,33 @@ pub extern "C" fn load_model(style_id: i64) -> bool { #[no_mangle] pub extern "C" fn is_model_loaded(speaker_id: i64) -> bool { - let _ = init_logger(); + init_logger_once(); ensure_initialized!(&*lock_synthesizer()) .is_loaded_model_by_style_id(StyleId::new(speaker_id as u32)) } #[no_mangle] pub extern "C" fn finalize() { - let _ = init_logger(); + init_logger_once(); *lock_synthesizer() = None; } #[no_mangle] pub extern "C" fn metas() -> *const c_char { - let _ = init_logger(); + init_logger_once(); let model_set = voice_model_set(); model_set.all_metas_json.as_ptr() } #[no_mangle] pub extern "C" fn last_error_message() -> *const c_char { - let _ = init_logger(); + init_logger_once(); ERROR_MESSAGE.lock().unwrap().as_ptr() as *const c_char } #[no_mangle] pub extern "C" fn supported_devices() -> *const c_char { - let _ = init_logger(); + init_logger_once(); return SUPPORTED_DEVICES.as_ptr(); static SUPPORTED_DEVICES: Lazy = Lazy::new(|| { @@ -199,7 +199,7 @@ pub extern "C" fn yukarin_s_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let _ = init_logger(); + init_logger_once(); let synthesizer = &*lock_synthesizer(); let result = ensure_initialized!(synthesizer).predict_duration( unsafe { std::slice::from_raw_parts_mut(phoneme_list, length as usize) }, @@ -230,7 +230,7 @@ pub extern "C" fn yukarin_sa_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let _ = init_logger(); + init_logger_once(); let synthesizer = &*lock_synthesizer(); let result = ensure_initialized!(synthesizer).predict_intonation( length as usize, @@ -264,7 +264,7 @@ pub extern "C" fn decode_forward( speaker_id: *mut i64, output: *mut f32, ) -> bool { - let _ = init_logger(); + init_logger_once(); let length = length as usize; let phoneme_size = phoneme_size as usize; let synthesizer = &*lock_synthesizer(); diff --git a/crates/voicevox_core_c_api/src/lib.rs b/crates/voicevox_core_c_api/src/lib.rs index c80494012..7ceb84383 100644 --- a/crates/voicevox_core_c_api/src/lib.rs +++ b/crates/voicevox_core_c_api/src/lib.rs @@ -24,41 +24,46 @@ use std::fmt; use std::io; use std::os::raw::c_char; use std::ptr::NonNull; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex, MutexGuard, Once}; use tracing_subscriber::fmt::format::Writer; use tracing_subscriber::EnvFilter; use uuid::Uuid; use voicevox_core::{AccentPhraseModel, AudioQueryModel, TtsOptions, UserDictWord, VoiceModelId}; use voicevox_core::{StyleId, SupportedDevices, SynthesisOptions}; -fn init_logger() -> std::result::Result<(), impl Sized> { - let ansi = { - // anstyle系のクレートを利用して次の2つを行う。 - // - // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) - // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 - - assert_eq!( - ColorChoice::Auto, - ColorChoice::global(), - "`ColorChoice::write_global` should not have been called", - ); - - AutoStream::choice(&out()) != ColorChoice::Never - && anstyle_query::term_supports_ansi_color() - && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) - }; - - return tracing_subscriber::fmt() - .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { - EnvFilter::from_default_env() - } else { - "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() - }) - .with_timer(local_time as fn(&mut Writer<'_>) -> _) - .with_ansi(ansi) - .with_writer(out) - .try_init(); +fn init_logger_once() { + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + let ansi = { + // anstyle系のクレートを利用して次の2つを行う。 + // + // * ANSI escape codeを出してよいかの判定(環境変数のチェックとisatty) + // * 必要であれば`ENABLE_VIRTUAL_TERMINAL_PROCESSING`の有効化 + + assert_eq!( + ColorChoice::Auto, + ColorChoice::global(), + "`ColorChoice::write_global` should not have been called", + ); + + AutoStream::choice(&out()) != ColorChoice::Never + && anstyle_query::term_supports_ansi_color() + && anstyle_query::windows::enable_ansi_colors().unwrap_or(true) + }; + + // FIXME: `try_init` → `init` (subscriberは他に存在しないはずなので) + let _ = tracing_subscriber::fmt() + .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { + EnvFilter::from_default_env() + } else { + "error,voicevox_core=info,voicevox_core_c_api=info,onnxruntime=info".into() + }) + .with_timer(local_time as fn(&mut Writer<'_>) -> _) + .with_ansi(ansi) + .with_writer(out) + .try_init(); + }); fn local_time(wtr: &mut Writer<'_>) -> fmt::Result { // ローカル時刻で表示はするが、そのフォーマットはtracing-subscriber本来のものに近いようにする。 @@ -122,7 +127,7 @@ pub unsafe extern "C" fn voicevox_open_jtalk_rc_new( open_jtalk_dic_dir: *const c_char, out_open_jtalk: NonNull>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let open_jtalk_dic_dir = ensure_utf8(CStr::from_ptr(open_jtalk_dic_dir))?; let open_jtalk = OpenJtalkRc::new(open_jtalk_dic_dir)?.into(); @@ -147,7 +152,7 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( open_jtalk: &OpenJtalkRc, user_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { open_jtalk.open_jtalk.use_user_dict(&user_dict.dict)?; Ok(()) @@ -170,7 +175,7 @@ pub extern "C" fn voicevox_open_jtalk_rc_use_user_dict( /// } #[no_mangle] pub extern "C" fn voicevox_open_jtalk_rc_delete(open_jtalk: Box) { - let _ = init_logger(); + init_logger_once(); drop(open_jtalk); } @@ -201,7 +206,7 @@ pub struct VoicevoxInitializeOptions { /// @return デフォルト値が設定された初期化オプション #[no_mangle] pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitializeOptions { - let _ = init_logger(); + init_logger_once(); VoicevoxInitializeOptions::default() } @@ -209,7 +214,7 @@ pub extern "C" fn voicevox_make_default_initialize_options() -> VoicevoxInitiali /// @return SemVerでフォーマットされたバージョン。 #[no_mangle] pub extern "C" fn voicevox_get_version() -> *const c_char { - let _ = init_logger(); + init_logger_once(); return C_STRING_DROP_CHECKER.blacklist(VERSION).as_ptr(); const VERSION: &CStr = unsafe { @@ -253,7 +258,7 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( path: *const c_char, out_model: NonNull>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let path = ensure_utf8(CStr::from_ptr(path))?; let model = VoicevoxVoiceModel::from_path(path)?.into(); @@ -273,7 +278,7 @@ pub unsafe extern "C" fn voicevox_voice_model_new_from_path( /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> VoicevoxVoiceModelId { - let _ = init_logger(); + init_logger_once(); model.id().as_ptr() } @@ -289,7 +294,7 @@ pub extern "C" fn voicevox_voice_model_id(model: &VoicevoxVoiceModel) -> Voicevo /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel) -> *const c_char { - let _ = init_logger(); + init_logger_once(); model.metas().as_ptr() } @@ -303,7 +308,7 @@ pub extern "C" fn voicevox_voice_model_get_metas_json(model: &VoicevoxVoiceModel /// } #[no_mangle] pub extern "C" fn voicevox_voice_model_delete(model: Box) { - let _ = init_logger(); + init_logger_once(); drop(model); } @@ -333,7 +338,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( options: VoicevoxInitializeOptions, out_synthesizer: NonNull>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let options = options.into(); @@ -353,7 +358,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_new( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_delete(synthesizer: Box) { - let _ = init_logger(); + init_logger_once(); drop(synthesizer); } @@ -373,7 +378,7 @@ pub extern "C" fn voicevox_synthesizer_load_voice_model( synthesizer: &VoicevoxSynthesizer, model: &VoicevoxVoiceModel, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error(synthesizer.load_voice_model(model.model())) } @@ -393,7 +398,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) })?; synthesizer @@ -413,7 +418,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_unload_voice_model( /// } #[no_mangle] pub extern "C" fn voicevox_synthesizer_is_gpu_mode(synthesizer: &VoicevoxSynthesizer) -> bool { - let _ = init_logger(); + init_logger_once(); synthesizer.synthesizer().is_gpu_mode() } @@ -433,7 +438,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( synthesizer: &VoicevoxSynthesizer, model_id: VoicevoxVoiceModelId, ) -> bool { - let _ = init_logger(); + init_logger_once(); // FIXME: 不正なUTF-8文字列に対し、正式なエラーとするか黙って`false`を返す let raw_model_id = ensure_utf8(unsafe { CStr::from_ptr(model_id) }).unwrap(); synthesizer @@ -456,7 +461,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_is_loaded_voice_model( pub extern "C" fn voicevox_synthesizer_create_metas_json( synthesizer: &VoicevoxSynthesizer, ) -> *mut c_char { - let _ = init_logger(); + init_logger_once(); let metas = synthesizer.metas(); C_STRING_DROP_CHECKER.whitelist(metas).into_raw() } @@ -485,7 +490,7 @@ pub extern "C" fn voicevox_synthesizer_create_metas_json( pub unsafe extern "C" fn voicevox_create_supported_devices_json( output_supported_devices_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let supported_devices = CString::new(SupportedDevices::create()?.to_json().to_string()).unwrap(); @@ -530,7 +535,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query_from_kana( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let kana = CStr::from_ptr(kana); let kana = ensure_utf8(kana)?; @@ -579,7 +584,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_audio_query( style_id: VoicevoxStyleId, output_audio_query_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let text = CStr::from_ptr(text); let text = ensure_utf8(text)?; @@ -629,7 +634,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases_from_kana( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; let accent_phrases = synthesizer @@ -676,7 +681,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let text = ensure_utf8(CStr::from_ptr(text))?; let accent_phrases = synthesizer @@ -714,7 +719,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) @@ -754,7 +759,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) @@ -794,7 +799,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch( style_id: VoicevoxStyleId, output_accent_phrases_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let accent_phrases: Vec = serde_json::from_str(ensure_utf8(CStr::from_ptr(accent_phrases_json))?) @@ -822,7 +827,7 @@ pub struct VoicevoxSynthesisOptions { /// @return デフォルト値が設定された `voicevox_synthesizer_synthesis` のオプション #[no_mangle] pub extern "C" fn voicevox_make_default_synthesis_options() -> VoicevoxSynthesisOptions { - let _ = init_logger(); + init_logger_once(); VoicevoxSynthesisOptions::default() } @@ -854,7 +859,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_synthesis( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let audio_query_json = CStr::from_ptr(audio_query_json) .to_str() @@ -882,7 +887,7 @@ pub struct VoicevoxTtsOptions { /// @return テキスト音声合成オプション #[no_mangle] pub extern "C" fn voicevox_make_default_tts_options() -> VoicevoxTtsOptions { - let _ = init_logger(); + init_logger_once(); voicevox_core::TtsOptions::default().into() } @@ -914,7 +919,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts_from_kana( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let kana = ensure_utf8(CStr::from_ptr(kana))?; let output = synthesizer.synthesizer().tts_from_kana( @@ -955,7 +960,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( output_wav_length: NonNull, output_wav: NonNull<*mut u8>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let text = ensure_utf8(CStr::from_ptr(text))?; let output = synthesizer.synthesizer().tts( @@ -988,7 +993,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { - let _ = init_logger(); + init_logger_once(); drop(CString::from_raw(C_STRING_DROP_CHECKER.check(json))); } @@ -1005,7 +1010,7 @@ pub unsafe extern "C" fn voicevox_json_free(json: *mut c_char) { /// } #[no_mangle] pub extern "C" fn voicevox_wav_free(wav: *mut u8) { - let _ = init_logger(); + init_logger_once(); U8_SLICE_OWNER.drop_for(wav); } @@ -1033,7 +1038,7 @@ pub extern "C" fn voicevox_wav_free(wav: *mut u8) { pub extern "C" fn voicevox_error_result_to_message( result_code: VoicevoxResultCode, ) -> *const c_char { - let _ = init_logger(); + init_logger_once(); let message = result_code::error_result_to_message(result_code); C_STRING_DROP_CHECKER.blacklist(message).as_ptr() } @@ -1087,7 +1092,7 @@ pub extern "C" fn voicevox_user_dict_word_make( surface: *const c_char, pronunciation: *const c_char, ) -> VoicevoxUserDictWord { - let _ = init_logger(); + init_logger_once(); VoicevoxUserDictWord { surface, pronunciation, @@ -1102,7 +1107,7 @@ pub extern "C" fn voicevox_user_dict_word_make( /// @returns ::VoicevoxUserDict #[no_mangle] pub extern "C" fn voicevox_user_dict_new() -> Box { - let _ = init_logger(); + init_logger_once(); Default::default() } @@ -1121,7 +1126,7 @@ pub unsafe extern "C" fn voicevox_user_dict_load( user_dict: &VoicevoxUserDict, dict_path: *const c_char, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let dict_path = ensure_utf8(unsafe { CStr::from_ptr(dict_path) })?; user_dict.dict.load(dict_path)?; @@ -1151,7 +1156,7 @@ pub unsafe extern "C" fn voicevox_user_dict_add_word( word: *const VoicevoxUserDictWord, output_word_uuid: NonNull<[u8; 16]>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let word = word.read_unaligned().try_into_word()?; let uuid = user_dict.dict.add_word(word)?; @@ -1179,7 +1184,7 @@ pub unsafe extern "C" fn voicevox_user_dict_update_word( word_uuid: &[u8; 16], word: *const VoicevoxUserDictWord, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; let word = word.read_unaligned().try_into_word()?; @@ -1204,7 +1209,7 @@ pub extern "C" fn voicevox_user_dict_remove_word( user_dict: &VoicevoxUserDict, word_uuid: &[u8; 16], ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let word_uuid = Uuid::from_slice(word_uuid).map_err(CApiError::InvalidUuid)?; user_dict.dict.remove_word(word_uuid)?; @@ -1230,7 +1235,7 @@ pub unsafe extern "C" fn voicevox_user_dict_to_json( user_dict: &VoicevoxUserDict, output_json: NonNull<*mut c_char>, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); let json = user_dict.dict.to_json(); let json = CString::new(json).expect("\\0を含まない文字列であることが保証されている"); output_json @@ -1253,7 +1258,7 @@ pub extern "C" fn voicevox_user_dict_import( user_dict: &VoicevoxUserDict, other_dict: &VoicevoxUserDict, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { user_dict.dict.import(&other_dict.dict)?; Ok(()) @@ -1274,7 +1279,7 @@ pub unsafe extern "C" fn voicevox_user_dict_save( user_dict: &VoicevoxUserDict, path: *const c_char, ) -> VoicevoxResultCode { - let _ = init_logger(); + init_logger_once(); into_result_code_with_error((|| { let path = ensure_utf8(CStr::from_ptr(path))?; user_dict.dict.save(path)?; @@ -1291,6 +1296,6 @@ pub unsafe extern "C" fn voicevox_user_dict_save( /// } #[no_mangle] pub unsafe extern "C" fn voicevox_user_dict_delete(user_dict: Box) { - let _ = init_logger(); + init_logger_once(); drop(user_dict); } From a8e830cc0ff62a1d8059aac11972e5ac69c571b2 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 15:44:26 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=A8=E3=81=AA?= =?UTF-8?q?=E3=81=A3=E3=81=9Fdependency=E3=82=92=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 - crates/voicevox_core_c_api/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1067a4d42..deba74398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4395,7 +4395,6 @@ dependencies = [ "cstr", "derive-getters", "duct", - "duplicate", "easy-ext", "futures", "inventory", diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index 5a55d0637..fe5ef243b 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -22,7 +22,6 @@ chrono = { workspace = true, default-features = false, features = ["clock"] } colorchoice.workspace = true cstr.workspace = true derive-getters.workspace = true -duplicate.workspace = true futures.workspace = true itertools.workspace = true libc.workspace = true From c9c9f6b8b8729e513daf5c2762deddb30de8edab Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 15:46:25 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=A8=E3=81=AA?= =?UTF-8?q?=E3=81=A3=E3=81=9Ftokio=E3=82=92dependencies=E3=81=8B=E3=82=89?= =?UTF-8?q?=E5=A4=96=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 - crates/voicevox_core_c_api/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index deba74398..f79482652 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4414,7 +4414,6 @@ dependencies = [ "tempfile", "test_util", "thiserror", - "tokio", "toml 0.7.2", "tracing", "tracing-subscriber", diff --git a/crates/voicevox_core_c_api/Cargo.toml b/crates/voicevox_core_c_api/Cargo.toml index fe5ef243b..ee45eee79 100644 --- a/crates/voicevox_core_c_api/Cargo.toml +++ b/crates/voicevox_core_c_api/Cargo.toml @@ -29,7 +29,6 @@ once_cell.workspace = true process_path.workspace = true serde_json = { workspace = true, features = ["preserve_order"] } thiserror.workspace = true -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } uuid.workspace = true From f43f70ecdd06fee6381dab8a50f5f8dffdda874d Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 16:46:24 +0900 Subject: [PATCH 6/9] Java API --- Cargo.lock | 1 - crates/voicevox_core_java_api/Cargo.toml | 1 - .../java/jp/hiroshiba/voicevoxcore/Dll.java | 6 ++ crates/voicevox_core_java_api/src/common.rs | 12 ++- .../voicevox_core_java_api/src/open_jtalk.rs | 11 +-- .../voicevox_core_java_api/src/synthesizer.rs | 99 ++++++++----------- .../voicevox_core_java_api/src/user_dict.rs | 24 ++--- .../voicevox_core_java_api/src/voice_model.rs | 8 +- 8 files changed, 73 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f79482652..7cab0379a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4432,7 +4432,6 @@ dependencies = [ "jni", "once_cell", "serde_json", - "tokio", "tracing", "tracing-subscriber", "uuid", diff --git a/crates/voicevox_core_java_api/Cargo.toml b/crates/voicevox_core_java_api/Cargo.toml index e09ec29ad..887813685 100644 --- a/crates/voicevox_core_java_api/Cargo.toml +++ b/crates/voicevox_core_java_api/Cargo.toml @@ -17,7 +17,6 @@ derive_more.workspace = true jni.workspace = true once_cell.workspace = true serde_json = { workspace = true, features = ["preserve_order"] } -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } tracing = { workspace = true, features = ["log"] } tracing-subscriber = { workspace = true, features = ["env-filter"] } uuid.workspace = true diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Dll.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Dll.java index e4e674205..4e642bbda 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Dll.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Dll.java @@ -64,5 +64,11 @@ abstract class Dll { throw new RuntimeException("Failed to load Voicevox Core DLL for " + target, e); } } + + new LoggerInitializer().initLogger(); + } + + static class LoggerInitializer { + native void initLogger(); } } diff --git a/crates/voicevox_core_java_api/src/common.rs b/crates/voicevox_core_java_api/src/common.rs index 138676a1d..96122c6e4 100644 --- a/crates/voicevox_core_java_api/src/common.rs +++ b/crates/voicevox_core_java_api/src/common.rs @@ -2,10 +2,12 @@ use std::{error::Error as _, iter}; use derive_more::From; use jni::{objects::JThrowable, JNIEnv}; -use once_cell::sync::Lazy; -use tokio::runtime::Runtime; -pub static RUNTIME: Lazy = Lazy::new(|| { +// FIXME: 別ファイルに分離する +#[no_mangle] +extern "system" fn Java_jp_hiroshiba_voicevoxcore_Dll_00024LoggerInitializer_initLogger( + _: JNIEnv<'_>, +) { if cfg!(target_os = "android") { android_logger::init_once( android_logger::Config::default() @@ -25,6 +27,7 @@ pub static RUNTIME: Lazy = Lazy::new(|| { }; use tracing_subscriber::{fmt::format::Writer, EnvFilter}; + // FIXME: `try_init` → `init` (subscriberは他に存在しないはずなので) let _ = tracing_subscriber::fmt() .with_env_filter(if env::var_os(EnvFilter::DEFAULT_ENV).is_some() { EnvFilter::from_default_env() @@ -57,8 +60,7 @@ pub static RUNTIME: Lazy = Lazy::new(|| { ) && env::var_os("NO_COLOR").is_none() } } - Runtime::new().unwrap() -}); +} #[macro_export] macro_rules! object { diff --git a/crates/voicevox_core_java_api/src/open_jtalk.rs b/crates/voicevox_core_java_api/src/open_jtalk.rs index b2242e984..905baa2b1 100644 --- a/crates/voicevox_core_java_api/src/open_jtalk.rs +++ b/crates/voicevox_core_java_api/src/open_jtalk.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, sync::Arc}; -use crate::common::{throw_if_err, RUNTIME}; +use crate::common::throw_if_err; use jni::{ objects::{JObject, JString}, JNIEnv, @@ -16,8 +16,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_OpenJtalk_rsNew<'local> let open_jtalk_dict_dir = env.get_string(&open_jtalk_dict_dir)?; let open_jtalk_dict_dir = &*Cow::from(&open_jtalk_dict_dir); - let internal = - RUNTIME.block_on(voicevox_core::tokio::OpenJtalk::new(open_jtalk_dict_dir))?; + let internal = voicevox_core::blocking::OpenJtalk::new(open_jtalk_dict_dir)?; env.set_rust_field(&this, "handle", internal)?; Ok(()) @@ -32,14 +31,14 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_OpenJtalk_rsUseUserDict ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::OpenJtalk>(&this, "handle")? + .get_rust_field::<_, _, voicevox_core::blocking::OpenJtalk>(&this, "handle")? .clone(); let user_dict = env - .get_rust_field::<_, _, Arc>(&user_dict, "handle")? + .get_rust_field::<_, _, Arc>(&user_dict, "handle")? .clone(); - RUNTIME.block_on(internal.use_user_dict(&user_dict))?; + internal.use_user_dict(&user_dict)?; Ok(()) }) diff --git a/crates/voicevox_core_java_api/src/synthesizer.rs b/crates/voicevox_core_java_api/src/synthesizer.rs index e36e0b9c2..fee5bc132 100644 --- a/crates/voicevox_core_java_api/src/synthesizer.rs +++ b/crates/voicevox_core_java_api/src/synthesizer.rs @@ -1,5 +1,5 @@ use crate::{ - common::{throw_if_err, JavaApiError, RUNTIME}, + common::{throw_if_err, JavaApiError}, enum_object, object, object_type, }; @@ -18,10 +18,6 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsNew<'loca builder: JObject<'local>, ) { throw_if_err(env, (), |env| { - // ロガーを起動 - // FIXME: `throw_if_err`を`run`とかに改名し、`init_logger`をその中に移動 - let _ = *RUNTIME; - let mut options = voicevox_core::InitializeOptions::default(); let acceleration_mode = env @@ -50,10 +46,11 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsNew<'loca options.cpu_num_threads = cpu_num_threads.i().expect("cpuNumThreads is not integer") as u16; let open_jtalk = env - .get_rust_field::<_, _, voicevox_core::tokio::OpenJtalk>(&open_jtalk, "handle")? + .get_rust_field::<_, _, voicevox_core::blocking::OpenJtalk>(&open_jtalk, "handle")? .clone(); - let internal = - voicevox_core::tokio::Synthesizer::new(open_jtalk, Box::leak(Box::new(options)))?; + let internal = Arc::new(voicevox_core::blocking::Synthesizer::new( + open_jtalk, &options, + )?); env.set_rust_field(&this, "handle", internal)?; Ok(()) }) @@ -65,7 +62,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsIsGpuMode ) -> jboolean { throw_if_err(env, false, |env| { let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -81,7 +78,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsGetMetasJ ) -> jobject { throw_if_err(env, std::ptr::null_mut(), |env| { let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -102,14 +99,14 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsLoadVoice ) { throw_if_err(env, (), |env| { let model = env - .get_rust_field::<_, _, Arc>(&model, "handle")? + .get_rust_field::<_, _, Arc>(&model, "handle")? .clone(); let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - RUNTIME.block_on(internal.load_voice_model(&model))?; + internal.load_voice_model(&model)?; Ok(()) }) } @@ -124,7 +121,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsUnloadVoi let model_id: String = env.get_string(&model_id)?.into(); let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -147,7 +144,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsIsLoadedV let model_id: String = env.get_string(&model_id)?.into(); let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -173,14 +170,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsAudioQuer let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let audio_query = RUNTIME.block_on( - internal.audio_query_from_kana(&kana, voicevox_core::StyleId::new(style_id)), - )?; + let audio_query = + internal.audio_query_from_kana(&kana, voicevox_core::StyleId::new(style_id))?; let query_json = serde_json::to_string(&audio_query).expect("should not fail"); @@ -202,13 +198,12 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsAudioQuer let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let audio_query = - RUNTIME.block_on(internal.audio_query(&text, voicevox_core::StyleId::new(style_id)))?; + let audio_query = internal.audio_query(&text, voicevox_core::StyleId::new(style_id))?; let query_json = serde_json::to_string(&audio_query).expect("should not fail"); @@ -232,14 +227,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsAccentPhr let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let accent_phrases = RUNTIME.block_on( - internal.create_accent_phrases_from_kana(&kana, voicevox_core::StyleId::new(style_id)), - )?; + let accent_phrases = internal + .create_accent_phrases_from_kana(&kana, voicevox_core::StyleId::new(style_id))?; let query_json = serde_json::to_string(&accent_phrases).expect("should not fail"); @@ -261,14 +255,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsAccentPhr let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let accent_phrases = RUNTIME.block_on( - internal.create_accent_phrases(&text, voicevox_core::StyleId::new(style_id)), - )?; + let accent_phrases = + internal.create_accent_phrases(&text, voicevox_core::StyleId::new(style_id))?; let query_json = serde_json::to_string(&accent_phrases).expect("should not fail"); @@ -292,14 +285,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsReplaceMo let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let replaced_accent_phrases = RUNTIME.block_on( - internal.replace_mora_data(&accent_phrases, voicevox_core::StyleId::new(style_id)), - )?; + let replaced_accent_phrases = + internal.replace_mora_data(&accent_phrases, voicevox_core::StyleId::new(style_id))?; let replaced_accent_phrases_json = serde_json::to_string(&replaced_accent_phrases).expect("should not fail"); @@ -324,17 +316,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsReplacePh let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let replaced_accent_phrases = { - RUNTIME.block_on( - internal - .replace_phoneme_length(&accent_phrases, voicevox_core::StyleId::new(style_id)), - )? - }; + let replaced_accent_phrases = internal + .replace_phoneme_length(&accent_phrases, voicevox_core::StyleId::new(style_id))?; let replaced_accent_phrases_json = serde_json::to_string(&replaced_accent_phrases).expect("should not fail"); @@ -357,14 +345,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsReplaceMo let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); - let replaced_accent_phrases = RUNTIME.block_on( - internal.replace_mora_pitch(&accent_phrases, voicevox_core::StyleId::new(style_id)), - )?; + let replaced_accent_phrases = + internal.replace_mora_pitch(&accent_phrases, voicevox_core::StyleId::new(style_id))?; let replaced_accent_phrases_json = serde_json::to_string(&replaced_accent_phrases).expect("should not fail"); @@ -388,7 +375,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsSynthesis let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -398,11 +385,11 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsSynthesis enable_interrogative_upspeak: enable_interrogative_upspeak != 0, // ..Default::default() }; - RUNTIME.block_on(internal.synthesis( + internal.synthesis( &audio_query, voicevox_core::StyleId::new(style_id), &options, - ))? + )? }; let j_bytes = env.byte_array_from_slice(&wave)?; @@ -424,7 +411,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsTtsFromKa let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -434,11 +421,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsTtsFromKa enable_interrogative_upspeak: enable_interrogative_upspeak != 0, // ..Default::default() }; - RUNTIME.block_on(internal.tts_from_kana( - &kana, - voicevox_core::StyleId::new(style_id), - &options, - ))? + internal.tts_from_kana(&kana, voicevox_core::StyleId::new(style_id), &options)? }; let j_bytes = env.byte_array_from_slice(&wave)?; @@ -460,7 +443,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsTts<'loca let style_id = style_id as u32; let internal = env - .get_rust_field::<_, _, voicevox_core::tokio::Synthesizer>( + .get_rust_field::<_, _, Arc>>( &this, "handle", )? .clone(); @@ -470,11 +453,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_Synthesizer_rsTts<'loca enable_interrogative_upspeak: enable_interrogative_upspeak != 0, // ..Default::default() }; - RUNTIME.block_on(internal.tts( - &text, - voicevox_core::StyleId::new(style_id), - &options, - ))? + internal.tts(&text, voicevox_core::StyleId::new(style_id), &options)? }; let j_bytes = env.byte_array_from_slice(&wave)?; diff --git a/crates/voicevox_core_java_api/src/user_dict.rs b/crates/voicevox_core_java_api/src/user_dict.rs index 7eb2722f4..df8b8270b 100644 --- a/crates/voicevox_core_java_api/src/user_dict.rs +++ b/crates/voicevox_core_java_api/src/user_dict.rs @@ -1,7 +1,7 @@ use jni::objects::JClass; use std::{borrow::Cow, sync::Arc}; -use crate::common::{throw_if_err, JavaApiError, RUNTIME}; +use crate::common::{throw_if_err, JavaApiError}; use jni::{ objects::{JObject, JString}, sys::jobject, @@ -14,7 +14,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsNew<'local>( this: JObject<'local>, ) { throw_if_err(env, (), |env| { - let internal = voicevox_core::tokio::UserDict::new(); + let internal = voicevox_core::blocking::UserDict::new(); env.set_rust_field(&this, "handle", Arc::new(internal))?; @@ -30,7 +30,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsAddWord<'loc ) -> jobject { throw_if_err(env, std::ptr::null_mut(), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let word_json = env.get_string(&word_json)?; @@ -55,7 +55,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsUpdateWord<' ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let uuid = env.get_string(&uuid)?; @@ -80,7 +80,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsRemoveWord<' ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let uuid = env.get_string(&uuid)?; @@ -100,10 +100,10 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsImportDict<' ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let other_dict = env - .get_rust_field::<_, _, Arc>(&other_dict, "handle")? + .get_rust_field::<_, _, Arc>(&other_dict, "handle")? .clone(); internal.import(&other_dict)?; @@ -120,13 +120,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsLoad<'local> ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let path = env.get_string(&path)?; let path = &Cow::from(&path); - RUNTIME.block_on(internal.load(path))?; + internal.load(path)?; Ok(()) }) @@ -140,13 +140,13 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsSave<'local> ) { throw_if_err(env, (), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let path = env.get_string(&path)?; let path = &Cow::from(&path); - RUNTIME.block_on(internal.save(path))?; + internal.save(path)?; Ok(()) }) @@ -159,7 +159,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_UserDict_rsGetWords<'lo ) -> jobject { throw_if_err(env, std::ptr::null_mut(), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let words = internal.to_json(); diff --git a/crates/voicevox_core_java_api/src/voice_model.rs b/crates/voicevox_core_java_api/src/voice_model.rs index d0ede9365..42a20544a 100644 --- a/crates/voicevox_core_java_api/src/voice_model.rs +++ b/crates/voicevox_core_java_api/src/voice_model.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, sync::Arc}; -use crate::common::{throw_if_err, RUNTIME}; +use crate::common::throw_if_err; use jni::{ objects::{JObject, JString}, sys::jobject, @@ -17,7 +17,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_VoiceModel_rsFromPath<' let model_path = env.get_string(&model_path)?; let model_path = &*Cow::from(&model_path); - let internal = RUNTIME.block_on(voicevox_core::tokio::VoiceModel::from_path(model_path))?; + let internal = voicevox_core::blocking::VoiceModel::from_path(model_path)?; env.set_rust_field(&this, "handle", Arc::new(internal))?; @@ -32,7 +32,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_VoiceModel_rsGetId<'loc ) -> jobject { throw_if_err(env, std::ptr::null_mut(), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let id = internal.id().raw_voice_model_id(); @@ -50,7 +50,7 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_VoiceModel_rsGetMetasJs ) -> jobject { throw_if_err(env, std::ptr::null_mut(), |env| { let internal = env - .get_rust_field::<_, _, Arc>(&this, "handle")? + .get_rust_field::<_, _, Arc>(&this, "handle")? .clone(); let metas = internal.metas(); From 210191128295eaa4217bb0609e4e03b8f997aad0 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 17:00:27 +0900 Subject: [PATCH 7/9] =?UTF-8?q?`impl=20PerformInference=20for=20voicevox?= =?UTF-8?q?=5Fcore::tokio::Synthesizer<=5F>`=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/voicevox_core/src/synthesizer.rs | 51 ++++--------------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/crates/voicevox_core/src/synthesizer.rs b/crates/voicevox_core/src/synthesizer.rs index c2bb1af5f..a728fff65 100644 --- a/crates/voicevox_core/src/synthesizer.rs +++ b/crates/voicevox_core/src/synthesizer.rs @@ -1040,47 +1040,6 @@ pub trait PerformInference { ) -> Result>; } -impl PerformInference for self::tokio::Synthesizer { - fn predict_duration(&self, phoneme_vector: &[i64], style_id: StyleId) -> Result> { - self.0.predict_duration(phoneme_vector, style_id) - } - - fn predict_intonation( - &self, - length: usize, - vowel_phoneme_vector: &[i64], - consonant_phoneme_vector: &[i64], - start_accent_vector: &[i64], - end_accent_vector: &[i64], - start_accent_phrase_vector: &[i64], - end_accent_phrase_vector: &[i64], - style_id: StyleId, - ) -> Result> { - self.0.predict_intonation( - length, - vowel_phoneme_vector, - consonant_phoneme_vector, - start_accent_vector, - end_accent_vector, - start_accent_phrase_vector, - end_accent_phrase_vector, - style_id, - ) - } - - fn decode( - &self, - length: usize, - phoneme_size: usize, - f0: &[f32], - phoneme_vector: &[f32], - style_id: StyleId, - ) -> Result> { - self.0 - .decode(length, phoneme_size, f0, phoneme_vector, style_id) - } -} - impl PerformInference for self::blocking::Synthesizer { fn predict_duration(&self, phoneme_vector: &[i64], style_id: StyleId) -> Result> { // FIXME: `Status::ids_for`があるため、ここは不要なはず @@ -1517,7 +1476,9 @@ mod tests { 30, 35, 14, 23, 7, 21, 14, 43, 30, 30, 23, 30, 35, 30, 0, ]; - let result = syntesizer.predict_duration(&phoneme_vector, StyleId::new(1)); + let result = syntesizer + .0 + .predict_duration(&phoneme_vector, StyleId::new(1)); assert!(result.is_ok(), "{result:?}"); assert_eq!(result.unwrap().len(), phoneme_vector.len()); @@ -1547,7 +1508,7 @@ mod tests { let start_accent_phrase_vector = [0, 1, 0, 0, 0]; let end_accent_phrase_vector = [0, 0, 0, 1, 0]; - let result = syntesizer.predict_intonation( + let result = syntesizer.0.predict_intonation( vowel_phoneme_vector.len(), &vowel_phoneme_vector, &consonant_phoneme_vector, @@ -1600,7 +1561,9 @@ mod tests { set_one(30, 45..60); set_one(0, 60..69); - let result = syntesizer.decode(F0_LENGTH, PHONEME_SIZE, &f0, &phoneme, StyleId::new(1)); + let result = syntesizer + .0 + .decode(F0_LENGTH, PHONEME_SIZE, &f0, &phoneme, StyleId::new(1)); assert!(result.is_ok(), "{result:?}"); assert_eq!(result.unwrap().len(), F0_LENGTH * 256); From 640604da0cefa64b17b69382e0d7213585a02197 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 17:02:38 +0900 Subject: [PATCH 8/9] =?UTF-8?q?FIXME=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/voicevox_core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/voicevox_core/Cargo.toml b/crates/voicevox_core/Cargo.toml index 1b8904875..96a8bb574 100644 --- a/crates/voicevox_core/Cargo.toml +++ b/crates/voicevox_core/Cargo.toml @@ -35,7 +35,7 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["preserve_order"] } tempfile.workspace = true thiserror.workspace = true -tokio = { workspace = true, features = ["rt"] } +tokio = { workspace = true, features = ["rt"] } # FIXME: feature-gateする tracing.workspace = true uuid = { workspace = true, features = ["v4", "serde"] } voicevox_core_macros = { path = "../voicevox_core_macros" } From c89b2eb8c81a28090ead13d6e469b1ead08dc7a1 Mon Sep 17 00:00:00 2001 From: Ryo Yamashita Date: Sun, 10 Dec 2023 17:15:27 +0900 Subject: [PATCH 9/9] =?UTF-8?q?`this`=E3=81=AE=E5=88=86=E3=81=AE=E5=BC=95?= =?UTF-8?q?=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/voicevox_core_java_api/src/common.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/voicevox_core_java_api/src/common.rs b/crates/voicevox_core_java_api/src/common.rs index 96122c6e4..c2987e207 100644 --- a/crates/voicevox_core_java_api/src/common.rs +++ b/crates/voicevox_core_java_api/src/common.rs @@ -1,12 +1,16 @@ use std::{error::Error as _, iter}; use derive_more::From; -use jni::{objects::JThrowable, JNIEnv}; +use jni::{ + objects::{JObject, JThrowable}, + JNIEnv, +}; // FIXME: 別ファイルに分離する #[no_mangle] extern "system" fn Java_jp_hiroshiba_voicevoxcore_Dll_00024LoggerInitializer_initLogger( _: JNIEnv<'_>, + _: JObject<'_>, ) { if cfg!(target_os = "android") { android_logger::init_once(