use alloc::{borrow::Cow, vec::Vec};
use core::fmt::Write;
use crate::{Element, Serialize, SerializeOptions, XmlWriter, util};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Expression(Cow<'static, str>, f32);
impl Expression {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
Self(name.into(), 1.0)
}
pub fn name(&self) -> &str {
&self.0
}
pub fn degree(&self) -> f32 {
self.1
}
pub fn with_degree(mut self, degree: f32) -> Self {
self.1 = degree.clamp(0.01, 2.0);
self
}
pub fn set_degree(&mut self, degree: f32) {
self.1 = degree.clamp(0.01, 2.0);
}
}
macro_rules! define_expressions {
($($(#[$outer:meta])* $x:ident => $e:expr),*) => {
$(
$(#[$outer])*
///
/// Some voices may not support this expression. See [the Azure docs][ms] for more information.
///
/// [ms]: https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts#voice-styles-and-roles
pub struct $x;
impl From<$x> for Expression {
fn from(_: $x) -> Expression {
Expression(Cow::Borrowed($e), 1.0)
}
}
impl $x {
pub fn with_degree(&self, degree: f32) -> Expression {
Expression(Cow::Borrowed($e), degree.clamp(0.01, 2.0))
}
}
)*
};
}
define_expressions! {
Advertisement => "advertisement_upbeat",
Affectionate => "affectionate",
Angry => "angry",
Assistant => "assistant",
Calm => "calm",
Chat => "chat",
Cheerful => "cheerful",
CustomerService => "customerservice",
Depressed => "depressed",
Disgruntled => "disgruntled",
NarrationDocumentary => "documentary-narration",
Embarrassed => "embarrassed",
Empathetic => "empathetic",
Envious => "envious",
Excited => "excited",
Fearful => "fearful",
Friendly => "friendly",
Gentle => "gentle",
Hopeful => "hopeful",
Lyrical => "lyrical",
NarrationProfessional => "narration-professional",
NarrationRelaxed => "narration-relaxed",
Newscast => "newscast",
NewscastCasual => "newscast-casual",
NewscastFormal => "newscast-formal",
PoetryReading => "poetry-reading",
Sad => "sad",
Serious => "serious",
Shouting => "shouting",
SportsCommentary => "sports_commentary",
SportsCommentaryExcited => "sports_commentary_excited",
Whispering => "whispering",
Terrified => "terrified",
Unfriendly => "unfriendly"
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Express<'s> {
expression: Expression,
children: Vec<Element<'s>>
}
impl<'s> Express<'s> {
pub fn new<S: Into<Element<'s>>, I: IntoIterator<Item = S>>(expression: impl Into<Expression>, elements: I) -> Self {
Self {
expression: expression.into(),
children: elements.into_iter().map(|f| f.into()).collect()
}
}
pub fn expression(&self) -> &Expression {
&self.expression
}
pub fn set_expression(&mut self, expression: impl Into<Expression>) {
self.expression = expression.into();
}
pub fn push(&mut self, element: impl Into<Element<'s>>) {
self.children.push(element.into());
}
pub fn extend<S: Into<Element<'s>>, I: IntoIterator<Item = S>>(&mut self, elements: I) {
self.children.extend(elements.into_iter().map(|f| f.into()));
}
pub fn children(&self) -> &[Element<'s>] {
&self.children
}
pub fn children_mut(&mut self) -> &mut Vec<Element<'s>> {
&mut self.children
}
pub fn into_el(self) -> Element<'s> {
Element::FlavorMSTTS(super::Element::Express(self))
}
}
impl<'s> From<Express<'s>> for crate::Element<'s> {
fn from(value: Express<'s>) -> Self {
value.into_el()
}
}
impl<'s> Serialize for Express<'s> {
fn serialize_xml<W: Write>(&self, writer: &mut XmlWriter<W>, options: &SerializeOptions) -> crate::Result<()> {
writer.element("mstts:express-as", |writer| {
writer.attr("style", &*self.expression.0)?;
writer.attr("styledegree", self.expression.1)?;
util::serialize_elements(writer, &self.children, options)
})
}
}
pub fn express<'s, S: Into<Element<'s>>, I: IntoIterator<Item = S>>(expression: impl Into<Expression>, elements: I) -> Express<'s> {
Express::new(expression, elements)
}