From e89886382dba555fae968b30714a41ffc05a66d8 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Wed, 22 Jul 2026 12:48:49 -0700 Subject: [PATCH] Limit set of active audio cells to only those enabled --- life/src/main.rs | 56 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/life/src/main.rs b/life/src/main.rs index ae9e326..c304b25 100644 --- a/life/src/main.rs +++ b/life/src/main.rs @@ -56,7 +56,6 @@ fn main() { load_audio_tones, load_materials, load_meshes, - spawn_audio_players.after(load_audio_tones), ), ) .configure_sets( @@ -111,7 +110,14 @@ fn main() { .add_systems( Update, ( - control_audio_players.run_if(any_component_changed::.or_else(state_changed::).or_else(state_changed::)).in_set(GameSet::React), + control_audio_players + .run_if( + on_message:: + .or_else(state_changed::) + .or_else(state_changed::), + ) + .in_set(GameSet::React), + manage_audio_players.run_if(resource_changed::), update_pitch_map_resource_ui.run_if(resource_changed::), ), ) @@ -122,6 +128,7 @@ fn main() { grid_gizmo, update_debug_info_coordinates, ( + #[cfg(debug_assertions)] assert_cell_uniqueness .run_if(any_with_component::) .after(update_material), @@ -784,6 +791,7 @@ fn is_ui_hovered(hovered: Query<&Hovered>) -> bool { hovered.iter().any(|Hovered(h)| *h) } +#[cfg(debug_assertions)] fn assert_cell_uniqueness(q: Query<(Entity, &Coordinates), With>) { q.iter().for_each(|(e1, c1)| { q.iter().for_each(|(e2, c2)| { @@ -1231,6 +1239,18 @@ impl PitchMap { // always ensure the notes list is sorted self.notes.sort(); } + + // Return an iterator over all enabled CellPitch values + fn iter_enabled_cell_pitches(&self) -> impl Iterator { + self.notes.iter().flat_map(|n| { + (0..=self.octaves) + .map(|o| o as isize) + .map(|o| o - (o / 2)) + .map(|o| { + CellPitch { note: n.clone(), octave: o } + }) + }) + } } #[test] @@ -1383,15 +1403,35 @@ fn update_camera_position(mut query: Query<(&Coordinates, &mut Transform), With< }); } -// Ordering: first, once, after(load_audio_tones) -fn spawn_audio_players(mut commands: Commands, cell_assets: Res) { +// Run when PitchMap changes to ensure we have just the audio sinks we need +fn manage_audio_players( + mut commands: Commands, + cell_assets: Res, + pitch_map: Res, + current: Query<(Entity, &CellPitch), With>, + mut active: Local>, +) { + *active = pitch_map.iter_enabled_cell_pitches().collect(); CellPitch::iter_all().for_each(|cp| { - let h = cell_assets.pitches.get(&cp).unwrap().clone(); - commands.spawn((AudioPlayer(h), cp, PlaybackSettings::default().muted())); - }); + // The cell is active, ensure it has an audio entity + if active.contains(&cp) { + if !current.iter().any(|(_this_e, this_cp)| *this_cp == cp) { + let h = cell_assets.pitches.get(&cp).unwrap().clone(); + commands.spawn((AudioPlayer(h), cp, PlaybackSettings::default().muted())); + } + } + // The cell is inactive, ensure it does not have an audio entity + else { + if let Some(e) = current + .iter() + .find_map(|(this_e, this_cp)| (*this_cp == cp).then_some(this_e)) + { + commands.entity(e).despawn(); + } + } + }) } -// Ordering: React fn control_audio_players( audio_state: Res>, simulation_state: Res>,