use alloc::{borrow::Cow, string::ToString, vec::Vec};
use core::fmt::Write;
use crate::{
Element, Serialize, SerializeOptions, XmlWriter,
unit::{Decibels, SpeedFormatter, TimeDesignation},
util
};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AudioRepeat {
Times(f32),
Duration(TimeDesignation)
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Audio<'s> {
src: Cow<'s, str>,
desc: Option<Cow<'s, str>>,
alternate: Vec<Element<'s>>,
clip: (Option<TimeDesignation>, Option<TimeDesignation>),
repeat: Option<AudioRepeat>,
sound_level: Option<Decibels>,
speed: Option<f32>
}
impl<'s> Audio<'s> {
pub fn new(src: impl Into<Cow<'s, str>>) -> Self {
Audio { src: src.into(), ..Audio::default() }
}
pub fn src(&self) -> &str {
&self.src
}
pub fn set_src(&mut self, src: impl Into<Cow<'s, str>>) {
self.src = src.into();
}
pub fn with_alternate<S: Into<Element<'s>>, I: IntoIterator<Item = S>>(mut self, elements: I) -> Self {
self.alternate.extend(elements.into_iter().map(|f| f.into()));
self
}
pub fn with_desc(mut self, desc: impl Into<Cow<'s, str>>) -> Self {
self.desc = Some(desc.into());
self
}
pub fn desc(&self) -> Option<&str> {
self.desc.as_deref()
}
pub fn set_desc(&mut self, desc: impl Into<Cow<'s, str>>) {
self.desc = Some(desc.into());
}
pub fn take_desc(&mut self) -> Option<Cow<'s, str>> {
self.desc.take()
}
pub fn with_clip(mut self, begin: impl Into<TimeDesignation>, end: impl Into<TimeDesignation>) -> Self {
self.clip = (Some(begin.into()), Some(end.into()));
self
}
pub fn with_clip_begin(mut self, begin: impl Into<TimeDesignation>) -> Self {
self.clip.0 = Some(begin.into());
self
}
pub fn clip_begin(&self) -> Option<&TimeDesignation> {
self.clip.0.as_ref()
}
pub fn set_clip_begin(&mut self, begin: impl Into<TimeDesignation>) {
self.clip.0 = Some(begin.into());
}
pub fn take_clip_begin(&mut self) -> Option<TimeDesignation> {
self.clip.0.take()
}
pub fn with_clip_end(mut self, end: impl Into<TimeDesignation>) -> Self {
self.clip.1 = Some(end.into());
self
}
pub fn clip_end(&self) -> Option<&TimeDesignation> {
self.clip.1.as_ref()
}
pub fn set_clip_end(&mut self, end: impl Into<TimeDesignation>) {
self.clip.1 = Some(end.into());
}
pub fn take_clip_end(&mut self) -> Option<TimeDesignation> {
self.clip.1.take()
}
pub fn with_repeat(mut self, repeat: AudioRepeat) -> Self {
self.repeat = Some(repeat);
self
}
pub fn repeat(&self) -> Option<&AudioRepeat> {
self.repeat.as_ref()
}
pub fn set_repeat(&mut self, repeat: AudioRepeat) {
self.repeat = Some(repeat);
}
pub fn take_repeat(&mut self) -> Option<AudioRepeat> {
self.repeat.take()
}
pub fn with_sound_level(mut self, db: impl Into<Decibels>) -> Self {
self.sound_level = Some(db.into());
self
}
pub fn sound_level(&self) -> Option<&Decibels> {
self.sound_level.as_ref()
}
pub fn set_sound_level(&mut self, db: impl Into<Decibels>) {
self.sound_level = Some(db.into());
}
pub fn take_sound_level(&mut self) -> Option<Decibels> {
self.sound_level.take()
}
pub fn with_speed(mut self, speed: f32) -> Self {
self.speed = Some(speed);
self
}
pub fn speed(&self) -> Option<f32> {
self.speed
}
pub fn set_speed(&mut self, speed: f32) {
self.speed = Some(speed.into());
}
pub fn take_speed(&mut self) -> Option<f32> {
self.speed.take()
}
pub fn alternate(&self) -> &[Element<'s>] {
&self.alternate
}
pub fn alternate_mut(&mut self) -> &mut Vec<Element<'s>> {
&mut self.alternate
}
pub fn to_owned(&self) -> Audio<'static> {
self.clone().into_owned()
}
pub fn into_owned(self) -> Audio<'static> {
Audio {
src: match self.src {
Cow::Borrowed(b) => Cow::Owned(b.to_string()),
Cow::Owned(b) => Cow::Owned(b)
},
desc: match self.desc {
Some(Cow::Borrowed(b)) => Some(Cow::Owned(b.to_string())),
Some(Cow::Owned(b)) => Some(Cow::Owned(b)),
None => None
},
alternate: self.alternate.into_iter().map(Element::into_owned).collect(),
clip: self.clip,
repeat: self.repeat,
sound_level: self.sound_level,
speed: self.speed
}
}
}
impl<'s> Serialize for Audio<'s> {
fn serialize_xml<W: Write>(&self, writer: &mut XmlWriter<W>, options: &SerializeOptions) -> crate::Result<()> {
writer.element("audio", |writer| {
writer.attr("src", &*self.src)?;
writer.attr_opt("clipBegin", self.clip.0.as_ref())?;
writer.attr_opt("clipEnd", self.clip.1.as_ref())?;
if let Some(repeat) = &self.repeat {
match repeat {
AudioRepeat::Duration(dur) => writer.attr("repeatDur", dur)?,
AudioRepeat::Times(times) => writer.attr("times", times)?
}
}
writer.attr_opt("soundLevel", self.sound_level.as_ref().map(|t| t))?;
writer.attr_opt("speed", self.speed.map(|s| SpeedFormatter(s)))?;
if let Some(desc) = &self.desc {
writer.element("desc", |writer| writer.text(desc))?;
}
util::serialize_elements(writer, &self.alternate, options)?;
Ok(())
})?;
Ok(())
}
}
pub fn audio<'s>(src: impl Into<Cow<'s, str>>) -> Audio<'s> {
Audio::new(src)
}