use crate::midi::state::MidiState;
pub(super) fn scale_to_range(value: f32, min: u8, max: u8) -> u8 {
let min = f32::from(min);
let max = f32::from(max);
let value = value.clamp(0.0, 1.0);
(min + (max - min) * value).round() as u8
}
pub(super) fn binary_output_value(active: bool, active_value: u8) -> u8 {
if active { active_value } else { 0 }
}
pub(super) fn beat_range_contains(position: f32, start: f32, end: f32) -> bool {
let start = start.rem_euclid(4.0);
let end = end.rem_euclid(4.0);
if start <= end {
position >= start && position <= end
} else {
position >= start || position <= end
}
}
pub(super) fn blackout_output_active(state: &MidiState, inverted: bool, blink: bool) -> bool {
let base_active = if inverted {
!state.blackout
} else {
state.blackout
};
if !base_active || !blink {
return base_active;
}
let beats_per_second = (state.beats_per_minute / 60.0).max(f32::EPSILON);
let elapsed_seconds = state.beat_progression / beats_per_second;
(elapsed_seconds * 2.0).rem_euclid(1.0) < 0.5
}
pub(super) fn distributed_scene_index_from_midi(value: u8, scene_count: usize) -> Option<usize> {
if scene_count == 0 {
return None;
}
Some((((usize::from(value) + 1) * scene_count).saturating_sub(1)) / 128)
}
pub(super) fn value_for_distributed_scene_index(index: usize, scene_count: usize) -> u8 {
if scene_count == 0 {
return 0;
}
for value in 0u8..=127u8 {
if distributed_scene_index_from_midi(value, scene_count) == Some(index) {
let mut last = value;
for candidate in value..=127u8 {
if distributed_scene_index_from_midi(candidate, scene_count) == Some(index) {
last = candidate;
} else {
break;
}
}
return ((u16::from(value) + u16::from(last)) / 2) as u8;
}
}
if scene_count <= 1 {
return 0;
}
((index.min(scene_count - 1) * 127) / (scene_count - 1)) as u8
}