use super::{Action, AdaptiveMusic, LoopBuffer, Scheduled, SectionFade, SoundDoc};
use crate::runtime::AudioSource;
impl AdaptiveMusic {
pub fn add_section(&mut self, name: impl Into<String>, doc: &SoundDoc) -> usize {
self.add_section_buffer(name, LoopBuffer::from_doc_at(doc, self.sample_rate))
}
pub fn add_section_buffer(&mut self, name: impl Into<String>, buffer: LoopBuffer) -> usize {
let index = self.sections.len();
self.sections.push(super::Section {
name: name.into(),
buffer,
});
if self.current_section.is_none() {
self.current_section = Some(index);
}
index
}
pub fn transition_to(&mut self, section: usize, q: super::Quantize) {
if section >= self.sections.len() {
return;
}
self.pending
.retain(|s| !matches!(s.action, Action::Transition { .. }));
if let Some(f) = &self.section_fade {
if f.to == section {
return;
}
if self.current_section == Some(section) {
self.section_fade = Some(SectionFade {
to: f.to,
from_gain: f.from_gain + f.frames_done as f32 * f.step,
step: -f.step,
frames_done: 0,
});
return;
}
}
if self.current_section == Some(section) {
return;
}
self.apply_or_schedule(q, Action::Transition { to: section });
}
pub(super) fn begin_transition(&mut self, to: usize) {
if self.current_section == Some(to) {
return;
}
if self.current_section.is_none() {
self.current_section = Some(to);
return;
}
if let Some(f) = &self.section_fade {
if f.to == to {
return;
}
let g_now = f.from_gain + f.frames_done as f32 * f.step;
let wait = if f.step > 0.0 {
(1.0 - g_now) / f.step
} else {
g_now / -f.step
};
let fire_at = self.position + (wait.ceil().max(0.0) as u64);
self.pending.push(Scheduled {
fire_at,
action: Action::Transition { to },
});
return;
}
self.sections[to].buffer.reset();
self.section_fade = Some(SectionFade {
to,
from_gain: 0.0,
step: self.section_step,
frames_done: 0,
});
}
pub fn current_section(&self) -> Option<usize> {
self.current_section
}
pub fn section_named(&self, name: &str) -> Option<usize> {
self.sections.iter().position(|s| s.name == name)
}
}