1use std::ffi::NulError;
12
13use libc::c_void;
14
15pub mod sys;
16
17pub type SAMAudio = Vec<u8>;
19
20pub enum TTSError {
22 ContainsNull,
24 Code(i32)
26}
27
28impl From<NulError> for TTSError {
30 fn from(_value: NulError) -> Self {
31 TTSError::ContainsNull
32 }
33}
34
35pub fn set_speech_values(
37 pitch: Option<u8>,
38 speed: Option<u8>,
39 throat: Option<u8>,
40 mouth: Option<u8>,
41) {
42 unsafe {
43 sys::setupSpeak(
44 pitch.unwrap_or(0),
45 speed.unwrap_or(0),
46 throat.unwrap_or(0),
47 mouth.unwrap_or(0),
48 )
49 }
50}
51
52unsafe fn render_chunk(chunk: &str) -> Result<Vec<u8>,TTSError> {
55 let mut bytes: Vec<i8> = chunk.bytes().map(|b|{std::mem::transmute(b)}).collect();
56 bytes.push(0);
57 let ptr = sys::speakText(bytes.as_mut_ptr());
58 let res = ptr.read();
59 if res.res != 1 {
60 libc::free(ptr as *mut c_void);
61 return Err(TTSError::Code(res.res))
62 }
63 let buf = std::slice::from_raw_parts(res.buf, res.buf_size as usize);
64 buf.into_iter().map(|b|std::mem::transmute(b)).collect()
65}
66
67pub fn speak_words(tospeak: &str) -> Result<SAMAudio, TTSError> {
69 let bytes: Vec<u8> = if tospeak.len()<=255 {
70 unsafe {render_chunk(tospeak)?}
71 } else {
72 let words = tospeak.split(' ');
73 let mut small = vec![];
74 let mut result: Vec<u8> = vec![];
75 for word in words {
76 if small.iter().map(|x:&&str| {x.len() }).fold(0,|acc, x| acc + x)+word.len() <= 255 {
77 small.push(word);
78 } else {
79 result.append(&mut unsafe {render_chunk(small.join(" ").as_str())?})
80 }
81 };
82 result.append(&mut unsafe {render_chunk(small.join(" ").as_str())?});
83 result
84 };
85 Ok(bytes)
86}