use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_time::{Time, TimeSystems};
use firewheel::clock::{DurationSeconds, InstantSeconds};
use std::time::Duration;
use crate::context::AudioContext;
pub(crate) struct TimePlugin;
impl Plugin for TimePlugin {
fn build(&self, app: &mut App) {
app.init_resource::<Time<Audio>>()
.add_systems(First, update_time.in_set(TimeSystems));
}
}
#[derive(Debug, Default)]
pub struct Audio {
instant: InstantSeconds,
}
impl Audio {
pub fn instant(&self) -> InstantSeconds {
self.instant
}
}
fn update_time(mut time: ResMut<Time<Audio>>, context: Option<ResMut<AudioContext>>) {
let Some(mut context) = context else {
return;
};
let last = time.context().instant;
let now = context.now();
let delta = (now.seconds.0 - last.0).max(0.0);
let delta = Duration::from_secs_f64(delta);
time.advance_by(delta);
time.context_mut().instant = now.seconds;
}
pub trait AudioTime {
fn now(&self) -> InstantSeconds;
fn delay(&self, duration: DurationSeconds) -> InstantSeconds;
fn render_range(&self) -> core::ops::Range<InstantSeconds>;
}
impl AudioTime for Time<Audio> {
fn now(&self) -> InstantSeconds {
self.context().instant()
}
fn delay(&self, duration: DurationSeconds) -> InstantSeconds {
self.now() + duration
}
fn render_range(&self) -> core::ops::Range<InstantSeconds> {
let now = self.context().instant();
let last = self.delta_secs_f64();
InstantSeconds(now.0 - last)..now
}
}