diff --git a/crates/voicevox_core/src/__internal/interop.rs b/crates/voicevox_core/src/__internal/interop.rs index a218730cd..61ea5f1ae 100644 --- a/crates/voicevox_core/src/__internal/interop.rs +++ b/crates/voicevox_core/src/__internal/interop.rs @@ -1,6 +1,3 @@ pub mod raii; -pub use crate::{ - metas::merge as merge_metas, synthesizer::blocking::PerformInference, - voice_model::blocking::IdRef, -}; +pub use crate::{metas::merge as merge_metas, synthesizer::blocking::PerformInference}; diff --git a/crates/voicevox_core/src/voice_model.rs b/crates/voicevox_core/src/voice_model.rs index ef105fae6..7f39b22cb 100644 --- a/crates/voicevox_core/src/voice_model.rs +++ b/crates/voicevox_core/src/voice_model.rs @@ -402,9 +402,6 @@ impl InferenceDomainMap { pub(crate) mod blocking { use std::path::Path; - use easy_ext::ext; - use uuid::Uuid; - use crate::{ asyncs::SingleTasked, error::LoadModelResult, future::FutureExt as _, infer::domains::InferenceDomainMap, VoiceModelMeta, @@ -443,13 +440,6 @@ pub(crate) mod blocking { self.0.header() } } - - #[ext(IdRef)] - pub impl VoiceModelFile { - fn id_ref(&self) -> &Uuid { - &self.header().manifest.id.0 - } - } } pub(crate) mod nonblocking { diff --git a/crates/voicevox_core_c_api/include/voicevox_core.h b/crates/voicevox_core_c_api/include/voicevox_core.h index e158ebb6a..e8656d8ec 100644 --- a/crates/voicevox_core_c_api/include/voicevox_core.h +++ b/crates/voicevox_core_c_api/include/voicevox_core.h @@ -615,34 +615,36 @@ VoicevoxResultCode voicevox_voice_model_file_open(const char *path, * ::VoicevoxVoiceModelFile からIDを取得する。 * * @param [in] model 音声モデル - * - * @returns 音声モデルID + * @param [out] output_voice_model_id 音声モデルID * * \safety{ * - `model`は ::voicevox_voice_model_file_open で得たものでなければならず、また ::voicevox_voice_model_file_close で解放されていてはいけない。 + * - `output_voice_model_id`は書き込みについて有効でなければならない。 * } */ #ifdef _WIN32 __declspec(dllimport) #endif -VoicevoxVoiceModelId voicevox_voice_model_file_id(const struct VoicevoxVoiceModelFile *model); +void voicevox_voice_model_file_id(const struct VoicevoxVoiceModelFile *model, + uint8_t (*output_voice_model_id)[16]); /** * ::VoicevoxVoiceModelFile からメタ情報を取得する。 * + * JSONの解放は ::voicevox_json_free で行う。 + * * @param [in] model 音声モデル * * @returns メタ情報のJSON文字列 * * \safety{ * - `model`は ::voicevox_voice_model_file_open で得たものでなければならず、また ::voicevox_voice_model_file_close で解放されていてはいけない。 - * - 戻り値の文字列の生存期間(_lifetime_)は次にこの関数が呼ばれるか、`model`が破棄されるまでである。この生存期間を越えて文字列にアクセスしてはならない。 * } */ #ifdef _WIN32 __declspec(dllimport) #endif -const char *voicevox_voice_model_file_get_metas_json(const struct VoicevoxVoiceModelFile *model); +char *voicevox_voice_model_file_create_metas_json(const struct VoicevoxVoiceModelFile *model); /** * ::VoicevoxVoiceModelFile を、所有しているファイルディスクリプタを閉じた上で破棄(_destruct_)する。 @@ -1173,6 +1175,7 @@ VoicevoxResultCode voicevox_synthesizer_tts(const struct VoicevoxSynthesizer *sy * \safety{ * - `json`は以下のAPIで得られたポインタでなくてはいけない。 * - ::voicevox_onnxruntime_create_supported_devices_json + * - ::voicevox_voice_model_file_create_metas_json * - ::voicevox_synthesizer_create_metas_json * - ::voicevox_synthesizer_create_audio_query * - ::voicevox_synthesizer_create_accent_phrases diff --git a/crates/voicevox_core_c_api/src/c_impls.rs b/crates/voicevox_core_c_api/src/c_impls.rs index 0e9ff9a78..8888cfdfe 100644 --- a/crates/voicevox_core_c_api/src/c_impls.rs +++ b/crates/voicevox_core_c_api/src/c_impls.rs @@ -2,7 +2,7 @@ use std::{ffi::CString, path::Path}; use camino::Utf8Path; use ref_cast::ref_cast_custom; -use voicevox_core::{InitializeOptions, Result, VoiceModelId}; +use voicevox_core::{InitializeOptions, Result, SpeakerMeta, VoiceModelId}; use crate::{ helpers::CApiResult, OpenJtalkRc, VoicevoxOnnxruntime, VoicevoxSynthesizer, @@ -100,15 +100,22 @@ impl VoicevoxSynthesizer { } pub(crate) fn metas(&self) -> CString { - let metas = &self.synthesizer.metas(); - CString::new(serde_json::to_string(metas).unwrap()).unwrap() + metas_to_json(&self.synthesizer.metas()) } } impl VoicevoxVoiceModelFile { pub(crate) fn open(path: impl AsRef) -> Result { let model = voicevox_core::blocking::VoiceModelFile::open(path)?; - let metas = CString::new(serde_json::to_string(model.metas()).unwrap()).unwrap(); - Ok(Self { model, metas }) + Ok(Self { model }) } + + pub(crate) fn metas(&self) -> CString { + metas_to_json(self.model.metas()) + } +} + +fn metas_to_json(metas: &[SpeakerMeta]) -> CString { + let metas = serde_json::to_string(metas).expect("should not fail"); + CString::new(metas).expect("should not contain NUL") } diff --git a/crates/voicevox_core_c_api/src/lib.rs b/crates/voicevox_core_c_api/src/lib.rs index a5c440146..a43ea03cf 100644 --- a/crates/voicevox_core_c_api/src/lib.rs +++ b/crates/voicevox_core_c_api/src/lib.rs @@ -34,7 +34,6 @@ use std::sync::{Arc, Once}; use tracing_subscriber::fmt::format::Writer; use tracing_subscriber::EnvFilter; use uuid::Uuid; -use voicevox_core::__internal::interop::IdRef as _; use voicevox_core::{AccentPhrase, AudioQuery, TtsOptions, UserDictWord}; use voicevox_core::{StyleId, SynthesisOptions}; @@ -400,7 +399,6 @@ pub extern "C" fn voicevox_get_version() -> *const c_char { #[derive(Getters)] pub struct VoicevoxVoiceModelFile { model: voicevox_core::blocking::VoiceModelFile, - metas: CString, } /// 音声モデルID。 @@ -439,36 +437,39 @@ pub unsafe extern "C" fn voicevox_voice_model_file_open( /// ::VoicevoxVoiceModelFile からIDを取得する。 /// /// @param [in] model 音声モデル -/// -/// @returns 音声モデルID +/// @param [out] output_voice_model_id 音声モデルID /// /// \safety{ /// - `model`は ::voicevox_voice_model_file_open で得たものでなければならず、また ::voicevox_voice_model_file_close で解放されていてはいけない。 +/// - `output_voice_model_id`は書き込みについて有効でなければならない。 /// } #[no_mangle] -pub extern "C" fn voicevox_voice_model_file_id( +pub unsafe extern "C" fn voicevox_voice_model_file_id( model: &VoicevoxVoiceModelFile, -) -> VoicevoxVoiceModelId<'_> { + output_voice_model_id: NonNull<[u8; 16]>, +) { init_logger_once(); - model.model.id_ref().as_bytes() + let id = model.model.id().raw_voice_model_id().into_bytes(); + unsafe { output_voice_model_id.write_unaligned(id) }; } /// ::VoicevoxVoiceModelFile からメタ情報を取得する。 /// +/// JSONの解放は ::voicevox_json_free で行う。 +/// /// @param [in] model 音声モデル /// /// @returns メタ情報のJSON文字列 /// /// \safety{ /// - `model`は ::voicevox_voice_model_file_open で得たものでなければならず、また ::voicevox_voice_model_file_close で解放されていてはいけない。 -/// - 戻り値の文字列の生存期間(_lifetime_)は次にこの関数が呼ばれるか、`model`が破棄されるまでである。この生存期間を越えて文字列にアクセスしてはならない。 /// } #[no_mangle] -pub extern "C" fn voicevox_voice_model_file_get_metas_json( +pub extern "C" fn voicevox_voice_model_file_create_metas_json( model: &VoicevoxVoiceModelFile, -) -> *const c_char { +) -> *mut c_char { init_logger_once(); - model.metas().as_ptr() + C_STRING_DROP_CHECKER.whitelist(model.metas()).into_raw() } /// ::VoicevoxVoiceModelFile を、所有しているファイルディスクリプタを閉じた上で破棄(_destruct_)する。 @@ -1161,6 +1162,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts( /// \safety{ /// - `json`は以下のAPIで得られたポインタでなくてはいけない。 /// - ::voicevox_onnxruntime_create_supported_devices_json +/// - ::voicevox_voice_model_file_create_metas_json /// - ::voicevox_synthesizer_create_metas_json /// - ::voicevox_synthesizer_create_audio_query /// - ::voicevox_synthesizer_create_accent_phrases