1
0
mirror of https://github.com/ndarilek/tts-rs.git synced 2024-11-17 12:39:36 +00:00
This commit is contained in:
Nolan Darilek 2020-09-02 16:03:08 -05:00
commit dac58539c9
8 changed files with 116 additions and 20 deletions

View File

@ -6,7 +6,6 @@ on:
- "v*"
jobs:
build_linux:
name: Build Linux
runs-on: ubuntu-latest
@ -15,6 +14,7 @@ jobs:
- run: |
sudo apt-get update
sudo apt-get install -y libspeechd-dev
rustup update
cargo build --release
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
@ -26,6 +26,7 @@ jobs:
- uses: actions/checkout@v2
- run: |
choco install -y llvm
rustup update
cargo build --release
build_macos:
@ -34,8 +35,20 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: |
rustup update
cargo build --release
build_ios:
name: Build iOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: |
rustup update
rustup target add aarch64-apple-ios x86_64-apple-ios
cargo install cargo-lipo
cargo lipo --release
publish_winrt_bindings:
name: Publish winrt_bindings
runs-on: windows-latest
@ -46,10 +59,11 @@ jobs:
- uses: actions/checkout@v2
- run: |
choco install -y llvm
rustup update
cargo login $CARGO_TOKEN
cd winrt_bindings
cargo package
cargo publish
cargo publish || true
publish:
name: Publish
@ -62,5 +76,6 @@ jobs:
- run: |
sudo apt-get update
sudo apt-get install -y libspeechd-dev
rustup update
cargo login $CARGO_TOKEN
cargo publish

View File

@ -5,7 +5,6 @@ on:
pull_request:
jobs:
build_linux:
name: Build Linux
runs-on: ubuntu-latest
@ -14,6 +13,7 @@ jobs:
- run: |
sudo apt-get update
sudo apt-get install -y libspeechd-dev
rustup update
cargo build --release
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
@ -25,6 +25,7 @@ jobs:
- uses: actions/checkout@v2
- run: |
choco install -y llvm
rustup update
cargo build --release
build_macos:
@ -33,7 +34,16 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: |
rustup update
cargo build --release
build_ios:
name: Build iOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: |
rustup update
rustup target add aarch64-apple-ios x86_64-apple-ios
cargo install cargo-lipo
rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios
cargo lipo --release

View File

@ -1,6 +1,6 @@
[package]
name = "tts"
version = "0.5.0"
version = "0.6.2"
authors = ["Nolan Darilek <nolan@thewordnerd.info>"]
repository = "https://github.com/ndarilek/tts-rs"
description = "High-level Text-To-Speech (TTS) interface"
@ -12,6 +12,7 @@ edition = "2018"
crate-type = ["lib", "staticlib"]
[dependencies]
lazy_static = "1"
log = "0.4"
thiserror = "1"
@ -24,7 +25,7 @@ winrt = "0.7"
tts_winrt_bindings = { version = "0.1", path="winrt_bindings" }
[target.'cfg(target_os = "linux")'.dependencies]
speech-dispatcher = "0.4"
speech-dispatcher = "0.6"
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
cocoa-foundation = "0.1"

View File

@ -8,5 +8,5 @@ This library provides a high-level Text-To-Speech (TTS) interface supporting var
* Linux via [Speech Dispatcher](https://freebsoft.org/speechd)
* MacOS
* AppKit on MacOS 10.13 and below
* AVFoundation on MacOS 10.14 and, eventually, iDevices
* WebAssembly
* AVFoundation on MacOS 10.14 and above, and iOS
* WebAssembly

View File

@ -95,9 +95,9 @@ impl Backend for AppKit {
Features {
stop: true,
rate: true,
pitch: false,
volume: true,
is_speaking: true,
..Default::default()
}
}

View File

@ -1,4 +1,8 @@
#[cfg(target_os = "linux")]
use std::collections::HashMap;
use std::sync::Mutex;
use lazy_static::*;
use log::{info, trace};
use speech_dispatcher::*;
@ -6,11 +10,41 @@ use crate::{Backend, Error, Features};
pub struct SpeechDispatcher(Connection);
lazy_static! {
static ref SPEAKING: Mutex<HashMap<u64, bool>> = {
let m: HashMap<u64, bool> = HashMap::new();
Mutex::new(m)
};
}
impl SpeechDispatcher {
pub fn new() -> Self {
info!("Initializing SpeechDispatcher backend");
let connection = speech_dispatcher::Connection::open("tts", "tts", "tts", Mode::Single);
SpeechDispatcher(connection)
let connection = speech_dispatcher::Connection::open("tts", "tts", "tts", Mode::Threaded);
let sd = SpeechDispatcher(connection);
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(sd.0.client_id(), false);
sd.0.on_begin(Some(|_msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, true);
}));
sd.0.on_end(Some(|_msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, false);
}));
sd.0.on_cancel(Some(|_msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, false);
}));
sd.0.on_pause(Some(|_msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, false);
}));
sd.0.on_resume(Some(|_msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, true);
}));
sd
}
}
@ -21,7 +55,7 @@ impl Backend for SpeechDispatcher {
rate: true,
pitch: true,
volume: true,
is_speaking: false,
is_speaking: true,
}
}
@ -98,7 +132,7 @@ impl Backend for SpeechDispatcher {
}
fn normal_volume(&self) -> f32 {
0.
100.
}
fn get_volume(&self) -> Result<f32, Error> {
@ -111,6 +145,15 @@ impl Backend for SpeechDispatcher {
}
fn is_speaking(&self) -> Result<bool, Error> {
unimplemented!()
let speaking = SPEAKING.lock().unwrap();
let is_speaking = speaking.get(&self.0.client_id()).unwrap();
Ok(*is_speaking)
}
}
impl Drop for SpeechDispatcher {
fn drop(&mut self) {
let mut speaking = SPEAKING.lock().unwrap();
speaking.remove(&self.0.client_id());
}
}

View File

@ -22,16 +22,31 @@ impl Backend for Tolk {
fn supported_features(&self) -> Features {
Features {
stop: true,
rate: false,
pitch: false,
volume: false,
is_speaking: false,
..Default::default()
}
}
fn speak(&mut self, text: &str, interrupt: bool) -> Result<(), Error> {
trace!("speak({}, {})", text, interrupt);
self.0.speak(text, interrupt);
const BUFFER_LENGTH: usize = 300;
if text.len() <= BUFFER_LENGTH {
self.0.speak(text, interrupt);
} else {
if interrupt {
self.stop()?;
}
let tokens = text.split_whitespace();
let mut buffer = String::new();
for token in tokens {
if buffer.len() + token.len() > BUFFER_LENGTH {
self.0.speak(buffer, false);
buffer = String::new();
} else {
buffer.push_str(token);
buffer.push(' ');
}
}
}
Ok(())
}

View File

@ -7,7 +7,7 @@
* * Linux via [Speech Dispatcher](https://freebsoft.org/speechd)
* * MacOS
* * AppKit on MacOS 10.13 and below
* * AVFoundation on MacOS 10.14 and, eventually, iDevices
* * AVFoundation on MacOS 10.14 and above, and iOS
* * WebAssembly
*/
@ -48,6 +48,18 @@ pub struct Features {
pub is_speaking: bool,
}
impl Default for Features {
fn default() -> Self {
Self {
stop: false,
rate: false,
pitch: false,
volume: false,
is_speaking: false,
}
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("IO error: {0}")]