use super::code::ToneCode;
use super::music::Music;
pub struct ToneSynth {
code: ToneCode,
music: Option<Music>,
delay: f64,
next_sample: u64,
}
impl ToneSynth {
pub fn new(code: ToneCode, delay_seconds: f64) -> Self {
ToneSynth {
code,
music: None,
delay: delay_seconds,
next_sample: 0,
}
}
pub fn with_music(mut self) -> Self {
self.music = Music::new(&self.code);
self
}
pub fn starting_at(mut self, sample: u64) -> Self {
self.next_sample = sample;
self
}
pub fn has_music(&self) -> bool {
self.music.is_some()
}
pub fn position(&self) -> u64 {
self.next_sample
}
pub fn fill(&mut self, out: &mut [f32]) {
let rate = f64::from(self.code.sample_rate());
for (i, sample) in out.iter_mut().enumerate() {
let t = (self.next_sample + i as u64) as f64 / rate - self.delay;
let music = self.music.as_ref().map_or(0.0, |m| m.signal_at(t));
*sample = (self.code.signal_at(t) + music) as f32;
}
self.next_sample += out.len() as u64;
}
}
pub fn synthesize(code: &ToneCode, delay_seconds: f64, start: u64, count: usize) -> Vec<f32> {
let mut synth = ToneSynth::new(code.clone(), delay_seconds).starting_at(start);
let mut out = vec![0.0; count];
synth.fill(&mut out);
out
}