pub mod aquestalk1{
use libloading::{Library, Symbol};
use std::{convert::TryFrom, ffi::{CString, OsStr}, mem::MaybeUninit, os::raw::c_char, sync::Arc};
type AqSynthe<'a> = Symbol<'a, unsafe extern fn(*const c_char, i32, *mut i32) -> *mut u8>;
type AqFreeWav<'a> = Symbol<'a, unsafe extern fn(*mut u8)>;
pub struct AqDLL<'a>{
dll: Arc<AqDLL2<'a>>,
}
struct AqDLL2<'a>{
lib: Library,
synthe: AqSynthe<'a>,
freewav: AqFreeWav<'a>
}
impl<'a> AqDLL<'a>{
pub fn load<P: AsRef<OsStr>>(dllpath: P) -> Result<Self, Box<dyn std::error::Error>>{
unsafe{
let dll = AqDLL{
dll: Arc::new(AqDLL2{
lib: Library::new(dllpath)?,
synthe: MaybeUninit::uninit().assume_init(),
freewav: MaybeUninit::uninit().assume_init(),
}),
};
*(&dll.dll.synthe as *const _ as *mut AqSynthe) = dll.dll.lib.get(b"AquesTalk_Synthe_Utf8")?;
*(&dll.dll.freewav as *const _ as *mut AqFreeWav) = dll.dll.lib.get(b"AquesTalk_FreeWave")?;
Ok(dll)
}
}
pub fn synthe<'b>(&self, koe: &str, ispeed: i32) -> Result<AqWAV<'b>,Box<dyn std::error::Error>>{
unsafe{
let koe2 = CString::new(koe)?;
let mut size = 0;
let wav = (self.dll.synthe)(koe2.as_ptr(), ispeed, &mut size as *mut i32);
if wav.is_null(){
Err(Box::new(AqErr(size)))
} else {
Ok(AqWAV{
wav: std::slice::from_raw_parts_mut(wav, TryFrom::try_from(size)?),
dll: Arc::clone(&*(&self.dll as *const _ as *mut Arc<AqDLL2>)),
})
}
}
}
}
pub struct AqWAV<'a>{
wav: &'a mut [u8],
dll: Arc<AqDLL2<'a>>,
}
impl<'a> std::ops::Deref for AqWAV<'a>{
type Target = &'a mut [u8];
fn deref(&self) -> &Self::Target {
&self.wav
}
}
impl<'a> std::ops::DerefMut for AqWAV<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.wav
}
}
impl<'a> std::ops::Drop for AqWAV<'a> {
fn drop(&mut self){
unsafe {
(self.dll.freewav)(&mut self.wav[0] as *mut u8);
}
}
}
struct AqErr(i32);
impl AqErr{
fn msg(&self) -> &str{
match self.0 {
100 => "その他のエラー, エラーコード: 100",
101 => "メモリ不足, エラーコード: 101",
102 => "音声記号列に未定義の読み記号が指定された, エラーコード: 102",
103 => "韻律データの時間長がマイナスなっている, エラーコード: 103",
104 => "内部エラー(未定義の区切りコード検出), エラーコード: 104",
105 => "音声記号列に未定義の読み記号が指定された, エラーコード: 105",
106 => "音声記号列のタグの指定が正しくない, エラーコード: 106",
107 => "タグの長さが制限を越えている(または[>]がみつからない), エラーコード: 107",
108 => "タグ内の値の指定が正しくない, エラーコード: 108",
109 => "WAVE再生ができない(サウンドドライバ関連の問題), エラーコード: 109",
110 => "WAVE再生ができない(サウンドドライバ関連の問題非同期再生), エラーコード: 110",
111 => "発声すべきデータがない, エラーコード: 111",
200 => "音声記号列が長すぎる, エラーコード: 200",
201 => "1つのフレーズ中の読み記号が多すぎる, エラーコード: 201",
202 => "音声記号列が長い(内部バッファオーバー1), エラーコード: 202",
203 => "ヒープメモリ不足, エラーコード: 203",
204 => "音声記号列が長い(内部バッファオーバー1), エラーコード: 204",
_ => "未定義のエラー",
}
}
}
impl std::fmt::Display for AqErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl std::fmt::Debug for AqErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl std::error::Error for AqErr {
fn description(&self) -> &str {
self.msg()
}
}
}
pub mod aqkanji2koe{
use libloading::{Library, Symbol};
use std::{alloc, convert::TryFrom, ffi::{CString, CStr, c_void, OsStr}, mem::MaybeUninit, mem, os::raw::c_char, sync::Arc};
type AqK2Kcreate<'a> = Symbol<'a, unsafe extern fn(*const c_char, *mut i32) -> *mut c_void>;
type AqK2Kcreateptr<'a> = Symbol<'a, unsafe extern fn(*const c_void, *const c_void, *mut i32) -> *mut c_void>;
type AqK2Krelease<'a> = Symbol<'a, unsafe extern fn(*mut c_void)>;
type AqK2Ksetdevkey<'a> = Symbol<'a, unsafe extern fn(*const c_char) -> i32>;
type AqK2Kconvert<'a> = Symbol<'a, unsafe extern fn(*mut c_void, *const c_char, *mut c_char, i32) -> i32>;
pub struct AqK2KDLL<'a>{
dll: Arc<AqK2KDLL2<'a>>,
}
struct AqK2KDLL2<'a>{
lib: Library,
create: AqK2Kcreate<'a>,
create_ptr: AqK2Kcreateptr<'a>,
release: AqK2Krelease<'a>,
convert: AqK2Kconvert<'a>,
setdevkey: AqK2Ksetdevkey<'a>,
}
impl<'a> AqK2KDLL<'a>{
pub fn load<P: AsRef<OsStr>>(dllpath: P, devkey: Option<&str>) -> Result<Self, Box<dyn std::error::Error>>{
unsafe{
let dll = AqK2KDLL{
dll: Arc::new(AqK2KDLL2{
lib: Library::new(dllpath)?,
create: MaybeUninit::uninit().assume_init(),
create_ptr: MaybeUninit::uninit().assume_init(),
release: MaybeUninit::uninit().assume_init(),
convert: MaybeUninit::uninit().assume_init(),
setdevkey: MaybeUninit::uninit().assume_init(),
}),
};
*(&dll.dll.setdevkey as *const _ as *mut AqK2Ksetdevkey) = dll.dll.lib.get(b"AqKanji2Koe_SetDevKey")?;
match devkey {
Some(s) => {
let s2 = CString::new(s)?;
let _ = (dll.dll.setdevkey)(s2.as_ptr());
},
None => (),
}
*(&dll.dll.create as *const _ as *mut AqK2Kcreate) = dll.dll.lib.get(b"AqKanji2Koe_Create")?;
*(&dll.dll.create_ptr as *const _ as *mut AqK2Kcreateptr) = dll.dll.lib.get(b"AqKanji2Koe_Create_Ptr")?;
*(&dll.dll.release as *const _ as *mut AqK2Krelease) = dll.dll.lib.get(b"AqKanji2Koe_Release")?;
*(&dll.dll.convert as *const _ as *mut AqK2Kconvert) = match platform_win() {
true => dll.dll.lib.get(b"AqKanji2Koe_Convert_utf8")?,
false => dll.dll.lib.get(b"AqKanji2Koe_Convert")?,
};
Ok(dll)
}
}
pub fn create<'b>(&self, pathdic: &str) -> Result<AqK2Kinstance<'b>,Box<dyn std::error::Error>> {
let mut errcode: i32 = 0;
let pathdic2 = CString::new(pathdic)?;
unsafe {
let instance = (self.dll.create)(pathdic2.as_ptr(), &mut errcode as *mut i32);
if instance.is_null() {
Err(Box::new(AqK2Kerr(errcode)))
} else {
Ok(AqK2Kinstance{
instance: instance,
dll: Arc::clone(&*(&self.dll as *const _ as *mut Arc<AqK2KDLL2>)),
})
}
}
}
pub unsafe fn create_ptr<'b>(&self, sysdic: *const c_void, userdic: *const c_void) -> Result<AqK2Kinstance<'b>,Box<dyn std::error::Error>> {
let mut errcode: i32 = 0;
let instance = (self.dll.create_ptr)(sysdic, userdic, &mut errcode as *mut i32);
if instance.is_null() {
Err(Box::new(AqK2Kerr(errcode)))
} else {
Ok(AqK2Kinstance{
instance: instance,
dll: Arc::clone(&*(&self.dll as *const _ as *mut Arc<AqK2KDLL2>)),
})
}
}
}
pub struct AqK2Kinstance<'a>{
instance: *mut c_void,
dll: Arc<AqK2KDLL2<'a>>,
}
impl<'a> AqK2Kinstance<'a>{
pub fn convert<'b>(&mut self, kanji: &str, buffersize: Option<usize>) -> Result<AqK2Kstr<'b>,Box<dyn std::error::Error>> {
unsafe{
let mut size: usize = match buffersize {
Some(s) => s,
None => {
(kanji.len()+1)*2
},
};
if size < 256 {
size = 256;
}
let kanji2 = CString::new(kanji)?;
let layout = alloc::Layout::from_size_align_unchecked(mem::size_of::<c_char>()*size, mem::align_of::<c_char>());
let buffer = alloc::alloc(layout) as *mut c_char;
let errcode = (self.dll.convert)(self.instance, kanji2.as_ptr(), buffer, TryFrom::try_from(size)?);
if errcode == 0{
Ok(AqK2Kstr{
content: &mut *(CStr::from_ptr(buffer).to_str()? as *const _ as *mut str),
layout: layout,
})
} else {
Err(Box::new(AqK2Kerr(errcode)))
}
}
}
}
impl<'a> std::ops::Drop for AqK2Kinstance<'a> {
fn drop(&mut self){
unsafe {
(self.dll.release)(self.instance);
}
}
}
unsafe impl<'a> Send for AqK2Kinstance<'a>{}
unsafe impl<'a> Sync for AqK2Kinstance<'a>{}
pub struct AqK2Kstr<'a>{
content: &'a mut str,
layout: alloc::Layout,
}
impl<'a> std::ops::Deref for AqK2Kstr<'a>{
type Target = &'a mut str;
fn deref(&self) -> &Self::Target {
&self.content
}
}
impl<'a> std::ops::DerefMut for AqK2Kstr<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.content
}
}
impl<'a> std::ops::Drop for AqK2Kstr<'a> {
fn drop(&mut self){
unsafe {
alloc::dealloc(&mut self.content.as_bytes_mut()[0] as *mut u8, self.layout);
}
}
}
struct AqK2Kerr(i32);
impl AqK2Kerr{
fn msg(&self) -> &str{
match self.0 {
100 => "その他のエラー, エラーコード: 100",
101 => "関数呼び出し時の引数がNULLになっている, エラーコード: 101",
104 => "初期化されていない(初期化ルーチンが呼ばれていない), エラーコード: 104",
105 => "入力テキストが長すぎる, エラーコード: 105",
106 => "システム辞書データが指定されていない, エラーコード: 106",
107 => "変換できない文字コードが含まれている, エラーコード: 107",
200..=299 => "システム辞書(aqdic.bin)が不正, エラーコード: 200番台",
300..=399 => "ユーザ辞書(aq_user.dic)が不正, エラーコード: 300番台",
_ => "未定義のエラー",
}
}
}
impl std::fmt::Display for AqK2Kerr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl std::fmt::Debug for AqK2Kerr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.msg())
}
}
impl std::error::Error for AqK2Kerr {
fn description(&self) -> &str {
self.msg()
}
}
#[cfg(target_os = "windows")]
fn platform_win() -> bool {
true
}
#[cfg(not(target_os = "windows"))]
fn platform_win() -> bool {
false
}
}