diff --git a/life/src/main.rs b/life/src/main.rs index 9025361..469f18d 100644 --- a/life/src/main.rs +++ b/life/src/main.rs @@ -1,9 +1,11 @@ // TODO: -// * Lock down system scheduling/run_if conditions // * Performance: have a limit on per-note+octave sounds // * Use a finite set of N audio entities and scale volume instead of // spawning a bunch of audio entities which is causing issues at >100 // cells +// * Volume slider +// * Invert mute/unmute icons +// * Only move camera when cells move out of view // * Stop creating cells when I didn't mean to (clicking UI, click + dragging) // * Keep some controls open when main ui panel is closed // * Exclude power button from web build @@ -52,6 +54,7 @@ fn main() { load_audio_tones, load_materials, load_meshes, + spawn_audio_players.after(load_audio_tones), ), ) .configure_sets( @@ -106,14 +109,8 @@ fn main() { .add_systems( Update, ( - control_volume, + control_audio_players.in_set(GameSet::React), update_pitch_map_resource_ui.run_if(resource_changed::), - update_audio - .run_if( - any_component_added:: - .or_else(any_component_changed::), - ) - .in_set(GameSet::React), ), ) // Debugging @@ -125,8 +122,7 @@ fn main() { ( assert_cell_uniqueness .run_if(any_with_component::) - .after(update_material) - .after(update_audio), + .after(update_material), update_debug_info_cell_count, update_debug_info_active, ) @@ -928,7 +924,6 @@ fn new_cell( template_value(playback_settings) template_value(Transform::from_translation(c.as_translation() + Vec3::new(0.0, 0.0, 1.0))) template_value(Mesh2dTemplate(cell_assets.mesh.clone().into())) - // AudioPlayer added by update_audio // MeshMaterial2d added by update_material template_value(MeshMaterial2dTemplate(cell_assets.materials.get(&cell_pitch).unwrap().clone().into())) } @@ -1121,32 +1116,6 @@ fn load_audio_tones(mut pitches: ResMut>, mut cell_assets: ResMut< debug_assert_eq!(cell_assets.pitches.iter().len(), 132); } -fn control_volume( - audio_state: Res>, - simulation_state: Res>, - mut sinks: Query<&mut AudioSink>, -) { - match audio_state.get() { - AudioPlayback::Play => match simulation_state.get() { - SimulationPlayback::Run => { - let ratio = 1.0 / sinks.count() as f32; - let volume = Volume::Linear(ratio); - sinks.par_iter_mut().for_each(|mut sink| { - sink.set_volume(volume); - }) - } - SimulationPlayback::Pause | SimulationPlayback::Step => { - sinks.par_iter_mut().for_each(|mut sink| { - sink.mute(); - }) - } - }, - AudioPlayback::Mute => sinks.par_iter_mut().for_each(|mut sink| { - sink.mute(); - }), - } -} - fn load_materials( server: ResMut, mut cell_assets: ResMut, @@ -1332,18 +1301,6 @@ fn update_material( }) } -// When CellPitch is added/updated on a cell, update the Pitch -fn update_audio( - mut query: Query<(&CellPitch, Entity), Or<(Added, Changed)>>, - cell_assets: ResMut, - mut commands: Commands, -) { - query.iter_mut().for_each(|(cell_pitch, e)| { - let h = cell_assets.pitches.get(cell_pitch).unwrap().clone(); - commands.entity(e).insert(AudioPlayer(h)); - }); -} - fn update_debug_info_cell_count(query: Query<&Cell>, mut text: Query<(&DebugInfo, &mut Text)>) { text.iter_mut() .filter(|(di, _)| **di == DebugInfo::CellCount) @@ -1452,3 +1409,70 @@ fn update_camera_position(mut query: Query<(&Coordinates, &mut Transform), With< t.translation = c.as_translation(); }); } + +// Ordering: first, once, after(load_audio_tones) +fn spawn_audio_players(mut commands: Commands, cell_assets: Res) { + CellPitch::iter_all().for_each(|cp| { + let h = cell_assets.pitches.get(&cp).unwrap().clone(); + commands.spawn((AudioPlayer(h), cp, PlaybackSettings::default().with_volume(Volume::Linear(0.0)))); + }); +} + +// Ordering: React +fn control_audio_players( + audio_state: Res>, + simulation_state: Res>, + mut players: Query<(&mut AudioSink, &CellPitch)>, + cells: Query<&CellPitch, With>, +) { + match audio_state.get() { + AudioPlayback::Play => { + match simulation_state.get() { + SimulationPlayback::Run => { + let mut s: HashMap = HashMap::new(); + + cells.iter().for_each(|cp| { + let this = s.entry(cp.clone()).or_insert(0); + *this += 1; + }); + + let total: usize = s.values().sum(); + + players.iter_mut().for_each(|(mut sink, cp)| { + match s.get(cp) { + Some(v) => { + let new_volume: f32 = (*v as f64 / total as f64) as f32; + debug!("Setting volume for {:?} to {:?}", cp, new_volume); + if sink.is_paused() { + sink.play(); + } + sink.set_volume(Volume::Linear(new_volume)); + }, + None => { + sink.pause(); + sink.set_volume(Volume::Linear(0.0)); + } + } + }); + // create distribution of cell pitches + // then go back and adjust volume based on % with this CellPitch + // if volume is 0, pause + // if volume > 0, play + }, + // If the sim is paused or stepping, mute an dpause audios + _ => { + players.iter_mut().for_each(|(mut sink, _)| { + sink.pause(); + sink.set_volume(Volume::Linear(0.0)); + }); + } + } + } + AudioPlayback::Mute => { + players.iter_mut().for_each(|(mut sink, _)| { + sink.pause(); + sink.set_volume(Volume::Linear(0.0)); + }); + }, + } +}