|
|
|
@ -1,9 +1,11 @@
|
|
|
|
// TODO:
|
|
|
|
// TODO:
|
|
|
|
// * Lock down system scheduling/run_if conditions
|
|
|
|
|
|
|
|
// * Performance: have a limit on per-note+octave sounds
|
|
|
|
// * Performance: have a limit on per-note+octave sounds
|
|
|
|
// * Use a finite set of N audio entities and scale volume instead of
|
|
|
|
// * 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
|
|
|
|
// spawning a bunch of audio entities which is causing issues at >100
|
|
|
|
// cells
|
|
|
|
// 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)
|
|
|
|
// * Stop creating cells when I didn't mean to (clicking UI, click + dragging)
|
|
|
|
// * Keep some controls open when main ui panel is closed
|
|
|
|
// * Keep some controls open when main ui panel is closed
|
|
|
|
// * Exclude power button from web build
|
|
|
|
// * Exclude power button from web build
|
|
|
|
@ -52,6 +54,7 @@ fn main() {
|
|
|
|
load_audio_tones,
|
|
|
|
load_audio_tones,
|
|
|
|
load_materials,
|
|
|
|
load_materials,
|
|
|
|
load_meshes,
|
|
|
|
load_meshes,
|
|
|
|
|
|
|
|
spawn_audio_players.after(load_audio_tones),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.configure_sets(
|
|
|
|
.configure_sets(
|
|
|
|
@ -106,14 +109,8 @@ fn main() {
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
control_volume,
|
|
|
|
control_audio_players.in_set(GameSet::React),
|
|
|
|
update_pitch_map_resource_ui.run_if(resource_changed::<PitchMap>),
|
|
|
|
update_pitch_map_resource_ui.run_if(resource_changed::<PitchMap>),
|
|
|
|
update_audio
|
|
|
|
|
|
|
|
.run_if(
|
|
|
|
|
|
|
|
any_component_added::<CellPitch>
|
|
|
|
|
|
|
|
.or_else(any_component_changed::<CellPitch>),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.in_set(GameSet::React),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Debugging
|
|
|
|
// Debugging
|
|
|
|
@ -125,8 +122,7 @@ fn main() {
|
|
|
|
(
|
|
|
|
(
|
|
|
|
assert_cell_uniqueness
|
|
|
|
assert_cell_uniqueness
|
|
|
|
.run_if(any_with_component::<Cell>)
|
|
|
|
.run_if(any_with_component::<Cell>)
|
|
|
|
.after(update_material)
|
|
|
|
.after(update_material),
|
|
|
|
.after(update_audio),
|
|
|
|
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
update_debug_info_active,
|
|
|
|
update_debug_info_active,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
@ -928,7 +924,6 @@ fn new_cell(
|
|
|
|
template_value(playback_settings)
|
|
|
|
template_value(playback_settings)
|
|
|
|
template_value(Transform::from_translation(c.as_translation() + Vec3::new(0.0, 0.0, 1.0)))
|
|
|
|
template_value(Transform::from_translation(c.as_translation() + Vec3::new(0.0, 0.0, 1.0)))
|
|
|
|
template_value(Mesh2dTemplate(cell_assets.mesh.clone().into()))
|
|
|
|
template_value(Mesh2dTemplate(cell_assets.mesh.clone().into()))
|
|
|
|
// AudioPlayer added by update_audio
|
|
|
|
|
|
|
|
// MeshMaterial2d added by update_material
|
|
|
|
// MeshMaterial2d added by update_material
|
|
|
|
template_value(MeshMaterial2dTemplate(cell_assets.materials.get(&cell_pitch).unwrap().clone().into()))
|
|
|
|
template_value(MeshMaterial2dTemplate(cell_assets.materials.get(&cell_pitch).unwrap().clone().into()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1121,32 +1116,6 @@ fn load_audio_tones(mut pitches: ResMut<Assets<Pitch>>, mut cell_assets: ResMut<
|
|
|
|
debug_assert_eq!(cell_assets.pitches.iter().len(), 132);
|
|
|
|
debug_assert_eq!(cell_assets.pitches.iter().len(), 132);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn control_volume(
|
|
|
|
|
|
|
|
audio_state: Res<State<AudioPlayback>>,
|
|
|
|
|
|
|
|
simulation_state: Res<State<SimulationPlayback>>,
|
|
|
|
|
|
|
|
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(
|
|
|
|
fn load_materials(
|
|
|
|
server: ResMut<AssetServer>,
|
|
|
|
server: ResMut<AssetServer>,
|
|
|
|
mut cell_assets: ResMut<CellAssets>,
|
|
|
|
mut cell_assets: ResMut<CellAssets>,
|
|
|
|
@ -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<CellPitch>, Changed<CellPitch>)>>,
|
|
|
|
|
|
|
|
cell_assets: ResMut<CellAssets>,
|
|
|
|
|
|
|
|
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)>) {
|
|
|
|
fn update_debug_info_cell_count(query: Query<&Cell>, mut text: Query<(&DebugInfo, &mut Text)>) {
|
|
|
|
text.iter_mut()
|
|
|
|
text.iter_mut()
|
|
|
|
.filter(|(di, _)| **di == DebugInfo::CellCount)
|
|
|
|
.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();
|
|
|
|
t.translation = c.as_translation();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ordering: first, once, after(load_audio_tones)
|
|
|
|
|
|
|
|
fn spawn_audio_players(mut commands: Commands, cell_assets: Res<CellAssets>) {
|
|
|
|
|
|
|
|
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<State<AudioPlayback>>,
|
|
|
|
|
|
|
|
simulation_state: Res<State<SimulationPlayback>>,
|
|
|
|
|
|
|
|
mut players: Query<(&mut AudioSink, &CellPitch)>,
|
|
|
|
|
|
|
|
cells: Query<&CellPitch, With<Cell>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
match audio_state.get() {
|
|
|
|
|
|
|
|
AudioPlayback::Play => {
|
|
|
|
|
|
|
|
match simulation_state.get() {
|
|
|
|
|
|
|
|
SimulationPlayback::Run => {
|
|
|
|
|
|
|
|
let mut s: HashMap<CellPitch, usize> = 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));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|