use crate::audio::TICKS_PER_MS;
use crate::{AUDIO_EFFECT_STATE_MARGIN_MS, AudioEffect, Project};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AudioEffectLoad {
pub effects: usize,
pub effects_at_ticks: i64,
pub delay_ticks: u64,
pub delay_at_ticks: i64,
}
impl AudioEffectLoad {
#[must_use]
pub fn delay_ms(&self) -> u64 {
self.delay_ticks.div_ceil(u64::from(TICKS_PER_MS))
}
}
struct Edge {
at: i64,
ends: bool,
effects: usize,
delay: u64,
}
impl Project {
#[must_use]
pub fn audio_effect_load(&self) -> AudioEffectLoad {
let chain = |effects: &[AudioEffect]| {
(
effects.len(),
effects.iter().map(AudioEffect::delay_ticks).sum::<u64>(),
)
};
let lookahead = |effects: &[AudioEffect]| {
effects
.iter()
.map(AudioEffect::lookahead_ticks)
.sum::<u64>()
};
let margin = u64::from(AUDIO_EFFECT_STATE_MARGIN_MS) * u64::from(TICKS_PER_MS);
let (mut effects, mut delay) = chain(&self.audio.effects);
let mut edges = Vec::new();
for track in &self.timeline.tracks {
let (count, held) = chain(&track.audio.effects);
effects += count;
delay += held;
let track_lookahead = lookahead(&track.audio.effects);
for clip in &track.clips {
if clip.audio.effects.is_empty() {
continue;
}
let (count, held) = chain(&clip.audio.effects);
let lead = track_lookahead + lookahead(&clip.audio.effects) + margin;
let lead = i64::try_from(lead).unwrap_or(i64::MAX);
let range = clip.timeline_range;
edges.push(Edge {
at: range.start().ticks().saturating_sub(lead).max(0),
ends: false,
effects: count,
delay: held,
});
edges.push(Edge {
at: range.end().ticks(),
ends: true,
effects: count,
delay: held,
});
}
}
edges.sort_unstable_by_key(|edge| (edge.at, edge.ends));
let mut load = AudioEffectLoad {
effects,
effects_at_ticks: 0,
delay_ticks: delay,
delay_at_ticks: 0,
};
for edge in edges {
if edge.ends {
effects -= edge.effects;
delay -= edge.delay;
continue;
}
effects += edge.effects;
delay += edge.delay;
if effects > load.effects {
load.effects = effects;
load.effects_at_ticks = edge.at;
}
if delay > load.delay_ticks {
load.delay_ticks = delay;
load.delay_at_ticks = edge.at;
}
}
load
}
}