use std::time::{Duration, SystemTime, UNIX_EPOCH};
use super::state::MidiState;
use crate::{
storage::asset::project::{deck::DeckPath, scene_instance_path::SceneInstancePath},
ui::action::UiAction,
};
use crossbeam_channel::Receiver;
use midir::MidiOutputConnection;
pub fn handle_input(_stamp: u64, message: &[u8]) {
if message.len() != 3 {
return;
}
let status = message[0];
let data1 = message[1];
let data2 = message[2];
match (status, data1, data2) {
(144, 0..40, 127) => {
let path = match data1 {
0..4 => SceneInstancePath::new(DeckPath::A, data1 as usize + 16),
4..8 => SceneInstancePath::new(DeckPath::B, data1 as usize + 12),
8..12 => SceneInstancePath::new(DeckPath::A, data1 as usize + 4),
12..16 => SceneInstancePath::new(DeckPath::B, data1 as usize),
16..20 => SceneInstancePath::new(DeckPath::A, data1 as usize - 8),
20..24 => SceneInstancePath::new(DeckPath::B, data1 as usize - 12),
24..28 => SceneInstancePath::new(DeckPath::A, data1 as usize - 20),
28..32 => SceneInstancePath::new(DeckPath::B, data1 as usize - 24),
32..36 => SceneInstancePath::new(DeckPath::A, data1 as usize - 32),
36..40 => SceneInstancePath::new(DeckPath::B, data1 as usize - 36),
_ => unreachable!(),
};
UiAction::ToggleSceneActive(path)
}
(128..136, 48 | 52, _) => UiAction::SetSceneActive(
SceneInstancePath::new(DeckPath::C, status as usize - 128),
false,
),
(144..152, 48 | 52, 127) => UiAction::SetSceneActive(
SceneInstancePath::new(DeckPath::C, status as usize - 144),
true,
),
(144, 91, 127) => UiAction::SetBlackout(false),
(128, 91, 127) => UiAction::SetBlackout(true),
(144, 82..=85 | 99, 127) => UiAction::Tap,
(176, 13, value) => {
let delta = if value > 64 {
value as f32 - 128.0
} else {
value as f32
};
UiAction::SpeedAdd(delta)
}
(176, 14, value) => UiAction::SetMainDimmer(f32::from(value) / 127.0),
(176..184, 7, value) => UiAction::SetSceneOpacity(
SceneInstancePath::new(DeckPath::C, status as usize - 176),
f32::from(value) / 127.0,
),
(144, 100 | 101, 127) => UiAction::SpeedMultiply(match data1 {
100 => 0.5,
101 => 2.0,
_ => unreachable!(),
}),
(176, 15, value) => UiAction::SetCrossFader(f32::from(value) / 127.0),
_ => {
return;
}
}
.enqueue();
}
pub fn send_output(state_receiver: Receiver<MidiState>, mut connection: MidiOutputConnection) {
log::trace!("Resetting all lights..");
for on in [true, false] {
for j in 0x90..0x99 {
for i in 0..127 {
if let Err(err) = connection.send(&[j, i, if on { 30 } else { 0 }, 127]) {
log::error!("Could not send value: {err:?}")
}
std::thread::sleep(Duration::from_micros(200));
}
}
}
log::trace!("Done resetting all lights!");
log::trace!("Waiting for first state of state receiver..");
for state in state_receiver {
if let Err(err) = connection.send(&[0x90, 91, if state.blackout { 0 } else { 127 }, 127]) {
log::error!("Error sending blackout value: {err:?}")
}
for flank in 0..4 {
if let Err(err) = connection.send(&[
0x90,
82 + flank,
match (state.beat_flank == flank, state.blackout) {
(true, false) => 30,
(_, true)
if SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_millis() / 200 % 2 == 0)
.unwrap_or_default() =>
{
120
}
_ => 0,
},
127,
]) {
log::error!("Error sending flank value: {err:?}");
}
}
for path in { 0..20 }
.map(|index| SceneInstancePath::new(DeckPath::A, index))
.chain({ 0..20 }.map(|index| SceneInstancePath::new(DeckPath::B, index)))
.chain({ 0..8 }.map(|index| SceneInstancePath::new(DeckPath::C, index)))
{
let active = state.active_scenes.contains(&path);
let value = match (path.deck_path, active) {
(DeckPath::A, true) => 30,
(DeckPath::B, true) => 50,
(DeckPath::C, true) => 30,
(DeckPath::A, false) if state.available_scenes_a > path.scene_instance => 11,
(DeckPath::B, false) if state.available_scenes_b > path.scene_instance => 11,
_ => 0,
};
let message = match (path.deck_path, path.scene_instance) {
(DeckPath::A, 0..4) => [0x90, path.scene_instance as u8 + 32, value, 127],
(DeckPath::B, 0..4) => [0x90, path.scene_instance as u8 + 36, value, 127],
(DeckPath::A, 4..8) => [0x90, path.scene_instance as u8 + 20, value, 127],
(DeckPath::B, 4..8) => [0x90, path.scene_instance as u8 + 24, value, 127],
(DeckPath::A, 8..12) => [0x90, path.scene_instance as u8 + 8, value, 127],
(DeckPath::B, 8..12) => [0x90, path.scene_instance as u8 + 12, value, 127],
(DeckPath::A, 12..16) => [0x90, path.scene_instance as u8 + 4, value, 127],
(DeckPath::B, 12..16) => [0x90, path.scene_instance as u8, value, 127],
(DeckPath::A, 16..20) => [0x90, path.scene_instance as u8 - 16, value, 127],
(DeckPath::B, 16..20) => [0x90, path.scene_instance as u8 - 12, value, 127],
(DeckPath::C, _) => [0x90 + path.scene_instance as u8, 48, value, 127],
_ => unreachable!(),
};
if let Err(err) = connection.send(&message) {
log::error!("Error sending scene value: {err:?}");
}
}
log::trace!("Waiting for next state of state receiver..");
}
}