Expand description
無料で使える中品質なテキスト読み上げソフトウェア、VOICEVOXのコア。
§Feature flags
buildtime-download-onnxruntime: ビルド時に後述する環境変数VVCORE_BUILD_DOWNLOAD_AND_COPY_ORTが1なら、ONNX Runtimeのバイナリをダウンロードしてtarget directory内の複数箇所に配置する。VVCORE_BUILD_DOWNLOAD_AND_COPY_ORTが1ではないなら警告を出して何もしない。後述のlink-onnxruntimeフィーチャと合わせると、システムにONNX Runtimeが無くてもビルドが可能になる。load-onnxruntime: ONNX Runtimeをdlopen/LoadLibraryExWで開く。CUDAとDirectMLが利用可能。link-onnxruntime: ONNX Runtimeをロード時動的リンクする。そのためビルドするためにはシステムにONNX Runtimeがインストールされているか、buildtime-download-onnxruntimeによるダウンロードを行う必要がある。iOSのようなdlopenの利用が困難な環境でのみこちらを利用するべきである。Note: 動的リンク対象のライブラリ名はonnxruntimeで固定。変更はpatchelf(1)やinstall_name_tool(1)で行うこと。また、ONNX RuntimeのGPU機能を使うことは不可。
このクレートの利用にあたっては上記のload-onnxruntimeかlink-onnxruntimeのうちどちらかを有効にしなければならない。両方の有効化はコンパイルエラーとなる。Onnxruntimeの初期化方法はこれらのフィーチャによって決まる。
§Build time environment variables
VVCORE_BUILD_DOWNLOAD_AND_COPY_ORT:buildtime-download-onnxruntimeフィーチャが有効化されているときのみ機能する。1のとき、ONNX Runtimeのバイナリをダウンロードしてtarget directory内の複数箇所に配置する。buildtime-download-onnxruntimeフィーチャが無効化されているときは値が1であっても、警告のみを出しダウンロードは行わない。
§Examples
//! トーク
use std::{io::Write as _, panic};
use anyhow::Context as _;
use const_format::concatcp;
use voicevox_core::{
blocking::{Onnxruntime, OpenJtalk, Synthesizer, VoiceModelFile},
CharacterMeta, StyleMeta,
};
// ダウンローダーにて`onnxruntime`としてダウンロードできるもの
const VVORT: &str = concatcp!(
"./voicevox_core/onnxruntime/lib/",
Onnxruntime::LIB_VERSIONED_FILENAME,
);
// ダウンローダーにて`dict`としてダウンロードできるもの
const OJT_DIC: &str = "./voicevox_core/dict/open_jtalk_dic_utf_8-1.11";
// ダウンローダーにて`models`としてダウンロードできるもの
const VVM: &str = "./voicevox_core/models/vvms/0.vvm";
const TARGET_CHARACTER_NAME: &str = "ずんだもん";
const TARGET_STYLE_NAME: &str = "ノーマル";
const TEXT: &str = "こんにちは";
let synth = {
let ort = Onnxruntime::load_once().filename(VVORT).perform()?;
let ojt = OpenJtalk::new(OJT_DIC)?;
Synthesizer::builder(ort).text_analyzer(ojt).build()?
};
dbg!(synth.is_gpu_mode());
synth
.load_voice_model(&VoiceModelFile::open(VVM)?)
.perform()?;
let StyleMeta { id: style_id, .. } = synth
.metas()
.into_iter()
.filter(|CharacterMeta { name, .. }| name == TARGET_CHARACTER_NAME)
.flat_map(|CharacterMeta { styles, .. }| styles)
.find(|StyleMeta { name, .. }| name == TARGET_STYLE_NAME)
.with_context(|| {
format!("could not find \"{TARGET_CHARACTER_NAME} ({TARGET_STYLE_NAME})\"")
})?;
eprintln!("Synthesizing");
let wav = &synth.tts(TEXT, style_id).perform()?;
eprintln!("Playing the WAV");
play(wav)?;
fn play(wav: &[u8]) -> anyhow::Result<()> {
let tempfile = tempfile::Builder::new().suffix(".wav").tempfile()?;
(&tempfile).write_all(wav)?;
let tempfile = &tempfile.into_temp_path();
open::that_in_background(tempfile)
.join()
.unwrap_or_else(|e| panic::resume_unwind(e))?;
Ok(())
}//! ソング
use std::{io::Write as _, panic};
use anyhow::Context as _;
use const_format::concatcp;
use voicevox_core::{
blocking::{Onnxruntime, Synthesizer, VoiceModelFile},
CharacterMeta, Score, StyleMeta, StyleType,
};
// ダウンローダーにて`onnxruntime`としてダウンロードできるもの
const VVORT: &str = concatcp!(
"./voicevox_core/onnxruntime/lib/",
Onnxruntime::LIB_VERSIONED_FILENAME,
);
// ダウンローダーにて`models`としてダウンロードできるもの
const VVM: &str = "./voicevox_core/models/vvms/s0.vvm";
const SINGING_TEACHER_CHARACTER_NAME: &str = "波音リツ";
const SINGING_TEACHER_STYLE_NAME: &str = "ノーマル";
const SINGER_CHARACTER_NAME: &str = "ずんだもん";
const SINGER_STYLE_NAME: &str = "ノーマル";
let synth = {
let ort = Onnxruntime::load_once().filename(VVORT).perform()?;
Synthesizer::builder(ort).build()?
};
dbg!(synth.is_gpu_mode());
synth
.load_voice_model(&VoiceModelFile::open(VVM)?)
.perform()?;
let metas = &synth.metas();
let find_style = |character_name, style_name, style_types: &[_]| {
metas
.iter()
.filter(|CharacterMeta { name, .. }| name == character_name)
.flat_map(|CharacterMeta { styles, .. }| styles)
.find(|StyleMeta { name, r#type, .. }| {
name == style_name && style_types.contains(r#type)
})
.map(|&StyleMeta { id, .. }| id)
.with_context(|| format!("could not find \"{character_name} ({style_name})\""))
};
let singing_teacher = find_style(
SINGING_TEACHER_CHARACTER_NAME,
SINGING_TEACHER_STYLE_NAME,
&[StyleType::SingingTeacher, StyleType::Sing],
)?;
let singer = find_style(
SINGER_CHARACTER_NAME,
SINGER_STYLE_NAME,
&[StyleType::FrameDecode],
)?;
let score = &serde_json::from_str::<Score>(
r#"
{
"notes": [
{ "key": null, "frame_length": 15, "lyric": "" },
{ "key": 60, "frame_length": 45, "lyric": "ド" },
{ "key": 62, "frame_length": 45, "lyric": "レ" },
{ "key": 64, "frame_length": 45, "lyric": "ミ" },
{ "key": null, "frame_length": 15, "lyric": "" }
]
}
"#,
)
.unwrap();
let frame_audio_query = &synth.create_sing_frame_audio_query(score, singing_teacher)?;
eprintln!("Synthesizing");
let wav = &synth
.frame_synthesis(&frame_audio_query, singer)
.perform()?;
eprintln!("Playing the WAV");
play(wav)?;
fn play(wav: &[u8]) -> anyhow::Result<()> {
let tempfile = tempfile::Builder::new().suffix(".wav").tempfile()?;
(&tempfile).write_all(wav)?;
let tempfile = &tempfile.into_temp_path();
open::that_in_background(tempfile)
.join()
.unwrap_or_else(|e| panic::resume_unwind(e))?;
Ok(())
}§音声の調整
ユーザーガイドのテキスト音声合成の流れを参照。
以下のwav1からwav4はすべて同一となる。
use std::collections::HashSet;
use voicevox_core::{
blocking::{Synthesizer, TextAnalyzer},
AudioQuery, StyleId,
};
fn f(synth: &Synthesizer<impl TextAnalyzer>) -> anyhow::Result<()> {
const TEXT: &str = _;
const STYLE_ID: StyleId = _;
let wav1 = synth.tts(TEXT, STYLE_ID).perform()?;
let wav2 = {
let query = synth.create_audio_query(TEXT, STYLE_ID)?;
synth.synthesis(&query, STYLE_ID).perform()?
};
let wav3 = {
let phrases = synth.create_accent_phrases(TEXT, STYLE_ID)?;
let query = AudioQuery::from(phrases);
synth.synthesis(&query, STYLE_ID).perform()?
};
let wav4 = {
let phrases = synth.text_analyzer().analyze(TEXT)?;
let phrases = synth.replace_mora_data(&phrases, STYLE_ID)?;
let query = AudioQuery::from(phrases);
synth.synthesis(&query, STYLE_ID).perform()?
};
let wav5 = {
let phrases = synth.text_analyzer().analyze(TEXT)?;
let phrases = synth.replace_phoneme_length(&phrases, STYLE_ID)?;
let phrases = synth.replace_mora_pitch(&phrases, STYLE_ID)?;
let query = AudioQuery::from(phrases);
synth.synthesis(&query, STYLE_ID).perform()?
};
assert_eq!(1, HashSet::from([wav1, wav2, wav3, wav4, wav5]).len());
Ok(())
}Modules§
- __doc
doc - blocking
- ブロッキング版API。
- nonblocking
- 非同期版API。
Macros§
Structs§
- Accent
Phrase - AccentPhrase (アクセント句ごとの情報)。
- Audio
Query - AudioQuery (音声合成用のクエリ)。
- Character
Meta - キャラクターのメタ情報。
- Character
Version - キャラクターのバージョン。
- Error
- VOICEVOX COREのエラー。
- Frame
Audio Query - フレームごとの音声合成用のクエリ。
- Frame
Phoneme - 音素の情報。
- Key
- 音階。
- Mora
- モーラ(子音+母音)ごとの情報。
- Note
- 音符または休符。
- NoteId
- 音符のID。
- Optional
Lyric - 音符の歌詞、または休符を表わす無音。
- Sampling
Rate - サンプリングレート(Hz)。
- Score
- 楽譜情報。
- Sil
sil(silent)。- StyleId
- スタイルID。
- Style
Meta - スタイルのメタ情報。
- Supported
Devices - 利用可能なデバイスの情報。
- User
Dict Word - ユーザー辞書の単語。
- User
Dict Word Builder UserDictWordのビルダー。- Voice
Model Id - 音声モデルID。
Enums§
- Acceleration
Mode - ハードウェアアクセラレーションモードを設定する設定値。
- Error
Kind - エラーの種類。
- OnExisting
Voice Model Id Synthesizer::load_voice_modelの実行時に、同じidのVoiceModelFileが既に読み込まれていたときのふるまい。- Phoneme
- 音素。
- Style
Type - スタイルに対応するモデルの種類。
- User
Dict Word Type - ユーザー辞書の単語の種類。
Constants§
- VERSION
- 本クレートの
package.version。
Functions§
- ensure_
compatible - 与えられた楽譜と歌唱音声合成用のクエリの組み合わせが、基本周波数と音量の生成に利用できるかどうかを確認する。
Type Aliases§
- Result
- Voice
Model Meta - 音声モデルのメタ情報。