use super::{Signal, SoundOrSilence, THRESHOLD, TTSQueueInput};
use anyhow::{Result, anyhow};
use rodio::{Sample, Source, source::Zero};
use std::sync::Arc;
pub struct TTSQueueOutput<T>
where
T: Source + Send + Clone,
{
pub current: SoundOrSilence<T>,
pub current_signal: Signal,
pub index: usize,
pub input: Arc<TTSQueueInput<T>>,
pub is_initial: bool,
}
impl<T> TTSQueueOutput<T>
where
T: Source + Send + Clone,
{
pub fn new(input: Arc<TTSQueueInput<T>>, index: usize) -> Self {
let (sound, signal, is_initial) =
if let Some((sound, signal)) = input.sounds.lock().unwrap().get(index) {
(SoundOrSilence::Sound(sound.clone()), signal.clone(), false)
} else {
let silence = Zero::new_samples(1, 44100, THRESHOLD);
(SoundOrSilence::Silence(silence), None, true)
};
Self {
current: sound,
current_signal: signal,
index,
input,
is_initial,
}
}
pub fn go_next(&mut self) -> Result<()> {
if let Some(sender) = self.current_signal.take() {
sender.try_send(true).ok();
}
let next_index = if self.is_initial {
self.index
} else {
self.index + 1
};
if let Some((sound, signal)) = self.input.sounds.lock().unwrap().get(next_index) {
self.current = SoundOrSilence::Sound(sound.clone());
self.current_signal = signal.clone();
self.index = next_index;
self.is_initial = false;
} else {
if self.input.is_finished() {
return Err(anyhow!("No more sounds in the queue"));
}
let silence = Zero::new_samples(1, 44100, THRESHOLD);
self.current = SoundOrSilence::Silence(silence);
}
if let Some(sender) = &self.current_signal {
sender.try_send(false).ok();
}
Ok(())
}
}
impl<T> Iterator for TTSQueueOutput<T>
where
T: Source + Send + Clone,
{
type Item = Sample;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(sample) = self.current.next() {
return Some(sample);
}
if self.go_next().is_err() {
return None;
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.current.size_hint().0, None)
}
}
impl<T> Source for TTSQueueOutput<T>
where
T: Source + Send + Clone,
{
fn current_span_len(&self) -> Option<usize> {
if let Some(val) = self.current.current_span_len() {
if val != 0 {
return Some(val);
} else if !self.input.is_finished() && self.input.sounds.lock().unwrap().is_empty() {
return Some(THRESHOLD);
}
}
let (lower_bound, _) = self.current.size_hint();
if lower_bound > 0 {
return Some(lower_bound);
}
Some(THRESHOLD)
}
fn channels(&self) -> rodio::ChannelCount {
self.current.channels()
}
fn sample_rate(&self) -> rodio::SampleRate {
self.current.sample_rate()
}
fn total_duration(&self) -> Option<std::time::Duration> {
None
}
}