diff --git a/main/src/application/group_model.rs b/main/src/application/group_model.rs index 01865db65..073365ba0 100644 --- a/main/src/application/group_model.rs +++ b/main/src/application/group_model.rs @@ -1,5 +1,6 @@ use crate::application::{ActivationConditionModel, GroupData}; use crate::core::{prop, Prop}; +use crate::domain::MappingCompartment; use core::fmt; use rx_util::UnitEvent; use serde::{Deserialize, Serialize}; @@ -10,6 +11,7 @@ use uuid::Uuid; /// A mapping group. #[derive(Clone, Debug)] pub struct GroupModel { + compartment: MappingCompartment, id: GroupId, pub name: Prop, pub control_is_enabled: Prop, @@ -17,18 +19,6 @@ pub struct GroupModel { pub activation_condition_model: ActivationConditionModel, } -impl Default for GroupModel { - fn default() -> Self { - Self { - id: Default::default(), - name: Default::default(), - control_is_enabled: prop(true), - feedback_is_enabled: prop(true), - activation_condition_model: ActivationConditionModel::default(), - } - } -} - impl fmt::Display for GroupModel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name.get_ref()) @@ -76,22 +66,37 @@ impl fmt::Display for GroupId { } impl GroupModel { - pub fn new_from_ui(name: String) -> Self { - Self::new_internal(GroupId::random(), name) + pub fn new_from_ui(compartment: MappingCompartment, name: String) -> Self { + Self::new_internal(compartment, GroupId::random(), name) } - pub fn new_from_data(id: GroupId) -> Self { - Self::new_internal(id, "".to_string()) + pub fn new_from_data(compartment: MappingCompartment, id: GroupId) -> Self { + Self::new_internal(compartment, id, "".to_string()) } - fn new_internal(id: GroupId, name: String) -> Self { + pub fn default_for_compartment(compartment: MappingCompartment) -> Self { + Self { + compartment, + id: Default::default(), + name: Default::default(), + control_is_enabled: prop(true), + feedback_is_enabled: prop(true), + activation_condition_model: ActivationConditionModel::default(), + } + } + + fn new_internal(compartment: MappingCompartment, id: GroupId, name: String) -> Self { Self { id, name: prop(name), - ..Default::default() + ..Self::default_for_compartment(compartment) } } + pub fn compartment(&self) -> MappingCompartment { + self.compartment + } + pub fn id(&self) -> GroupId { self.id } diff --git a/main/src/application/mapping_model.rs b/main/src/application/mapping_model.rs index 887e526a8..ea51697c1 100644 --- a/main/src/application/mapping_model.rs +++ b/main/src/application/mapping_model.rs @@ -363,6 +363,8 @@ impl<'a> MappingModelWithContext<'a> { } fn target_with_context(&self) -> TargetModelWithContext<'_> { - self.mapping.target_model.with_context(self.context) + self.mapping + .target_model + .with_context(self.context, self.mapping.compartment) } } diff --git a/main/src/application/preset.rs b/main/src/application/preset.rs index 8397bea46..06977c228 100644 --- a/main/src/application/preset.rs +++ b/main/src/application/preset.rs @@ -53,13 +53,14 @@ fn mapping_has_project_references(mapping: &MappingModel) -> bool { } fn make_mapping_project_independent(mapping: &mut MappingModel, context: ExtendedProcessorContext) { + let compartment = mapping.compartment(); let target = &mut mapping.target_model; match target.category.get() { TargetCategory::Reaper => { let changed_to_track_ignore_fx = if target.supports_fx() { let refers_to_project = target.fx_type.get().refers_to_project(); if refers_to_project { - let target_with_context = target.with_context(context); + let target_with_context = target.with_context(context, compartment); let virtual_fx = if target_with_context.fx().ok().as_ref() == Some(context.context.containing_fx()) { @@ -80,7 +81,7 @@ fn make_mapping_project_independent(mapping: &mut MappingModel, context: Extende let new_virtual_track = if changed_to_track_ignore_fx { // Track doesn't matter at all. We change it to . Looks nice. Some(VirtualTrack::This) - } else if let Ok(t) = target.with_context(context).effective_track() { + } else if let Ok(t) = target.with_context(context, compartment).effective_track() { if let Some(i) = t.index() { Some(VirtualTrack::ByIndex(i)) } else { diff --git a/main/src/application/session.rs b/main/src/application/session.rs index 2fc6dec53..eadac633e 100644 --- a/main/src/application/session.rs +++ b/main/src/application/session.rs @@ -9,9 +9,9 @@ use crate::domain::{ MappingCompartment, MappingId, MidiControlInput, MidiFeedbackOutput, NormalMainTask, NormalRealTimeTask, OscDeviceId, ParameterArray, ProcessorContext, ProjectionFeedbackValue, QualifiedMappingId, RealSource, RealTimeSender, ReaperTarget, TargetValueChangedEvent, - VirtualSource, PLUGIN_PARAMETER_COUNT, ZEROED_PLUGIN_PARAMETERS, + VirtualSource, COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT, ZEROED_PLUGIN_PARAMETERS, }; -use enum_map::EnumMap; +use enum_map::{enum_map, EnumMap}; use reaper_high::Reaper; use rx_util::{BoxedUnitEvent, Event, Notifier, SharedItemEvent, SharedPayload, UnitEvent}; @@ -80,7 +80,7 @@ pub struct Session { party_is_over_subject: LocalSubject<'static, (), ()>, ui: WrapDebug>, parameters: ParameterArray, - parameter_settings: Vec, + parameter_settings: EnumMap>, controller_preset_manager: Box>, main_preset_manager: Box>, main_preset_link_manager: Box, @@ -176,8 +176,12 @@ impl Session { active_main_preset_id: None, context, mappings: Default::default(), - default_main_group: Default::default(), - default_controller_group: Default::default(), + default_main_group: Rc::new(RefCell::new(GroupModel::default_for_compartment( + MappingCompartment::MainMappings, + ))), + default_controller_group: Rc::new(RefCell::new(GroupModel::default_for_compartment( + MappingCompartment::ControllerMappings, + ))), groups: Default::default(), everything_changed_subject: Default::default(), mapping_list_changed_subject: Default::default(), @@ -192,8 +196,10 @@ impl Session { party_is_over_subject: Default::default(), ui: WrapDebug(Box::new(ui)), parameters: ZEROED_PLUGIN_PARAMETERS, - // TODO-high This should be probably divided per compartment! - parameter_settings: vec![Default::default(); PLUGIN_PARAMETER_COUNT as usize], + parameter_settings: enum_map! { + ControllerMappings => vec![Default::default(); COMPARTMENT_PARAMETER_COUNT as usize], + MainMappings => vec![Default::default(); COMPARTMENT_PARAMETER_COUNT as usize], + }, controller_preset_manager: Box::new(controller_manager), main_preset_manager: Box::new(main_preset_manager), main_preset_link_manager: Box::new(preset_link_manager), @@ -253,12 +259,16 @@ impl Session { }) } - pub fn get_parameter_settings(&self, index: u32) -> &ParameterSetting { - &self.parameter_settings[index as usize] + pub fn get_parameter_settings( + &self, + compartment: MappingCompartment, + index: u32, + ) -> &ParameterSetting { + &self.parameter_settings[compartment][index as usize] } - pub fn get_parameter_name(&self, index: u32) -> String { - let setting = &self.parameter_settings[index as usize]; + pub fn get_parameter_name(&self, compartment: MappingCompartment, index: u32) -> String { + let setting = &self.parameter_settings[compartment][index as usize]; match &setting.custom_name { None => format!("Parameter {}", index + 1), Some(n) => n.clone(), @@ -267,9 +277,10 @@ impl Session { pub fn set_parameter_settings_without_notification( &mut self, + compartment: MappingCompartment, parameter_settings: Vec, ) { - self.parameter_settings = parameter_settings; + self.parameter_settings[compartment] = parameter_settings; } fn initial_sync(&mut self, weak_session: WeakSession) { @@ -431,9 +442,10 @@ impl Session { fn invalidate_fx_indexes_of_mapping_targets(&self) { for m in self.all_mappings() { - m.borrow_mut() - .target_model - .invalidate_fx_index(self.extended_context()); + let mut m = m.borrow_mut(); + let compartment = m.compartment(); + m.target_model + .invalidate_fx_index(self.extended_context(), compartment); } } @@ -663,7 +675,7 @@ impl Session { } pub fn add_default_group(&mut self, compartment: MappingCompartment, name: String) -> GroupId { - let group = GroupModel::new_from_ui(name); + let group = GroupModel::new_from_ui(compartment, name); self.add_group(compartment, group) } @@ -1373,7 +1385,8 @@ impl Session { ); } else { // preset - self.default_main_group.replace(Default::default()); + self.default_main_group + .replace(GroupModel::default_for_compartment(compartment)); self.set_groups_without_notification(compartment, std::iter::empty()); self.set_mappings_without_notification(compartment, std::iter::empty()); } diff --git a/main/src/application/target_model.rs b/main/src/application/target_model.rs index 178088e6f..9abfe7e6d 100644 --- a/main/src/application/target_model.rs +++ b/main/src/application/target_model.rs @@ -155,8 +155,9 @@ impl TargetModel { pub fn take_fx_snapshot( &self, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { - let fx = self.with_context(context).fx()?; + let fx = self.with_context(context, compartment).fx()?; let fx_info = fx.info(); let fx_snapshot = FxSnapshot { fx_type: if fx_info.sub_type_expression.is_empty() { @@ -171,11 +172,15 @@ impl TargetModel { Ok(fx_snapshot) } - pub fn invalidate_fx_index(&mut self, context: ExtendedProcessorContext) { + pub fn invalidate_fx_index( + &mut self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) { if !self.supports_fx() { return; } - if let Ok(actual_fx) = self.with_context(context).fx() { + if let Ok(actual_fx) = self.with_context(context, compartment).fx() { let new_virtual_fx = match self.virtual_fx() { Some(virtual_fx) => { match virtual_fx { @@ -691,10 +696,12 @@ impl TargetModel { pub fn with_context<'a>( &'a self, context: ExtendedProcessorContext<'a>, + compartment: MappingCompartment, ) -> TargetModelWithContext<'a> { TargetModelWithContext { target: self, context, + compartment, } } @@ -843,6 +850,7 @@ pub fn get_fx_label(index: u32, fx: &Fx) -> String { pub struct TargetModelWithContext<'a> { target: &'a TargetModel, context: ExtendedProcessorContext<'a>, + compartment: MappingCompartment, } impl<'a> TargetModelWithContext<'a> { @@ -858,7 +866,7 @@ impl<'a> TargetModelWithContext<'a> { /// track/FX/parameter) is not available. pub fn create_target(&self) -> Result { let unresolved = self.target.create_target()?; - unresolved.resolve(self.context) + unresolved.resolve(self.context, self.compartment) } pub fn is_known_to_be_roundable(&self) -> bool { @@ -874,7 +882,11 @@ impl<'a> TargetModelWithContext<'a> { } // Returns an error if the FX doesn't exist. pub fn fx(&self) -> Result { - get_fx(self.context, &self.target.fx_descriptor()?) + get_fx( + self.context, + &self.target.fx_descriptor()?, + self.compartment, + ) } pub fn project(&self) -> Project { @@ -886,18 +898,26 @@ impl<'a> TargetModelWithContext<'a> { self.target .virtual_track() .ok_or("virtual track not complete")? - .resolve(self.context) + .resolve(self.context, self.compartment) .map_err(|_| "particular track couldn't be resolved") } // Returns an error if that send (or track) doesn't exist. pub fn track_route(&self) -> Result { - get_track_route(self.context, &self.target.track_route_descriptor()?) + get_track_route( + self.context, + &self.target.track_route_descriptor()?, + self.compartment, + ) } // Returns an error if that param (or FX) doesn't exist. fn fx_param(&self) -> Result { - get_fx_param(self.context, &self.target.fx_parameter_descriptor()?) + get_fx_param( + self.context, + &self.target.fx_parameter_descriptor()?, + self.compartment, + ) } fn route_type_label(&self) -> &'static str { @@ -928,7 +948,7 @@ impl<'a> TargetModelWithContext<'a> { fn track_label(&self) -> String { if let Some(t) = self.target.virtual_track() { - t.with_context(self.context).to_string() + t.with_context(self.context, self.compartment).to_string() } else { "".to_owned() } diff --git a/main/src/domain/conditional_activation.rs b/main/src/domain/conditional_activation.rs index 4a137be9d..89c4a137e 100644 --- a/main/src/domain/conditional_activation.rs +++ b/main/src/domain/conditional_activation.rs @@ -1,7 +1,5 @@ use crate::core::eel; -use crate::domain::{ - ParameterArray, ParameterSlice, COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT, -}; +use crate::domain::{ParameterArray, ParameterSlice, COMPARTMENT_PARAMETER_COUNT}; use std::collections::HashSet; #[derive(Debug)] diff --git a/main/src/domain/main_processor.rs b/main/src/domain/main_processor.rs index 3e2424e96..2fc04dbc2 100644 --- a/main/src/domain/main_processor.rs +++ b/main/src/domain/main_processor.rs @@ -25,7 +25,7 @@ const FEEDBACK_TASK_BULK_SIZE: usize = 64; const CONTROL_TASK_BULK_SIZE: usize = 32; const PARAMETER_TASK_BULK_SIZE: usize = 32; -pub const PLUGIN_PARAMETER_COUNT: u32 = 100; +pub const PLUGIN_PARAMETER_COUNT: u32 = 200; pub const COMPARTMENT_PARAMETER_COUNT: u32 = 100; pub type ParameterArray = [f32; PLUGIN_PARAMETER_COUNT as usize]; pub type ParameterSlice = [f32]; @@ -215,10 +215,10 @@ impl MainProcessor { let real_time_mappings = mappings .iter_mut() .map(|m| { - m.refresh_all( - ExtendedProcessorContext::new(&self.context, &self.parameters), + m.refresh_all(ExtendedProcessorContext::new( + &self.context, &self.parameters, - ); + )); if m.feedback_is_effectively_on() { // Mark source as used unused_sources.remove(&m.qualified_source()); @@ -314,10 +314,10 @@ impl MainProcessor { mapping.id() ); // Refresh - mapping.refresh_all( - ExtendedProcessorContext::new(&self.context, &self.parameters), + mapping.refresh_all(ExtendedProcessorContext::new( + &self.context, &self.parameters, - ); + )); // Sync to real-time processor self.normal_real_time_task_sender .send(NormalRealTimeTask::UpdateSingleMapping( @@ -551,7 +551,7 @@ impl MainProcessor { .handle_event(DomainEvent::UpdatedParameter { index, value }); // Mapping activation is supported for both compartments and target activation // might change also in non-virtual controller mappings due to dynamic targets. - for compartment in MappingCompartment::enum_iter() { + if let Some(compartment) = MappingCompartment::by_absolute_param_index(index) { let mut changed_mappings = HashSet::new(); let mut unused_sources = self.currently_feedback_enabled_sources(compartment, true); diff --git a/main/src/domain/mapping.rs b/main/src/domain/mapping.rs index 5dba3ff2d..54f1a27f8 100644 --- a/main/src/domain/mapping.rs +++ b/main/src/domain/mapping.rs @@ -2,7 +2,7 @@ use crate::domain::{ ActivationChange, ActivationCondition, ControlOptions, ExtendedProcessorContext, MappingActivationEffect, Mode, ParameterArray, ParameterSlice, PlayPosFeedbackResolution, RealearnTarget, ReaperTarget, TargetCharacter, UnresolvedReaperTarget, VirtualControlElement, - VirtualSource, VirtualSourceValue, VirtualTarget, + VirtualSource, VirtualSourceValue, VirtualTarget, COMPARTMENT_PARAMETER_COUNT, }; use derive_more::Display; use enum_iterator::IntoEnumIterator; @@ -19,6 +19,7 @@ use serde::{Deserialize, Serialize}; use smallvec::alloc::fmt::Formatter; use std::fmt; use std::fmt::Display; +use std::ops::Range; use std::time::{Duration, Instant}; use uuid::Uuid; @@ -164,16 +165,25 @@ impl MainMapping { /// Returns `Some` if this affects the mapping's activation state in any way. pub fn check_activation_effect( &self, - params: &ParameterSlice, - index: u32, + params: &ParameterArray, + absolute_param_index: u32, previous_value: f32, ) -> Option { - let effect_1 = - self.activation_condition_1 - .is_fulfilled_single(params, index, previous_value); - let effect_2 = - self.activation_condition_2 - .is_fulfilled_single(params, index, previous_value); + let sliced_params = self.core.compartment.slice_params(params); + let rel_param_index = self + .core + .compartment + .relativize_absolute_index(absolute_param_index); + let effect_1 = self.activation_condition_1.is_fulfilled_single( + sliced_params, + rel_param_index, + previous_value, + ); + let effect_2 = self.activation_condition_2.is_fulfilled_single( + sliced_params, + rel_param_index, + previous_value, + ); MappingActivationEffect::new(self.id(), effect_1, effect_2) } @@ -213,9 +223,9 @@ impl MainMapping { Some(update) } - pub fn refresh_all(&mut self, context: ExtendedProcessorContext, params: &ParameterSlice) { + pub fn refresh_all(&mut self, context: ExtendedProcessorContext) { self.refresh_target(context); - self.update_activation(params); + self.update_activation(&context.params); } pub fn needs_refresh_when_target_touched(&self) -> bool { @@ -245,7 +255,7 @@ impl MainMapping { let was_active_before = self.core.options.target_is_active; let (target, is_active) = match self.unresolved_target.as_ref() { None => (None, false), - Some(t) => match t.resolve(context).ok() { + Some(t) => match t.resolve(context, self.core.compartment).ok() { None => (None, false), Some(rt) => { let met = t.conditions_are_met(&rt); @@ -266,10 +276,11 @@ impl MainMapping { (target_changed, Some(update)) } - pub fn update_activation(&mut self, params: &ParameterSlice) -> Option { + pub fn update_activation(&mut self, params: &ParameterArray) -> Option { + let sliced_params = self.core.compartment.slice_params(params); let was_active_before = self.is_active(); - self.is_active_1 = self.activation_condition_1.is_fulfilled(params); - self.is_active_2 = self.activation_condition_2.is_fulfilled(params); + self.is_active_1 = self.activation_condition_1.is_fulfilled(sliced_params); + self.is_active_2 = self.activation_condition_2.is_fulfilled(sliced_params); let now_is_active = self.is_active(); if now_is_active == was_active_before { return None; @@ -810,10 +821,11 @@ impl UnresolvedCompoundMappingTarget { pub fn resolve( &self, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { use UnresolvedCompoundMappingTarget::*; let resolved = match self { - Reaper(t) => CompoundMappingTarget::Reaper(t.resolve(context)?), + Reaper(t) => CompoundMappingTarget::Reaper(t.resolve(context, compartment)?), Virtual(t) => CompoundMappingTarget::Virtual(*t), }; Ok(resolved) @@ -1016,6 +1028,31 @@ impl MappingCompartment { pub fn enum_iter() -> impl Iterator + ExactSizeIterator { MappingCompartment::into_enum_iter() } + + pub fn by_absolute_param_index(absolute_index: u32) -> Option { + Self::enum_iter().find(|c| c.param_range().contains(&(absolute_index))) + } + + pub fn relativize_absolute_index(self, absolute_index: u32) -> u32 { + absolute_index - self.param_offset() + } + + pub fn slice_params(self, params: &ParameterArray) -> &ParameterSlice { + let range = self.param_range(); + ¶ms[range.start as usize..range.end as usize] + } + + const fn param_offset(self) -> u32 { + match self { + MappingCompartment::ControllerMappings => 100u32, + MappingCompartment::MainMappings => 0u32, + } + } + + const fn param_range(self) -> Range { + let offset = self.param_offset(); + (offset..(offset + COMPARTMENT_PARAMETER_COUNT)) + } } pub enum ExtendedSourceCharacter { diff --git a/main/src/domain/unresolved_reaper_target.rs b/main/src/domain/unresolved_reaper_target.rs index 556c147a1..933906229 100644 --- a/main/src/domain/unresolved_reaper_target.rs +++ b/main/src/domain/unresolved_reaper_target.rs @@ -1,9 +1,10 @@ use crate::application::BookmarkAnchorType; use crate::core::hash_util; use crate::domain::{ - ActionInvocationType, DomainGlobal, ExtendedProcessorContext, ParameterArray, ParameterSlice, - PlayPosFeedbackResolution, ReaperTarget, SeekOptions, SoloBehavior, TouchedParameterType, - TrackExclusivity, TransportAction, COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT, + ActionInvocationType, DomainGlobal, ExtendedProcessorContext, MappingCompartment, + ParameterArray, ParameterSlice, PlayPosFeedbackResolution, ReaperTarget, SeekOptions, + SoloBehavior, TouchedParameterType, TrackExclusivity, TransportAction, + COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT, }; use derive_more::{Display, Error}; use enum_iterator::IntoEnumIterator; @@ -102,7 +103,11 @@ pub enum UnresolvedReaperTarget { } impl UnresolvedReaperTarget { - pub fn resolve(&self, context: ExtendedProcessorContext) -> Result { + pub fn resolve( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Result { use UnresolvedReaperTarget::*; let resolved = match self { Action { @@ -116,39 +121,39 @@ impl UnresolvedReaperTarget { FxParameter { fx_parameter_descriptor, } => ReaperTarget::FxParameter { - param: get_fx_param(context, fx_parameter_descriptor)?, + param: get_fx_param(context, fx_parameter_descriptor, compartment)?, }, TrackVolume { track_descriptor } => ReaperTarget::TrackVolume { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, }, TrackSendVolume { descriptor } => ReaperTarget::TrackRouteVolume { - route: get_track_route(context, descriptor)?, + route: get_track_route(context, descriptor, compartment)?, }, TrackPan { track_descriptor } => ReaperTarget::TrackPan { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, }, TrackWidth { track_descriptor } => ReaperTarget::TrackWidth { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, }, TrackArm { track_descriptor, exclusivity, } => ReaperTarget::TrackArm { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, exclusivity: *exclusivity, }, TrackSelection { track_descriptor, exclusivity, } => ReaperTarget::TrackSelection { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, exclusivity: *exclusivity, }, TrackMute { track_descriptor, exclusivity, } => ReaperTarget::TrackMute { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, exclusivity: *exclusivity, }, TrackSolo { @@ -156,15 +161,15 @@ impl UnresolvedReaperTarget { behavior, exclusivity, } => ReaperTarget::TrackSolo { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, behavior: *behavior, exclusivity: *exclusivity, }, TrackSendPan { descriptor } => ReaperTarget::TrackRoutePan { - route: get_track_route(context, descriptor)?, + route: get_track_route(context, descriptor, compartment)?, }, TrackSendMute { descriptor } => ReaperTarget::TrackRouteMute { - route: get_track_route(context, descriptor)?, + route: get_track_route(context, descriptor, compartment)?, }, Tempo => ReaperTarget::Tempo { project: context.context.project_or_current_project(), @@ -173,10 +178,10 @@ impl UnresolvedReaperTarget { project: context.context.project_or_current_project(), }, FxEnable { fx_descriptor } => ReaperTarget::FxEnable { - fx: get_fx(context, fx_descriptor)?, + fx: get_fx(context, fx_descriptor, compartment)?, }, FxPreset { fx_descriptor } => ReaperTarget::FxPreset { - fx: get_fx(context, fx_descriptor)?, + fx: get_fx(context, fx_descriptor, compartment)?, }, SelectedTrack => ReaperTarget::SelectedTrack { project: context.context.project_or_current_project(), @@ -185,7 +190,7 @@ impl UnresolvedReaperTarget { track_descriptor, exclusivity, } => ReaperTarget::AllTrackFxEnable { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, exclusivity: *exclusivity, }, Transport { action } => ReaperTarget::Transport { @@ -196,7 +201,7 @@ impl UnresolvedReaperTarget { fx_descriptor, chunk, } => ReaperTarget::LoadFxSnapshot { - fx: get_fx(context, fx_descriptor)?, + fx: get_fx(context, fx_descriptor, compartment)?, chunk: chunk.clone(), chunk_hash: hash_util::calculate_non_crypto_hash(chunk), }, @@ -214,7 +219,7 @@ impl UnresolvedReaperTarget { parameter_type, exclusivity, } => ReaperTarget::AutomationTouchState { - track: get_effective_track(context, &track_descriptor.track)?, + track: get_effective_track(context, &track_descriptor.track, compartment)?, parameter_type: *parameter_type, exclusivity: *exclusivity, }, @@ -366,9 +371,10 @@ impl UnresolvedReaperTarget { pub fn get_effective_track( context: ExtendedProcessorContext, virtual_track: &VirtualTrack, + compartment: MappingCompartment, ) -> Result { virtual_track - .resolve(context) + .resolve(context, compartment) .map_err(|_| "track couldn't be resolved") } @@ -376,11 +382,12 @@ pub fn get_effective_track( pub fn get_track_route( context: ExtendedProcessorContext, descriptor: &TrackRouteDescriptor, + compartment: MappingCompartment, ) -> Result { - let track = get_effective_track(context, &descriptor.track_descriptor.track)?; + let track = get_effective_track(context, &descriptor.track_descriptor.track, compartment)?; descriptor .route - .resolve(&track, context) + .resolve(&track, context, compartment) .map_err(|_| "route doesn't exist") } @@ -429,11 +436,12 @@ impl TrackRouteSelector { track: &Track, route_type: TrackRouteType, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { use TrackRouteSelector::*; let route = match self { Dynamic(evaluator) => { - let i = Self::evaluate_to_route_index(evaluator, context); + let i = Self::evaluate_to_route_index(evaluator, context, compartment); resolve_track_route_by_index(track, route_type, i)? } ById(guid) => { @@ -457,9 +465,17 @@ impl TrackRouteSelector { Ok(route) } - pub fn calculated_route_index(&self, context: ExtendedProcessorContext) -> Option { + pub fn calculated_route_index( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Option { if let TrackRouteSelector::Dynamic(evaluator) = self { - Some(Self::evaluate_to_route_index(evaluator, context)) + Some(Self::evaluate_to_route_index( + evaluator, + context, + compartment, + )) } else { None } @@ -468,8 +484,10 @@ impl TrackRouteSelector { fn evaluate_to_route_index( evaluator: &ExpressionEvaluator, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> u32 { - let result = evaluator.evaluate(context.params); + let sliced_params = compartment.slice_params(context.params); + let result = evaluator.evaluate(sliced_params); result.max(0.0) as u32 } @@ -515,8 +533,10 @@ impl VirtualTrackRoute { &self, track: &Track, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { - self.selector.resolve(track, self.r#type, context) + self.selector + .resolve(track, self.r#type, context, compartment) } pub fn id(&self) -> Option { @@ -597,11 +617,12 @@ impl VirtualFxParameter { &self, fx: &Fx, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { use VirtualFxParameter::*; match self { Dynamic(evaluator) => { - let i = Self::evaluate_to_fx_parameter_index(evaluator, context); + let i = Self::evaluate_to_fx_parameter_index(evaluator, context, compartment); resolve_parameter_by_index(fx, i) } ByName(name) => fx @@ -615,9 +636,17 @@ impl VirtualFxParameter { } } - pub fn calculated_fx_parameter_index(&self, context: ExtendedProcessorContext) -> Option { + pub fn calculated_fx_parameter_index( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Option { if let VirtualFxParameter::Dynamic(evaluator) = self { - Some(Self::evaluate_to_fx_parameter_index(evaluator, context)) + Some(Self::evaluate_to_fx_parameter_index( + evaluator, + context, + compartment, + )) } else { None } @@ -626,8 +655,10 @@ impl VirtualFxParameter { fn evaluate_to_fx_parameter_index( evaluator: &ExpressionEvaluator, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> u32 { - let result = evaluator.evaluate(context.params); + let sliced_params = compartment.slice_params(context.params); + let result = evaluator.evaluate(sliced_params); result.max(0.0) as u32 } @@ -765,7 +796,11 @@ impl VirtualFx { } impl VirtualTrack { - pub fn resolve(&self, context: ExtendedProcessorContext) -> Result { + pub fn resolve( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Result { use VirtualTrack::*; let project = context.context.project_or_current_project(); let track = match self { @@ -782,7 +817,7 @@ impl VirtualTrack { .first_selected_track(MasterTrackBehavior::IncludeMasterTrack) .ok_or(TrackResolveError::NoTrackSelected)?, Dynamic(evaluator) => { - let index = Self::evaluate_to_track_index(evaluator, context); + let index = Self::evaluate_to_track_index(evaluator, context, compartment); resolve_track_by_index(project, index)? } Master => project.master_track(), @@ -821,9 +856,17 @@ impl VirtualTrack { Ok(track) } - pub fn calculated_track_index(&self, context: ExtendedProcessorContext) -> Option { + pub fn calculated_track_index( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Option { if let VirtualTrack::Dynamic(evaluator) = self { - Some(Self::evaluate_to_track_index(evaluator, context)) + Some(Self::evaluate_to_track_index( + evaluator, + context, + compartment, + )) } else { None } @@ -832,18 +875,22 @@ impl VirtualTrack { fn evaluate_to_track_index( evaluator: &ExpressionEvaluator, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> u32 { - let result = evaluator.evaluate(context.params); + let sliced_params = compartment.slice_params(context.params); + let result = evaluator.evaluate(sliced_params); result.max(0.0) as u32 } pub fn with_context<'a>( &'a self, context: ExtendedProcessorContext<'a>, + compartment: MappingCompartment, ) -> VirtualTrackWithContext<'a> { VirtualTrackWithContext { virtual_track: self, context, + compartment, } } @@ -951,11 +998,12 @@ impl VirtualChainFx { &self, fx_chain: &FxChain, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> Result { use VirtualChainFx::*; let fx = match self { Dynamic(evaluator) => { - let index = Self::evaluate_to_fx_index(evaluator, context); + let index = Self::evaluate_to_fx_index(evaluator, context, compartment); get_index_based_fx_on_chain(fx_chain, index).map_err(|_| { FxResolveError::FxNotFound { guid: None, @@ -1003,9 +1051,13 @@ impl VirtualChainFx { Ok(fx) } - pub fn calculated_fx_index(&self, context: ExtendedProcessorContext) -> Option { + pub fn calculated_fx_index( + &self, + context: ExtendedProcessorContext, + compartment: MappingCompartment, + ) -> Option { if let VirtualChainFx::Dynamic(evaluator) = self { - Some(Self::evaluate_to_fx_index(evaluator, context)) + Some(Self::evaluate_to_fx_index(evaluator, context, compartment)) } else { None } @@ -1014,8 +1066,10 @@ impl VirtualChainFx { fn evaluate_to_fx_index( evaluator: &ExpressionEvaluator, context: ExtendedProcessorContext, + compartment: MappingCompartment, ) -> u32 { - let result = evaluator.evaluate(context.params); + let sliced_params = compartment.slice_params(context.params); + let result = evaluator.evaluate(sliced_params); result.max(0.0) as u32 } @@ -1063,6 +1117,7 @@ pub enum FxResolveError { pub struct VirtualTrackWithContext<'a> { virtual_track: &'a VirtualTrack, context: ExtendedProcessorContext<'a>, + compartment: MappingCompartment, } impl<'a> fmt::Display for VirtualTrackWithContext<'a> { @@ -1071,7 +1126,7 @@ impl<'a> fmt::Display for VirtualTrackWithContext<'a> { match self.virtual_track { This | Selected | Master | Dynamic(_) => write!(f, "{}", self.virtual_track), _ => { - if let Ok(t) = self.virtual_track.resolve(self.context) { + if let Ok(t) = self.virtual_track.resolve(self.context, self.compartment) { f.write_str(&get_track_label(&t)) } else { f.write_str(&get_non_present_virtual_track_label(&self.virtual_track)) @@ -1109,11 +1164,12 @@ fn get_track_label(track: &Track) -> String { pub fn get_fx_param( context: ExtendedProcessorContext, fx_parameter_descriptor: &FxParameterDescriptor, + compartment: MappingCompartment, ) -> Result { - let fx = get_fx(context, &fx_parameter_descriptor.fx_descriptor)?; + let fx = get_fx(context, &fx_parameter_descriptor.fx_descriptor, compartment)?; fx_parameter_descriptor .fx_parameter - .resolve(&fx, context) + .resolve(&fx, context, compartment) .map_err(|_| "parameter doesn't exist") } @@ -1121,6 +1177,7 @@ pub fn get_fx_param( pub fn get_fx( context: ExtendedProcessorContext, descriptor: &FxDescriptor, + compartment: MappingCompartment, ) -> Result { match &descriptor.fx { VirtualFx::This => { @@ -1165,10 +1222,15 @@ pub fn get_fx( } _ => MaybeOwned::Borrowed(chain_fx), }; - let fx_chain = get_fx_chain(context, &descriptor.track_descriptor.track, *is_input_fx)?; + let fx_chain = get_fx_chain( + context, + &descriptor.track_descriptor.track, + *is_input_fx, + compartment, + )?; chain_fx .get() - .resolve(&fx_chain, context) + .resolve(&fx_chain, context, compartment) .map_err(|_| "couldn't resolve particular FX") } } @@ -1230,8 +1292,9 @@ pub fn get_fx_chain( context: ExtendedProcessorContext, track: &VirtualTrack, is_input_fx: bool, + compartment: MappingCompartment, ) -> Result { - let track = get_effective_track(context, track)?; + let track = get_effective_track(context, track, compartment)?; let result = if is_input_fx { if track.is_master_track() { // The combination "Master track + input FX chain" by convention represents the diff --git a/main/src/infrastructure/data/controller_preset.rs b/main/src/infrastructure/data/controller_preset.rs index 5fdf9f315..0a92ff640 100644 --- a/main/src/infrastructure/data/controller_preset.rs +++ b/main/src/infrastructure/data/controller_preset.rs @@ -1,4 +1,6 @@ -use crate::application::{ControllerPreset, Preset, PresetManager, SharedGroup, SharedMapping}; +use crate::application::{ + ControllerPreset, GroupModel, Preset, PresetManager, SharedGroup, SharedMapping, +}; use crate::core::default_util::is_default; use crate::domain::MappingCompartment; use crate::infrastructure::data::{ @@ -96,22 +98,26 @@ impl PresetData for ControllerPresetData { } fn to_model(&self, id: String) -> ControllerPreset { + let compartment = MappingCompartment::ControllerMappings; let migration_descriptor = MigrationDescriptor::new(self.version.as_ref()); let final_default_group = self .default_group .as_ref() - .map(|g| g.to_model()) - .unwrap_or_default(); + .map(|g| g.to_model(compartment)) + .unwrap_or_else(|| GroupModel::default_for_compartment(compartment)); ControllerPreset::new( id, self.name.clone(), final_default_group, - self.groups.iter().map(|g| g.to_model()).collect(), + self.groups + .iter() + .map(|g| g.to_model(compartment)) + .collect(), self.mappings .iter() .map(|m| { m.to_model_flexible( - MappingCompartment::ControllerMappings, + compartment, None, &migration_descriptor, self.version.as_ref(), diff --git a/main/src/infrastructure/data/group_model_data.rs b/main/src/infrastructure/data/group_model_data.rs index b2806322c..c019f5fe4 100644 --- a/main/src/infrastructure/data/group_model_data.rs +++ b/main/src/infrastructure/data/group_model_data.rs @@ -1,5 +1,6 @@ use crate::application::{GroupId, GroupModel}; use crate::core::default_util::is_default; +use crate::domain::MappingCompartment; use crate::infrastructure::data::{ActivationConditionData, EnabledData}; use serde::{Deserialize, Serialize}; use std::borrow::BorrowMut; @@ -34,8 +35,8 @@ impl GroupModelData { } } - pub fn to_model(&self) -> GroupModel { - let mut model = GroupModel::new_from_data(self.id); + pub fn to_model(&self, compartment: MappingCompartment) -> GroupModel { + let mut model = GroupModel::new_from_data(compartment, self.id); self.apply_to_model(&mut model); model } diff --git a/main/src/infrastructure/data/main_preset.rs b/main/src/infrastructure/data/main_preset.rs index 806f43fce..1909a892d 100644 --- a/main/src/infrastructure/data/main_preset.rs +++ b/main/src/infrastructure/data/main_preset.rs @@ -1,4 +1,6 @@ -use crate::application::{MainPreset, Preset, PresetManager, SharedGroup, SharedMapping}; +use crate::application::{ + GroupModel, MainPreset, Preset, PresetManager, SharedGroup, SharedMapping, +}; use crate::core::default_util::is_default; use crate::domain::MappingCompartment; use crate::infrastructure::data::{ @@ -91,22 +93,26 @@ impl PresetData for MainPresetData { } fn to_model(&self, id: String) -> MainPreset { + let compartment = MappingCompartment::MainMappings; let migration_descriptor = MigrationDescriptor::new(self.version.as_ref()); let final_default_group = self .default_group .as_ref() - .map(|g| g.to_model()) - .unwrap_or_default(); + .map(|g| g.to_model(compartment)) + .unwrap_or_else(|| GroupModel::default_for_compartment(compartment)); MainPreset::new( id, self.name.clone(), final_default_group, - self.groups.iter().map(|g| g.to_model()).collect(), + self.groups + .iter() + .map(|g| g.to_model(compartment)) + .collect(), self.mappings .iter() .map(|m| { m.to_model_flexible( - MappingCompartment::MainMappings, + compartment, None, &migration_descriptor, self.version.as_ref(), diff --git a/main/src/infrastructure/data/session_data.rs b/main/src/infrastructure/data/session_data.rs index 8cf87e9f7..a34ce7bff 100644 --- a/main/src/infrastructure/data/session_data.rs +++ b/main/src/infrastructure/data/session_data.rs @@ -2,7 +2,8 @@ use crate::application::{GroupModel, MainPresetAutoLoadMode, ParameterSetting, S use crate::core::default_util::{bool_true, is_bool_true, is_default}; use crate::domain::{ ExtendedProcessorContext, MappingCompartment, MidiControlInput, MidiFeedbackOutput, - OscDeviceId, ParameterArray, PLUGIN_PARAMETER_COUNT, ZEROED_PLUGIN_PARAMETERS, + OscDeviceId, ParameterArray, COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT, + ZEROED_PLUGIN_PARAMETERS, }; use crate::infrastructure::data::{ GroupModelData, MappingModelData, MigrationDescriptor, ParameterData, @@ -71,6 +72,8 @@ pub struct SessionData { main_preset_auto_load_mode: MainPresetAutoLoadMode, #[serde(default, skip_serializing_if = "is_default")] parameters: HashMap, + #[serde(default, skip_serializing_if = "is_default")] + controller_parameters: HashMap, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -109,6 +112,7 @@ impl Default for SessionData { active_main_preset_id: None, main_preset_auto_load_mode: session_defaults::MAIN_PRESET_AUTO_LOAD_MODE, parameters: Default::default(), + controller_parameters: Default::default(), } } } @@ -172,21 +176,16 @@ impl SessionData { .map(|id| id.to_string()), active_main_preset_id: session.active_main_preset_id().map(|id| id.to_string()), main_preset_auto_load_mode: session.main_preset_auto_load_mode.get(), - // TODO-high This should probably be divided - parameters: (0..PLUGIN_PARAMETER_COUNT) - .filter_map(|i| { - let value = parameters[i as usize]; - let settings = session.get_parameter_settings(i); - if value == 0.0 && settings.custom_name.is_none() { - return None; - } - let data = ParameterData { - value, - name: settings.custom_name.clone(), - }; - Some((i, data)) - }) - .collect(), + parameters: get_parameter_data_map( + session, + parameters, + MappingCompartment::MainMappings, + ), + controller_parameters: get_parameter_data_map( + session, + parameters, + MappingCompartment::ControllerMappings, + ), } } @@ -278,24 +277,35 @@ impl SessionData { .osc_output_device_id .set_without_notification(osc_feedback_output); // Groups - let get_final_default_group = |def_group: Option<&GroupModelData>| { - def_group.map(|g| g.to_model()).unwrap_or_default() - }; + let get_final_default_group = + |def_group: Option<&GroupModelData>, compartment: MappingCompartment| { + def_group + .map(|g| g.to_model(compartment)) + .unwrap_or_else(|| GroupModel::default_for_compartment(compartment)) + }; session .default_group(MappingCompartment::MainMappings) - .replace(get_final_default_group(self.default_group.as_ref())); + .replace(get_final_default_group( + self.default_group.as_ref(), + MappingCompartment::MainMappings, + )); session.set_groups_without_notification( MappingCompartment::MainMappings, - self.groups.iter().map(|g| g.to_model()), + self.groups + .iter() + .map(|g| g.to_model(MappingCompartment::MainMappings)), ); session .default_group(MappingCompartment::ControllerMappings) .replace(get_final_default_group( self.default_controller_group.as_ref(), + MappingCompartment::ControllerMappings, )); session.set_groups_without_notification( MappingCompartment::ControllerMappings, - self.controller_groups.iter().map(|g| g.to_model()), + self.controller_groups + .iter() + .map(|g| g.to_model(MappingCompartment::ControllerMappings)), ); // Mappings let context = session.context().clone(); @@ -324,13 +334,14 @@ impl SessionData { .main_preset_auto_load_mode .set_without_notification(self.main_preset_auto_load_mode); // Parameters - let mut parameter_settings = vec![Default::default(); PLUGIN_PARAMETER_COUNT as usize]; - for (i, p) in self.parameters.iter() { - parameter_settings[*i as usize] = ParameterSetting { - custom_name: p.name.clone(), - }; - } - session.set_parameter_settings_without_notification(parameter_settings); + session.set_parameter_settings_without_notification( + MappingCompartment::MainMappings, + get_parameter_settings(&self.parameters), + ); + session.set_parameter_settings_without_notification( + MappingCompartment::ControllerMappings, + get_parameter_settings(&self.controller_parameters), + ); Ok(()) } @@ -342,3 +353,35 @@ impl SessionData { parameters } } + +fn get_parameter_data_map( + session: &Session, + parameters: &ParameterArray, + compartment: MappingCompartment, +) -> HashMap { + (0..COMPARTMENT_PARAMETER_COUNT) + .filter_map(|i| { + let parameter_slice = compartment.slice_params(parameters); + let value = parameter_slice[i as usize]; + let settings = session.get_parameter_settings(compartment, i); + if value == 0.0 && settings.custom_name.is_none() { + return None; + } + let data = ParameterData { + value, + name: settings.custom_name.clone(), + }; + Some((i, data)) + }) + .collect() +} + +fn get_parameter_settings(data_map: &HashMap) -> Vec { + let mut settings = vec![Default::default(); COMPARTMENT_PARAMETER_COUNT as usize]; + for (i, p) in data_map.iter() { + settings[*i as usize] = ParameterSetting { + custom_name: p.name.clone(), + }; + } + settings +} diff --git a/main/src/infrastructure/data/target_model_data.rs b/main/src/infrastructure/data/target_model_data.rs index d7589577a..6604386ec 100644 --- a/main/src/infrastructure/data/target_model_data.rs +++ b/main/src/infrastructure/data/target_model_data.rs @@ -191,7 +191,11 @@ impl TargetModelData { with_notification, ); let virtual_track = model.virtual_track().unwrap_or(VirtualTrack::This); - let fx_prop_values = deserialize_fx(&self.fx_data, context, &virtual_track); + let fx_prop_values = deserialize_fx( + &self.fx_data, + context.map(|c| (c, compartment)), + &virtual_track, + ); model.set_fx(fx_prop_values, with_notification); model .enable_only_if_fx_has_focus @@ -619,7 +623,7 @@ fn deserialize_track(track_data: &TrackData) -> TrackPropValues { fn deserialize_fx( fx_data: &FxData, - context: Option, + ctx: Option<(ExtendedProcessorContext, MappingCompartment)>, virtual_track: &VirtualTrack, ) -> FxPropValues { match fx_data { @@ -638,13 +642,11 @@ fn deserialize_fx( is_input_fx, .. } => { - let fx = get_guid_based_fx_at_index( - context.expect("trying to load pre-1.12.0 FX target without processor context"), - virtual_track, - *is_input_fx, - *i, - ) - .ok(); + let (context, compartment) = + ctx.expect("trying to load pre-1.12.0 FX target without processor context"); + let fx = + get_guid_based_fx_at_index(context, virtual_track, *is_input_fx, *i, compartment) + .ok(); FxPropValues { r#type: VirtualFxType::ByIdOrIndex, is_input_fx: *is_input_fx, @@ -879,7 +881,8 @@ pub fn get_guid_based_fx_at_index( track: &VirtualTrack, is_input_fx: bool, fx_index: u32, + compartment: MappingCompartment, ) -> Result { - let fx_chain = get_fx_chain(context, track, is_input_fx)?; + let fx_chain = get_fx_chain(context, track, is_input_fx, compartment)?; fx_chain.fx_by_index(fx_index).ok_or("no FX at that index") } diff --git a/main/src/infrastructure/plugin/realearn_plugin_parameters.rs b/main/src/infrastructure/plugin/realearn_plugin_parameters.rs index 25433b38e..23cca1ea9 100644 --- a/main/src/infrastructure/plugin/realearn_plugin_parameters.rs +++ b/main/src/infrastructure/plugin/realearn_plugin_parameters.rs @@ -6,7 +6,9 @@ use reaper_low::firewall; use slog::debug; use crate::application::{SharedSession, WeakSession}; -use crate::domain::{ParameterArray, ParameterMainTask, ZEROED_PLUGIN_PARAMETERS}; +use crate::domain::{ + MappingCompartment, ParameterArray, ParameterMainTask, ZEROED_PLUGIN_PARAMETERS, +}; use crate::infrastructure::data::SessionData; use std::rc::Rc; use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -163,11 +165,18 @@ impl PluginParameters for RealearnPluginParameters { fn get_parameter_name(&self, index: i32) -> String { firewall(|| { - if let Some(s) = self.session() { - s.borrow().get_parameter_name(index as u32) + let name = if let Some(s) = self.session() { + let index = index as u32; + if let Some(compartment) = MappingCompartment::by_absolute_param_index(index) { + let rel_index = compartment.relativize_absolute_index(index); + Some(s.borrow().get_parameter_name(compartment, rel_index)) + } else { + None + } } else { - format!("Parameter {}", index + 1) - } + None + }; + name.unwrap_or_else(|| format!("Parameter {}", index + 1)) }) .unwrap_or_default() } diff --git a/main/src/infrastructure/ui/mapping_header_panel.rs b/main/src/infrastructure/ui/mapping_header_panel.rs index 9fa37c6ed..8c85843a8 100644 --- a/main/src/infrastructure/ui/mapping_header_panel.rs +++ b/main/src/infrastructure/ui/mapping_header_panel.rs @@ -11,7 +11,7 @@ use crate::application::{ ActivationType, GroupModel, MappingModel, ModifierConditionModel, ProgramConditionModel, SharedSession, WeakSession, }; -use crate::domain::{COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT}; +use crate::domain::{MappingCompartment, COMPARTMENT_PARAMETER_COUNT, PLUGIN_PARAMETER_COUNT}; use std::fmt::Debug; use swell_ui::{DialogUnits, Point, SharedView, View, ViewContext, Window}; @@ -28,6 +28,7 @@ pub struct MappingHeaderPanel { } pub trait Item: Debug { + fn compartment(&self) -> MappingCompartment; fn supports_name_change(&self) -> bool; fn supports_activation(&self) -> bool; fn name(&self) -> &str; @@ -178,21 +179,25 @@ impl MappingHeaderPanel { fn fill_activation_combo_boxes(&self, item: &dyn Item) { use ActivationType::*; + let compartment = item.compartment(); match item.activation_type() { Modifiers => { self.fill_combo_box_with_realearn_params( root::ID_MAPPING_ACTIVATION_SETTING_1_COMBO_BOX, true, + compartment, ); self.fill_combo_box_with_realearn_params( root::ID_MAPPING_ACTIVATION_SETTING_2_COMBO_BOX, true, + compartment, ); } Program => { self.fill_combo_box_with_realearn_params( root::ID_MAPPING_ACTIVATION_SETTING_1_COMBO_BOX, false, + compartment, ); self.view .require_control(root::ID_MAPPING_ACTIVATION_SETTING_2_COMBO_BOX) @@ -482,7 +487,12 @@ impl MappingHeaderPanel { }); } - fn fill_combo_box_with_realearn_params(&self, control_id: u32, with_none: bool) { + fn fill_combo_box_with_realearn_params( + &self, + control_id: u32, + with_none: bool, + compartment: MappingCompartment, + ) { let b = self.view.require_control(control_id); let start = if with_none { vec![(-1isize, "".to_string())] @@ -495,7 +505,7 @@ impl MappingHeaderPanel { (0..COMPARTMENT_PARAMETER_COUNT).map(|i| { ( i as isize, - format!("{}. {}", i + 1, session.get_parameter_name(i)), + format!("{}. {}", i + 1, session.get_parameter_name(compartment, i)), ) }), )); @@ -598,6 +608,10 @@ impl View for MappingHeaderPanel { } impl Item for MappingModel { + fn compartment(&self) -> MappingCompartment { + self.compartment() + } + fn supports_name_change(&self) -> bool { true } @@ -676,6 +690,10 @@ impl Item for MappingModel { } impl Item for GroupModel { + fn compartment(&self) -> MappingCompartment { + self.compartment() + } + fn supports_name_change(&self) -> bool { !self.is_default_group() } diff --git a/main/src/infrastructure/ui/mapping_panel.rs b/main/src/infrastructure/ui/mapping_panel.rs index a8aa37a33..82a7d229e 100644 --- a/main/src/infrastructure/ui/mapping_panel.rs +++ b/main/src/infrastructure/ui/mapping_panel.rs @@ -136,10 +136,11 @@ impl MappingPanel { // Important that neither session nor mapping is mutably borrowed while doing this // because state of our ReaLearn instance is not unlikely to be // queried as well! + let compartment = mapping.borrow().compartment(); let fx_snapshot = mapping .borrow() .target_model - .take_fx_snapshot(self.session().borrow().extended_context())?; + .take_fx_snapshot(self.session().borrow().extended_context(), compartment)?; mapping .borrow_mut() .target_model @@ -230,16 +231,19 @@ impl MappingPanel { &mapping.target_model, session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_2_LABEL_3), + mapping.compartment(), ); invalidat_target_line_3_expression_result( &mapping.target_model, session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_3_LABEL_3), + mapping.compartment(), ); invalidate_target_line_4_expression_result( &mapping.target_model, session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_4_LABEL_3), + mapping.compartment(), ); }); Ok(()) @@ -1562,7 +1566,7 @@ impl<'a> MutableMappingPanel<'a> { fn target_with_context(&'a self) -> TargetModelWithContext<'a> { self.mapping .target_model - .with_context(self.session.extended_context()) + .with_context(self.session.extended_context(), self.mapping.compartment()) } } @@ -2017,6 +2021,7 @@ impl<'a> ImmutableMappingPanel<'a> { self.target, self.session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_2_LABEL_3), + self.mapping.compartment(), ); } @@ -2100,7 +2105,9 @@ impl<'a> ImmutableMappingPanel<'a> { combo.fill_combo_box_indexed(track_combo_box_entries(project)); // Set if let Some(virtual_track) = self.target.virtual_track() { - if let Ok(track) = virtual_track.resolve(context) { + if let Ok(track) = + virtual_track.resolve(context, self.mapping.compartment()) + { let i = track.index().unwrap(); combo.select_combo_box_item_by_index(i as _).unwrap(); } else { @@ -2196,7 +2203,7 @@ impl<'a> ImmutableMappingPanel<'a> { fn target_with_context(&'a self) -> TargetModelWithContext<'a> { self.mapping .target_model - .with_context(self.session.extended_context()) + .with_context(self.session.extended_context(), self.mapping.compartment()) } fn invalidate_target_line_3(&self) { @@ -2235,6 +2242,7 @@ impl<'a> ImmutableMappingPanel<'a> { self.target, self.session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_3_LABEL_3), + self.mapping.compartment(), ); } @@ -2243,6 +2251,7 @@ impl<'a> ImmutableMappingPanel<'a> { self.target, self.session.extended_context(), self.view.require_control(root::ID_TARGET_LINE_4_LABEL_3), + self.mapping.compartment(), ); } @@ -2466,7 +2475,11 @@ impl<'a> ImmutableMappingPanel<'a> { ) { combo.show(); let context = self.session.extended_context(); - if let Ok(track) = self.target.with_context(context).effective_track() { + if let Ok(track) = self + .target + .with_context(context, self.mapping.compartment()) + .effective_track() + { // Fill let chain = if self.target.fx_is_input_fx.get() { track.input_fx_chain() @@ -2478,7 +2491,9 @@ impl<'a> ImmutableMappingPanel<'a> { if let Some(VirtualFx::ChainFx { chain_fx, .. }) = self.target.virtual_fx() { - if let Ok(fx) = chain_fx.resolve(&chain, context) { + if let Ok(fx) = + chain_fx.resolve(&chain, context, self.mapping.compartment()) + { combo .select_combo_box_item_by_index(fx.index() as _) .unwrap(); @@ -2543,7 +2558,11 @@ impl<'a> ImmutableMappingPanel<'a> { { combo.show(); let context = self.session.extended_context(); - if let Ok(fx) = self.target.with_context(context).fx() { + if let Ok(fx) = self + .target + .with_context(context, self.mapping.compartment()) + .fx() + { combo.fill_combo_box_indexed(fx_parameter_combo_box_entries(&fx)); let param_index = self.target.param_index.get(); combo @@ -2567,7 +2586,9 @@ impl<'a> ImmutableMappingPanel<'a> { if self.target.route_selector_type.get() == TrackRouteSelectorType::ById { combo.show(); let context = self.session.extended_context(); - let target_with_context = self.target.with_context(context); + let target_with_context = self + .target + .with_context(context, self.mapping.compartment()); if let Ok(track) = target_with_context.effective_track() { // Fill let route_type = self.target.route_type.get(); @@ -2587,7 +2608,11 @@ impl<'a> ImmutableMappingPanel<'a> { } else { // This is the real case. We use IDs. if let Ok(virtual_route) = self.target.virtual_track_route() { - if let Ok(route) = virtual_route.resolve(&track, context) { + if let Ok(route) = virtual_route.resolve( + &track, + context, + self.mapping.compartment(), + ) { let i = route.track_route_index().unwrap(); combo.select_combo_box_item_by_index(i as _).unwrap(); } else { @@ -4188,6 +4213,7 @@ fn invalidate_target_line_2_expression_result( target: &TargetModel, context: ExtendedProcessorContext, label: Window, + compartment: MappingCompartment, ) { let text = match target.category.get() { TargetCategory::Reaper => { @@ -4196,7 +4222,7 @@ fn invalidate_target_line_2_expression_result( { target .virtual_track() - .and_then(|t| t.calculated_track_index(context)) + .and_then(|t| t.calculated_track_index(context, compartment)) .map(|i| i.to_string()) } else { None @@ -4211,13 +4237,14 @@ fn invalidat_target_line_3_expression_result( target: &TargetModel, context: ExtendedProcessorContext, label: Window, + compartment: MappingCompartment, ) { let text = match target.category.get() { TargetCategory::Reaper => { if target.r#type.get().supports_fx() && target.fx_type.get() == VirtualFxType::Dynamic { target .virtual_chain_fx() - .and_then(|fx| fx.calculated_fx_index(context)) + .and_then(|fx| fx.calculated_fx_index(context, compartment)) .map(|i| i.to_string()) } else { None @@ -4232,6 +4259,7 @@ fn invalidate_target_line_4_expression_result( target: &TargetModel, context: ExtendedProcessorContext, label: Window, + compartment: MappingCompartment, ) { let text = match target.category.get() { TargetCategory::Reaper => match target.r#type.get() { @@ -4240,7 +4268,7 @@ fn invalidate_target_line_4_expression_result( { target .virtual_fx_parameter() - .and_then(|p| p.calculated_fx_parameter_index(context)) + .and_then(|p| p.calculated_fx_parameter_index(context, compartment)) .map(|i| i.to_string()) } t if t.supports_send() @@ -4248,7 +4276,7 @@ fn invalidate_target_line_4_expression_result( { target .track_route_selector() - .and_then(|p| p.calculated_route_index(context)) + .and_then(|p| p.calculated_route_index(context, compartment)) .map(|i| i.to_string()) } _ => None, diff --git a/main/src/infrastructure/ui/mapping_row_panel.rs b/main/src/infrastructure/ui/mapping_row_panel.rs index 6dd6bbcf7..f36b44002 100644 --- a/main/src/infrastructure/ui/mapping_row_panel.rs +++ b/main/src/infrastructure/ui/mapping_row_panel.rs @@ -158,7 +158,10 @@ impl MappingRowPanel { // Prevent error on project close return; } - let target_model_string = mapping.target_model.with_context(context).to_string(); + let target_model_string = mapping + .target_model + .with_context(context, mapping.compartment()) + .to_string(); self.view .require_window() .require_control(root::ID_MAPPING_ROW_TARGET_LABEL_TEXT) diff --git a/main/src/infrastructure/ui/mapping_rows_panel.rs b/main/src/infrastructure/ui/mapping_rows_panel.rs index b26cb32b8..92bb88b84 100644 --- a/main/src/infrastructure/ui/mapping_rows_panel.rs +++ b/main/src/infrastructure/ui/mapping_rows_panel.rs @@ -349,7 +349,7 @@ impl MappingRowsPanel { if let Some(filter_target) = main_state.target_filter.get_ref() { let mapping_target = match mapping .target_model - .with_context(session.extended_context()) + .with_context(session.extended_context(), mapping.compartment()) .create_target() { Ok(CompoundMappingTarget::Reaper(t)) => t,