maolan 0.2.0

Rust DAW application for recording, editing, routing, automation, export, and plugin hosting
use super::*;

impl Maolan {
    pub(super) fn handle_response_track_action(&mut self, action: &Action) -> bool {
        match action {
            Action::TrackLevel(name, level) => {
                let mut state = self.state.blocking_write();
                if name == "hw:out" {
                    state.hw_out_level = *level;
                } else if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                    track.level = *level;
                }
                true
            }
            Action::TrackBalance(name, balance) => {
                let mut state = self.state.blocking_write();
                if name == "hw:out" {
                    state.hw_out_balance = *balance;
                } else if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                    track.balance = *balance;
                }
                true
            }
            Action::TrackAutomationLevel(name, level) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.level = *level;
                }
                true
            }
            Action::TrackAutomationBalance(name, balance) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.balance = *balance;
                }
                true
            }
            Action::TrackAutomationMute(name, muted) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.muted = *muted;
                }
                true
            }
            Action::TrackToggleMute(name) => {
                let mut state = self.state.blocking_write();
                if name == "hw:out" {
                    state.hw_out_muted = !state.hw_out_muted;
                } else if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                    track.muted = !track.muted;
                }
                true
            }
            Action::TrackTogglePhase(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.phase_inverted = !track.phase_inverted;
                }
                true
            }
            Action::TrackToggleSolo(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.soloed = !track.soloed;
                }
                true
            }
            Action::TrackToggleMaster(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.is_master = !track.is_master;
                }
                true
            }
            Action::TrackToggleArm(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.armed = !track.armed;
                }
                true
            }
            Action::TrackToggleInputMonitor(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.input_monitor = !track.input_monitor;
                }
                true
            }
            Action::TrackToggleDiskMonitor(name) => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *name)
                {
                    track.disk_monitor = !track.disk_monitor;
                }
                true
            }
            Action::TrackSetColor { track_name, color } => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *track_name)
                {
                    track.color = color.map(|c| iced::Color::from_rgba(c.r, c.g, c.b, c.a));
                }
                true
            }
            Action::TrackSetVcaMaster {
                track_name,
                master_track,
            } => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *track_name)
                {
                    track.vca_master = master_track.clone();
                }
                true
            }
            Action::TrackSetMidiLaneChannel {
                track_name,
                lane,
                channel,
            } => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *track_name)
                {
                    if track.midi_lane_channels.len() < track.midi.ins {
                        track.midi_lane_channels.resize(track.midi.ins, None);
                    }
                    if let Some(slot) = track.midi_lane_channels.get_mut(*lane) {
                        *slot = *channel;
                    }
                }
                true
            }
            Action::TrackAddAudioInput(name) => {
                let mut state = self.state.blocking_write();
                if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                    track.audio.ins = track.audio.ins.saturating_add(1);
                    track.height = track.height.max(track.min_height_for_layout());
                }
                true
            }
            Action::TrackAddAudioOutput(name) => {
                let mut state = self.state.blocking_write();
                if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                    track.audio.outs = track.audio.outs.saturating_add(1);
                    if track.meter_out_db.len() < track.audio.outs {
                        track.meter_out_db.resize(track.audio.outs, -90.0);
                    }
                }
                true
            }
            Action::TrackRemoveAudioInput(name) => {
                let mut state = self.state.blocking_write();
                let removed_port =
                    state
                        .tracks
                        .iter()
                        .find(|t| t.name == *name)
                        .and_then(|track| {
                            (track.audio.ins > track.primary_audio_ins())
                                .then_some(track.audio.ins - 1)
                        });
                if let Some(removed_port) = removed_port {
                    state.connections.retain(|conn| {
                        !(conn.kind == maolan_engine::kind::Kind::Audio
                            && conn.to_track == *name
                            && conn.to_port == removed_port)
                    });
                    if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                        track.audio.ins -= 1;
                        track.height = track.height.max(track.min_height_for_layout());
                    }
                }
                true
            }
            Action::TrackRemoveAudioOutput(name) => {
                let mut state = self.state.blocking_write();
                let removed_port =
                    state
                        .tracks
                        .iter()
                        .find(|t| t.name == *name)
                        .and_then(|track| {
                            (track.audio.outs > track.primary_audio_outs())
                                .then_some(track.audio.outs - 1)
                        });
                if let Some(removed_port) = removed_port {
                    state.connections.retain(|conn| {
                        !(conn.kind == maolan_engine::kind::Kind::Audio
                            && conn.from_track == *name
                            && conn.from_port == removed_port)
                    });
                    if let Some(track) = state.tracks.iter_mut().find(|t| t.name == *name) {
                        track.audio.outs -= 1;
                        track.meter_out_db.truncate(track.audio.outs);
                    }
                }
                true
            }
            Action::TrackArmMidiLearn { track_name, target } => {
                self.state.blocking_write().message = format!(
                    "MIDI learn armed for '{}' ({:?}). Move a hardware MIDI CC control.",
                    track_name, target
                );
                true
            }
            Action::TrackSetMidiLearnBinding {
                track_name,
                target,
                binding,
            } => {
                if let Some(track) = self
                    .state
                    .blocking_write()
                    .tracks
                    .iter_mut()
                    .find(|t| t.name == *track_name)
                {
                    match target {
                        maolan_engine::message::TrackMidiLearnTarget::Volume => {
                            track.midi_learn_volume = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::Balance => {
                            track.midi_learn_balance = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::Mute => {
                            track.midi_learn_mute = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::Solo => {
                            track.midi_learn_solo = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::Arm => {
                            track.midi_learn_arm = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::InputMonitor => {
                            track.midi_learn_input_monitor = binding.clone();
                        }
                        maolan_engine::message::TrackMidiLearnTarget::DiskMonitor => {
                            track.midi_learn_disk_monitor = binding.clone();
                        }
                    }
                }
                let message = if let Some(binding) = binding {
                    format!(
                        "MIDI learn mapped '{}' {:?} to CH{} CC{}",
                        track_name,
                        target,
                        binding.channel + 1,
                        binding.cc
                    )
                } else {
                    format!("MIDI learn cleared for '{}' {:?}", track_name, target)
                };
                self.state.blocking_write().message = message;
                if self.midi_mappings_panel_open {
                    self.rebuild_midi_mappings_report_lines_from_state();
                }
                true
            }
            Action::SetGlobalMidiLearnBinding { target, binding } => {
                {
                    let mut state = self.state.blocking_write();
                    match target {
                        maolan_engine::message::GlobalMidiLearnTarget::PlayPause => {
                            state.global_midi_learn_play_pause = binding.clone();
                        }
                        maolan_engine::message::GlobalMidiLearnTarget::Stop => {
                            state.global_midi_learn_stop = binding.clone();
                        }
                        maolan_engine::message::GlobalMidiLearnTarget::RecordToggle => {
                            state.global_midi_learn_record_toggle = binding.clone();
                        }
                    }
                }
                self.state.blocking_write().message = if let Some(binding) = binding {
                    format!(
                        "Global MIDI learn mapped {:?} to CH{} CC{}",
                        target,
                        binding.channel + 1,
                        binding.cc
                    )
                } else {
                    format!("Global MIDI learn cleared for {:?}", target)
                };
                if self.midi_mappings_panel_open {
                    self.rebuild_midi_mappings_report_lines_from_state();
                }
                true
            }
            Action::TrackSetFrozen { track_name, frozen } => {
                self.state.blocking_write().message = if *frozen {
                    format!("Track '{track_name}' frozen")
                } else {
                    format!("Track '{track_name}' unfrozen")
                };
                true
            }
            #[cfg(all(unix, not(target_os = "macos")))]
            Action::TrackSetPluginBypassed {
                track_name,
                instance_id,
                bypassed,
                ..
            } => {
                let mut state = self.state.blocking_write();
                if state.plugin_graph_track.as_deref() == Some(track_name)
                    && let Some(plugin) = state
                        .plugin_graph_plugins
                        .iter_mut()
                        .find(|p| p.instance_id == *instance_id)
                {
                    plugin.bypassed = *bypassed;
                }
                if let Some((plugins, _)) = state.plugin_graphs_by_track.get_mut(track_name)
                    && let Some(plugin) = plugins.iter_mut().find(|p| p.instance_id == *instance_id)
                {
                    plugin.bypassed = *bypassed;
                }
                true
            }
            #[cfg(not(all(unix, not(target_os = "macos"))))]
            Action::TrackSetPluginBypassed { .. } => true,
            _ => false,
        }
    }
}