gled-core 2.31.0

The engine of gled without a user interface: inputs, timing, rendering, Art-Net/DMX output and storage
Documentation
use super::values::{
    distributed_scene_index_from_midi, scale_to_range, value_for_distributed_scene_index,
};
use crate::midi::state::MidiState;
use gled_model::patching::layout::{LayoutRef, LayoutSelection};

/// Regression: the raw stack index went into `scale_to_range`, which
/// clamps to 0–1, so every layout past the topology sent the maximum.
#[test]
fn layout_feedback_sends_the_value_the_input_takes() {
    for (selection, expected) in [
        (None, 0),
        (Some(LayoutSelection::new(LayoutRef::Topology, 0)), 1),
        (Some(LayoutSelection::new(LayoutRef::Layout(1), 1)), 3),
    ] {
        assert_eq!(
            scale_to_range(MidiState::layout_value(selection), 0, 127),
            expected,
            "{selection:?}"
        );
    }
}

/// Feedback sent over the full 0–127 range and played back by the
/// controller picks the layout it reported: inherit, the topology and the
/// layouts each survive the round trip.
#[test]
fn layout_feedback_round_trips_through_the_input() {
    for selection in [
        None,
        Some(LayoutSelection::new(LayoutRef::Topology, 0)),
        Some(LayoutSelection::new(LayoutRef::Layout(0), 0)),
        Some(LayoutSelection::new(LayoutRef::Layout(4), 1)),
    ] {
        let midi_byte = scale_to_range(MidiState::layout_value(selection), 0, 127);
        assert_eq!(
            MidiState::layout_from_midi(midi_byte),
            selection.map(|selection| selection.layout.stack_index()),
            "{selection:?} sent as {midi_byte}"
        );
    }
}

#[test]
fn layout_input_zero_inherits_the_tiles_layout() {
    assert_eq!(MidiState::layout_from_midi(0), None);
}

#[test]
fn layout_input_one_is_the_topology() {
    assert_eq!(
        MidiState::layout_from_midi(1),
        Some(LayoutRef::Topology.stack_index())
    );
}

#[test]
fn distributed_index_covers_first_and_last_scene() {
    assert_eq!(distributed_scene_index_from_midi(0, 5), Some(0));
    assert_eq!(distributed_scene_index_from_midi(127, 5), Some(4));
}

#[test]
fn distributed_value_round_trips_for_reachable_indices() {
    let scene_count = 24;
    for index in 0..scene_count {
        let value = value_for_distributed_scene_index(index, scene_count);
        assert_eq!(
            distributed_scene_index_from_midi(value, scene_count),
            Some(index)
        );
    }
}