use super::{MidiEffectTarget, MidiSceneTarget};
use serde::{Deserialize, Serialize};
use strum::{Display, EnumDiscriminants, EnumIter};
use crate::asset::scene::color::SceneInstanceColor;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiOutputBinding {
pub name: String,
pub kind: MidiOutputBindingKind,
#[serde(default)]
pub mode: Option<u8>,
}
impl Default for MidiOutputBinding {
fn default() -> Self {
Self {
name: "Output".to_owned(),
kind: MidiOutputBindingKind::Value(MidiValueOutput::default()),
mode: None,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, EnumDiscriminants)]
#[strum_discriminants(name(MidiOutputBindingSelector), derive(Display, EnumIter))]
pub enum MidiOutputBindingKind {
#[strum_discriminants(strum(serialize = "Single Value"))]
Value(MidiValueOutput),
#[strum_discriminants(strum(serialize = "Scene Color Mapping"))]
SceneColorValue(MidiSceneColorValueOutput),
#[strum_discriminants(strum(serialize = "Mackie Meter"))]
Meter(MidiMeterOutput),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
pub struct MidiMeterOutput {
pub strip: u8,
pub source: MidiValueSource,
}
impl MidiMeterOutput {
const MAX_LEVEL: u8 = 12;
pub fn message(&self, value: f32) -> [u8; 2] {
let level = (value.clamp(0.0, 1.0) * f32::from(Self::MAX_LEVEL)).round() as u8;
[0xD0, ((self.strip & 0x07) << 4) | level]
}
}
#[derive(
Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Hash, Default, Display, EnumIter,
)]
pub enum MidiEffectParameter {
#[default]
Opacity,
#[strum(serialize = "Beat Progression")]
BeatProgression,
#[strum(serialize = "Color Shift")]
ColorShift,
#[strum(serialize = "Beat Offset")]
BeatOffset,
#[strum(serialize = "Setting 1")]
Setting0,
#[strum(serialize = "Setting 2")]
Setting1,
#[strum(serialize = "Setting 3")]
Setting2,
#[strum(serialize = "Setting 4")]
Setting3,
#[strum(serialize = "Setting 5")]
Setting4,
#[strum(serialize = "Setting 6")]
Setting5,
}
impl MidiOutputBindingKind {
pub fn source(&self) -> Option<&MidiValueSource> {
match self {
Self::Value(output) => Some(&output.source),
Self::Meter(meter) => Some(&meter.source),
Self::SceneColorValue(_) => None,
}
}
pub fn source_mut(&mut self) -> Option<&mut MidiValueSource> {
match self {
Self::Value(output) => Some(&mut output.source),
Self::Meter(meter) => Some(&mut meter.source),
Self::SceneColorValue(_) => None,
}
}
}
impl MidiEffectParameter {
pub fn setting(index: u8) -> Option<Self> {
Some(match index {
0 => Self::Setting0,
1 => Self::Setting1,
2 => Self::Setting2,
3 => Self::Setting3,
4 => Self::Setting4,
5 => Self::Setting5,
_ => return None,
})
}
}
impl Default for MidiOutputBindingKind {
fn default() -> Self {
Self::Value(MidiValueOutput::default())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiValueOutput {
pub status: u8,
pub data1: u8,
pub min: u8,
pub max: u8,
pub active_value: u8,
pub source: MidiValueSource,
}
impl Default for MidiValueOutput {
fn default() -> Self {
Self {
status: 176,
data1: 0,
min: 0,
max: 127,
active_value: 127,
source: MidiValueSource::SelectedSceneOpacity,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default, EnumDiscriminants)]
#[strum_discriminants(
name(MidiValueSourceKind),
derive(Display, EnumIter),
strum(serialize_all = "title_case")
)]
pub enum MidiValueSource {
#[default]
SelectedSceneOpacity,
#[strum_discriminants(strum(serialize = "Selected Scene (Distributed 0-127)"))]
SelectedSceneDistributed,
#[strum_discriminants(strum(serialize = "Selected Effect (Distributed 0-127)"))]
SelectedEffectDistributed,
#[strum_discriminants(strum(serialize = "Selected Scene Opacity Live"))]
SelectedSceneOpacityLive,
#[strum_discriminants(strum(serialize = "Effect Live Value"))]
SelectedSceneEffectLive {
effect: MidiEffectTarget,
parameter: MidiEffectParameter,
},
#[strum_discriminants(strum(serialize = "Effect Selected"))]
EffectSelected {
index: u8,
},
SelectedSceneInputDimmer,
SelectedSceneBeatOffset,
SelectedSceneIgnoreMainDimmer,
SelectedSceneSetOffsetOnFlash,
MainDimmer,
#[strum_discriminants(strum(serialize = "Beat Flank"))]
BeatFlankPulse {
start_beat: f32,
end_beat: f32,
blackout_blink_value: Option<u8>,
},
Blackout {
inverted: bool,
blink: bool,
},
SceneOpacity {
target: MidiSceneTarget,
},
SceneInputDimmer {
target: MidiSceneTarget,
},
SceneBeatOffset {
target: MidiSceneTarget,
},
SceneIgnoreMainDimmer {
target: MidiSceneTarget,
},
SceneSetOffsetOnFlash {
target: MidiSceneTarget,
},
SceneActive {
target: MidiSceneTarget,
},
SceneFlashed {
target: MidiSceneTarget,
},
SceneSelected {
target: MidiSceneTarget,
},
ModeActive {
mode: u8,
},
#[strum_discriminants(strum(serialize = "Scene Effect Setting (n,n) f32"))]
SceneEffectSettingF32 {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
setting_index: u8,
},
#[strum_discriminants(strum(serialize = "Effect Opacity"))]
SceneEffectOpacity {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
#[strum_discriminants(strum(serialize = "Effect Color Shift"))]
SceneEffectColorShift {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
#[strum_discriminants(strum(serialize = "Effect Beat Progression"))]
SceneEffectBeatProgression {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
#[strum_discriminants(strum(serialize = "Effect Beat Offset"))]
SceneEffectBeatOffset {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
#[strum_discriminants(strum(serialize = "Effect Speed Exponent"))]
SceneEffectSpeedExponent {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
#[serde(alias = "SceneEffectGroupIndex")]
#[strum_discriminants(strum(serialize = "Effect Layout"))]
SceneEffectLayout {
target: MidiSceneTarget,
#[serde(rename = "effect_index")]
effect: MidiEffectTarget,
},
}
impl Eq for MidiValueSource {}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Display)]
pub enum MidiColorSource {
#[strum(serialize = "Scene Color")]
SceneColor { target: MidiSceneTarget },
}
impl Default for MidiColorSource {
fn default() -> Self {
Self::SceneColor {
target: MidiSceneTarget::Selected,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiSceneColorValueOutput {
pub source: MidiColorSource,
pub mapping_name: String,
pub status: u8,
pub data1: u8,
}
impl Default for MidiSceneColorValueOutput {
fn default() -> Self {
Self {
source: MidiColorSource::default(),
mapping_name: String::new(),
status: 144,
data1: 0,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiNamedSceneColorMapping {
pub name: String,
pub active: MidiSceneColorMessageMap,
pub inactive: MidiSceneColorMessageMap,
pub flashed: MidiSceneColorMessageMap,
}
impl Default for MidiNamedSceneColorMapping {
fn default() -> Self {
let default_map = MidiSceneColorMessageMap::default();
Self {
name: "Color Mapping".to_owned(),
active: default_map.clone(),
inactive: default_map.clone(),
flashed: default_map,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
pub struct MidiSceneColorMessage {
pub value: u8,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiSceneColorMessageMap {
pub red: MidiSceneColorMessage,
pub green: MidiSceneColorMessage,
pub blue: MidiSceneColorMessage,
pub white: MidiSceneColorMessage,
pub orange: MidiSceneColorMessage,
pub yellow: MidiSceneColorMessage,
pub purple: MidiSceneColorMessage,
pub pink: MidiSceneColorMessage,
pub black: MidiSceneColorMessage,
}
impl Default for MidiSceneColorMessageMap {
fn default() -> Self {
Self {
red: MidiSceneColorMessage { value: 5 },
green: MidiSceneColorMessage { value: 21 },
blue: MidiSceneColorMessage { value: 45 },
white: MidiSceneColorMessage { value: 3 },
orange: MidiSceneColorMessage { value: 9 },
yellow: MidiSceneColorMessage { value: 13 },
purple: MidiSceneColorMessage { value: 49 },
pink: MidiSceneColorMessage { value: 53 },
black: MidiSceneColorMessage { value: 0 },
}
}
}
impl MidiSceneColorMessageMap {
pub fn message_for_color(&self, color: SceneInstanceColor) -> &MidiSceneColorMessage {
match color {
SceneInstanceColor::Red => &self.red,
SceneInstanceColor::Green => &self.green,
SceneInstanceColor::Blue => &self.blue,
SceneInstanceColor::White => &self.white,
SceneInstanceColor::Orange => &self.orange,
SceneInstanceColor::Yellow => &self.yellow,
SceneInstanceColor::Purple => &self.purple,
SceneInstanceColor::Pink => &self.pink,
SceneInstanceColor::Black => &self.black,
}
}
}