add the basic text to speech infrastructure.

also creates a method for isolating incompatibly licensed repos
This commit is contained in:
bunnie 2022-03-08 03:08:12 +08:00
parent 3325a96fd4
commit 1d6fbbe5bb
11 changed files with 297 additions and 42 deletions

110
Cargo.lock generated
View file

@ -135,7 +135,7 @@ dependencies = [
"ticktimer-server",
"trng",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -168,7 +168,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -183,7 +183,7 @@ dependencies = [
"rkyv",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -312,7 +312,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -329,7 +329,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -346,7 +346,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -449,7 +449,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -470,7 +470,7 @@ dependencies = [
"typenum",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -713,7 +713,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -769,7 +769,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -924,7 +924,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1010,7 +1010,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1073,7 +1073,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1087,7 +1087,7 @@ dependencies = [
"num-traits",
"rkyv",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1104,7 +1104,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1142,7 +1142,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1191,7 +1191,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1274,7 +1274,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1308,7 +1308,7 @@ dependencies = [
"num-traits",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
]
[[package]]
@ -1384,7 +1384,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1410,7 +1410,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1573,7 +1573,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1836,7 +1836,7 @@ dependencies = [
"ticktimer-server",
"trng",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1900,7 +1900,7 @@ dependencies = [
"rkyv",
"ticktimer-server",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -1948,7 +1948,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
"zeroize",
]
@ -2132,7 +2132,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2176,10 +2176,11 @@ dependencies = [
"susres",
"ticktimer-server",
"trng",
"tts-frontend",
"utralib",
"x25519-dalek",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2259,7 +2260,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2301,7 +2302,7 @@ dependencies = [
"trng",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2334,7 +2335,7 @@ dependencies = [
"rkyv",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2442,7 +2443,7 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
]
[[package]]
@ -2495,7 +2496,7 @@ dependencies = [
"susres",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
@ -2541,10 +2542,27 @@ dependencies = [
"ticktimer-server",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
"xous-names",
]
[[package]]
name = "tts-frontend"
version = "0.1.0"
dependencies = [
"log",
"log-server",
"num-derive",
"num-traits",
"rkyv",
"ticktimer-server",
"utralib",
"xous",
"xous-ipc 0.9.7",
"xous-names",
"xous-tts-backend",
]
[[package]]
name = "typenum"
version = "1.12.0"
@ -2927,6 +2945,17 @@ dependencies = [
"xous",
]
[[package]]
name = "xous-ipc"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9874c4b4dcce5c8fe73351e0bb27e08cc1bf5b58ce621a4c42d1a5cb8869bd87"
dependencies = [
"bitflags",
"rkyv",
"xous",
]
[[package]]
name = "xous-macros"
version = "0.1.0"
@ -2948,7 +2977,20 @@ dependencies = [
"rkyv",
"utralib",
"xous",
"xous-ipc",
"xous-ipc 0.9.7",
]
[[package]]
name = "xous-tts-backend"
version = "0.1.0"
dependencies = [
"log",
"num-derive",
"num-traits",
"rkyv",
"xous",
"xous-ipc 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
"xous-names",
]
[[package]]

View file

@ -90,6 +90,7 @@ members = [
"apps/repl",
"services/libstd-test",
"services/ffi-test",
"services/tts",
"kernel",
]
resolver = "2"
@ -121,6 +122,8 @@ xous-macros = {path = "macros"}
path = "services/engine-sha512"
[patch.crates-io.aes]
path = "services/aes"
[patch.crates-io.xous-names]
path = "services/xous-names"
[patch.crates-io.curve25519-dalek]
git="https://github.com/betrusted-io/curve25519-dalek.git"

View file

@ -3,7 +3,7 @@
# set RUSTFLAGS=--remap-path-prefix=F:\largework\rust-win\code\xous-core\=build
# $env:RUSTFLAGS="--remap-path-prefix=$(Get-Location)=build"
cargo xtask app-image ball repl
cargo xtask tts
# cargo xtask ffi-test
# cargo xtask minimal precursors/soc.svd
@ -12,7 +12,8 @@ CertUtil -hashfile precursors/soc_csr.bin MD5
CertUtil -hashfile target/riscv32imac-unknown-xous-elf/release/loader.bin MD5
CertUtil -hashfile target/riscv32imac-unknown-xous-elf/release/xous.img MD5
scp -i c:/users/bunnie/.ssh/id_pi target/riscv32imac-unknown-xous-elf/release/xous.img target/riscv32imac-unknown-xous-elf/release/loader.bin precursors/soc_csr.bin pi@10.0.245.181:code/precursors/
# scp -i c:/users/bunnie/.ssh/id_pi target/riscv32imac-unknown-xous-elf/release/xous.img target/riscv32imac-unknown-xous-elf/release/loader.bin precursors/soc_csr.bin pi@10.0.245.181:code/precursors/
scp -i c:/users/bunnie/.ssh/id_ed25519 target/riscv32imac-unknown-xous-elf/release/xous.img target/riscv32imac-unknown-xous-elf/release/loader.bin precursors/soc_csr.bin bunnie@10.0.245.9:/mnt/c/Users/bunnie/
# CertUtil -hashfile target/riscv32imac-unknown-none-elf/release/loader.bin MD5
# CertUtil -hashfile target/riscv32imac-unknown-none-elf/release/xous.img MD5

View file

@ -36,6 +36,7 @@ net = {path="../net"}
dns = {path="../dns"}
pddb = {path="../pddb"}
modals = {path="../modals"}
tts-frontend = {path="../tts"}
trng = {path = "../trng"}
@ -76,6 +77,7 @@ utralib = {path = "../../utralib"}
debugprint = []
spinortest = [] # for spinor testing. contra-indicated with PDDB, as it steals memory from the PDDB.
benchmarks = [] # adds the benchmark routines. Left off normally to free up code and memory space.
tts = [] # adds text to speech plugin
default = [] # "debugprint"
[target.'cfg(any(windows,unix))'.dependencies]

View file

@ -102,6 +102,11 @@ mod jtag_cmd; use jtag_cmd::*;
mod net_cmd; use net_cmd::*;
mod pddb_cmd; use pddb_cmd::*;
#[cfg(feature="tts")]
mod tts;
#[cfg(feature="tts")]
use tts::*;
#[cfg(feature="benchmarks")]
mod engine;
#[cfg(feature="benchmarks")]
@ -138,6 +143,9 @@ pub struct CmdEnv {
pddb_cmd: PddbCmd,
wlan_cmd: Wlan,
#[cfg(feature="tts")]
tts_cmd: Tts,
#[cfg(feature="benchmarks")]
sha_cmd: Sha,
#[cfg(feature="benchmarks")]
@ -205,6 +213,9 @@ impl CmdEnv {
pddb_cmd: PddbCmd::new(&xns),
wlan_cmd: Wlan::new(),
#[cfg(feature="tts")]
tts_cmd: Tts::new(&xns),
#[cfg(feature="benchmarks")]
sha_cmd: sha,
#[cfg(feature="benchmarks")]
@ -247,6 +258,9 @@ impl CmdEnv {
&mut self.net_cmd,
&mut self.pddb_cmd,
#[cfg(feature="tts")]
&mut self.tts_cmd,
#[cfg(feature="benchmarks")]
&mut self.sha_cmd,
#[cfg(feature="benchmarks")]

View file

@ -0,0 +1,55 @@
use crate::{ShellCmdApi, CommonEnv};
use xous_ipc::String;
use tts_frontend::*;
use core::fmt::Write;
#[derive(Debug)]
pub struct Tts {
pub fe: TtsFrontend,
}
impl Tts {
pub fn new(xns: &xous_names::XousNames) -> Tts {
Tts {
fe: TtsFrontend::new(xns).unwrap(),
}
}
}
impl<'a> ShellCmdApi<'a> for Tts {
cmd_api!(tts); // inserts boilerplate for command API
fn process(&mut self, args: String::<1024>, env: &mut CommonEnv) -> Result<Option<String::<1024>>, xous::Error> {
let mut ret = String::<1024>::new();
let helpstring = "tts options: speak";
let mut tokens = args.as_str().unwrap().split(' ');
if let Some(sub_cmd) = tokens.next() {
match sub_cmd {
"speak" => {
let mut text = String::<1024>::new();
join_tokens(&mut text, &mut tokens);
self.fe.tts_simple(text.as_str().expect("not valid utf-8")).unwrap();
}
_ => {
write!(ret, "{}", helpstring).unwrap();
}
}
} else {
write!(ret, "{}", helpstring).unwrap();
}
Ok(Some(ret))
}
}
fn join_tokens<'a>(buf: &mut String<1024>, tokens: impl Iterator<Item = &'a str>) {
for (i, tok) in tokens.enumerate() {
if i == 0 {
write!(buf, "{}", tok).unwrap();
} else {
write!(buf, " {}", tok).unwrap();
}
}
}

26
services/tts/Cargo.toml Normal file
View file

@ -0,0 +1,26 @@
[package]
name = "tts-frontend"
version = "0.1.0"
authors = ["bunnie <bunnie@kosagi.com>"]
edition = "2018"
description = "Text to speech integration server"
# Dependency policy: fully specify dependencies to the minor version number
[dependencies]
xous = { path = "../../xous-rs" }
xous-ipc = {path="../../xous-ipc"}
log-server = { path = "../log-server" }
ticktimer-server = { path = "../ticktimer-server" }
xous-names = { path = "../xous-names" }
log = "0.4.14"
num-derive = {version = "0.3.3", default-features = false}
num-traits = {version = "0.2.14", default-features = false}
rkyv = {version = "0.4.3", default-features = false, features = ["const_generics"]}
xous-tts-backend = {path="../../../tts-backend"}
[target.'cfg(not(any(windows,unix)))'.dependencies]
utralib = { path = "../../utralib"}
[features]
tts = []
default = []

16
services/tts/src/api.rs Normal file
View file

@ -0,0 +1,16 @@
pub(crate) const SERVER_NAME_TTS: &str = "_Text to speech front end_";
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
pub(crate) enum Opcode {
/// Basic, synchronous, non-abortable conversion of a string to audible speech
TextToSpeech,
/// Callback for the codec crate
CodecCb,
/// Exits the server
Quit,
}
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct TtsFrontendMsg {
pub text: xous_ipc::String::<2048>,
}

45
services/tts/src/lib.rs Normal file
View file

@ -0,0 +1,45 @@
#![cfg_attr(target_os = "none", no_std)]
pub mod api;
pub use api::*;
use xous::{CID, send_message};
use xous_ipc::Buffer;
use num_traits::ToPrimitive;
#[derive(Debug)]
pub struct TtsFrontend {
conn: CID,
}
impl TtsFrontend {
pub fn new(xns: &xous_names::XousNames) -> Result<Self, xous::Error> {
REFCOUNT.fetch_add(1, Ordering::Relaxed);
let conn = xns.request_connection_blocking(api::SERVER_NAME_TTS).expect("Can't connect to TtsFrontend server");
Ok(TtsFrontend {
conn
})
}
/// A fully synchronous text to speech call. The text is turned into speech and played immediately,
/// with no further synchronization or ability to abort the speech playback.
pub fn tts_simple(&self, text: &str) -> Result<(), xous::Error> {
let msg = TtsFrontendMsg {
text: xous_ipc::String::from_str(text),
};
let buf = Buffer::into_buf(msg).or(Err(xous::Error::InternalError))?;
buf.lend(self.conn, Opcode::TextToSpeech.to_u32().unwrap()).map(|_| ())
}
}
use core::sync::atomic::{AtomicU32, Ordering};
static REFCOUNT: AtomicU32 = AtomicU32::new(0);
impl Drop for TtsFrontend {
fn drop(&mut self) {
// the connection to the server side must be reference counted, so that multiple instances of this object within
// a single process do not end up de-allocating the CID on other threads before they go out of scope.
// Note to future me: you want this. Don't get rid of it because you think, "nah, nobody will ever make more than one copy of this object".
if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
unsafe{xous::disconnect(self.conn).unwrap();}
}
// if there was object-specific state (such as a one-time use server for async callbacks, specific to the object instance),
// de-allocate those items here. They don't need a reference count because they are object-specific
}
}

51
services/tts/src/main.rs Normal file
View file

@ -0,0 +1,51 @@
#![cfg_attr(target_os = "none", no_std)]
#![cfg_attr(target_os = "none", no_main)]
mod api;
use api::*;
use xous_ipc::Buffer;
use num_traits::*;
use xous_tts_backend::*;
#[xous::xous_main]
fn xmain() -> ! {
log_server::init_wait().unwrap();
log::set_max_level(log::LevelFilter::Trace);
log::info!("my PID is {}", xous::process::id());
let xns = xous_names::XousNames::new().unwrap();
let tts_sid = xns.register_name(api::SERVER_NAME_TTS, None).expect("can't register server");
log::trace!("registered with NS -- {:?}", tts_sid);
let tts_be = TtsBackend::new(&xns).unwrap();
loop {
let msg = xous::receive_message(tts_sid).unwrap();
match FromPrimitive::from_usize(msg.body.id()) {
Some(Opcode::TextToSpeech) => {
let buffer = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) };
let msg = buffer.to_original::<TtsFrontendMsg, _>().unwrap();
log::info!("tts front end got string {}", msg.text.as_str().unwrap());
tts_be.tts_simple(msg.text.as_str().unwrap()).unwrap();
},
Some(Opcode::CodecCb) => {
// tbd
},
Some(Opcode::Quit) => {
log::warn!("Quit received, goodbye world!");
break;
},
None => {
log::error!("couldn't convert opcode: {:?}", msg);
}
}
}
// clean up our program
log::trace!("main loop exit, destroying servers");
xns.unregister_server(tts_sid).unwrap();
xous::destroy_server(tts_sid).unwrap();
log::trace!("quitting");
xous::terminate_process(0)
}

View file

@ -201,20 +201,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Some("tts") => {
let mut args = env::args();
args.nth(1);
//let mut pkgs = hw_pkgs.to_vec();
let mut pkgs = gfx_dev_pkgs.to_vec();
let mut pkgs = hw_pkgs.to_vec();
//let mut pkgs = gfx_dev_pkgs.to_vec();
let apps: Vec<String> = args.collect();
for app in &apps {
pkgs.push(app);
}
pkgs.push("tts");
pkgs.push("tts-frontend");
generate_app_menus(&apps);
build_hw_image(false,
Some("./precursors/soc.svd".to_string()),
&pkgs,
lkey, kkey,
None, None,
Some(&["--features", "tts"]), // one thing at a time... "--features", "braille",
&[])?
&["bins/espeak-embedded"], None)?
}
Some("libstd-test") => {
let mut args = env::args();
@ -469,7 +469,7 @@ Various debug configurations:
pddb-hosted PDDB testing in a hosted environment
pddb-ci PDDB config for CI testing (eg: TRNG->deterministic for reproducible errors)
ffi-test builds an image for testing C-FFI bindings and integration
tts builds an image with text to speech support via externally linked C executable
"
)
}