use gled_model::asset::midi_controller::{
MidiColorSource, MidiInputAction, MidiMeterOutput, MidiOutputBindingKind,
MidiSceneColorValueOutput, MidiSceneTarget, MidiValueOutput, MidiValueSource,
};
use super::build::Rule;
use super::controls::{Control, ControlKind};
use super::sentence::action_target;
use super::sources::{live_source, matching_source};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum FeedbackRole {
Light,
MotorFader,
Meter,
Ring,
PadColor,
Value,
}
impl FeedbackRole {
pub(crate) fn label(self) -> &'static str {
match self {
Self::Light => "light shows",
Self::MotorFader => "motor fader follows",
Self::Meter => "meter shows",
Self::Ring => "ring light shows",
Self::PadColor => "pad shows the color of",
Self::Value => "sends",
}
}
pub(crate) fn name(self) -> &'static str {
match self {
Self::Light => "Light",
Self::MotorFader => "Motor fader",
Self::Meter => "Level meter",
Self::Ring => "Ring light",
Self::PadColor => "Pad color",
Self::Value => "Value",
}
}
pub(crate) fn description(self) -> &'static str {
match self {
Self::Light => "The LED on this control",
Self::MotorFader => "The fader moves by itself",
Self::Meter => "The LED meter of this fader's strip",
Self::Ring => "The LEDs around the knob",
Self::PadColor => "The scene's color, through a color mapping",
Self::Value => "Any value, to this control's message",
}
}
}
pub(crate) fn feedback_role(
controls: &[Control],
rule: &Rule,
kind: &MidiOutputBindingKind,
) -> FeedbackRole {
let control = &controls[rule.control];
match kind {
MidiOutputBindingKind::Meter(_) => FeedbackRole::Meter,
MidiOutputBindingKind::SceneColorValue(_) => FeedbackRole::PadColor,
MidiOutputBindingKind::Value(value) => match value.status & 0xF0 {
0xE0 => FeedbackRole::MotorFader,
0xB0 if matches!(control.kind, ControlKind::Knob | ControlKind::Encoder) => {
FeedbackRole::Ring
}
0x80 | 0x90 => FeedbackRole::Light,
_ => FeedbackRole::Value,
},
}
}
pub(crate) fn roles_for(kind: ControlKind) -> &'static [FeedbackRole] {
match kind {
ControlKind::Button => &[FeedbackRole::Light, FeedbackRole::Value],
ControlKind::Pad => &[
FeedbackRole::PadColor,
FeedbackRole::Light,
FeedbackRole::Value,
],
ControlKind::Fader => &[
FeedbackRole::MotorFader,
FeedbackRole::Meter,
FeedbackRole::Value,
],
ControlKind::Knob | ControlKind::Encoder => &[FeedbackRole::Ring, FeedbackRole::Value],
}
}
pub(crate) fn source_for(
role: FeedbackRole,
action: Option<&MidiInputAction>,
) -> Option<MidiValueSource> {
let source = matching_source(action?)?;
Some(match role {
FeedbackRole::Meter => live_source(source),
_ => source,
})
}
pub(crate) fn new_feedback(
control: &Control,
role: FeedbackRole,
source: MidiValueSource,
target: MidiSceneTarget,
mapping_name: &str,
) -> MidiOutputBindingKind {
let channel = control.trigger.status & 0x0F;
let value = |status: u8, data1: u8| {
MidiOutputBindingKind::Value(MidiValueOutput {
status,
data1,
min: 0,
max: 127,
active_value: 127,
source: source.clone(),
})
};
match role {
FeedbackRole::Light | FeedbackRole::Value => value(0x90 | channel, control.trigger.data1),
FeedbackRole::MotorFader => value(0xE0 | channel, 0),
FeedbackRole::Ring => value(0xB0 | channel, control.trigger.data1),
FeedbackRole::Meter => MidiOutputBindingKind::Meter(MidiMeterOutput {
strip: channel & 0x07,
source: source.clone(),
}),
FeedbackRole::PadColor => {
MidiOutputBindingKind::SceneColorValue(MidiSceneColorValueOutput {
source: MidiColorSource::SceneColor { target },
mapping_name: mapping_name.to_owned(),
status: 0x90 | channel,
data1: control.trigger.data1,
})
}
}
}
pub(crate) fn pad_target(action: Option<&MidiInputAction>) -> MidiSceneTarget {
action
.and_then(action_target)
.cloned()
.unwrap_or(MidiSceneTarget::Selected)
}