Skip to content

Commit

Permalink
#231 Make conditional activation also work for controller mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Mar 22, 2021
1 parent 99aecee commit 7b36d86
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 21 deletions.
65 changes: 51 additions & 14 deletions main/src/domain/main_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,18 +468,17 @@ impl<EH: DomainEventHandler> MainProcessor<EH> {
self.parameters = *parameters;
self.event_handler
.handle_event(DomainEvent::UpdatedAllParameters(parameters));
// Activation is only supported for main mappings
// Mappings with virtual targets can only exist in the controller compartment
// and the mappings in there don't support conditional activation. However,
// REAPER targets in the controller compartment can use <Dynamic> and therefore
// might need a refresh in response to parameter changes.
for compartment in MappingCompartment::enum_iter() {
let mut mapping_activation_changes: Vec<ActivationChange> = vec![];
let mut target_activation_changes: Vec<ActivationChange> = vec![];
let mut changed_mappings = vec![];
let mut unused_sources =
self.currently_feedback_enabled_sources(compartment, false);
for m in &mut self.mappings[compartment].values_mut() {
self.currently_feedback_enabled_sources(compartment, true);
for m in all_mappings_in_compartment_mut(
&mut self.mappings,
&mut self.mappings_with_virtual_targets,
compartment,
) {
if m.activation_can_be_affected_by_parameters() {
if let Some(update) = m.update_activation(&self.parameters) {
mapping_activation_changes.push(update);
Expand Down Expand Up @@ -535,19 +534,18 @@ impl<EH: DomainEventHandler> MainProcessor<EH> {
self.parameters[index as usize] = value;
self.event_handler
.handle_event(DomainEvent::UpdatedParameter { index, value });
// Mapping activation is only supported for main mappings but target activation
// 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() {
let mut changed_mappings = HashSet::new();
let mut unused_sources =
self.currently_feedback_enabled_sources(compartment, false);
self.currently_feedback_enabled_sources(compartment, true);
// In order to avoid a mutable borrow of mappings and an immutable borrow of
// parameters at the same time, we need to separate into READ activation
// affects and WRITE activation updates.
// 1. Mapping activation: Read
let activation_effects: Vec<MappingActivationEffect> = self.mappings
[compartment]
.values()
let activation_effects: Vec<MappingActivationEffect> = self
.all_mappings_in_compartment(compartment)
.filter_map(|m| {
m.check_activation_effect(&self.parameters, index, previous_value)
})
Expand All @@ -557,13 +555,22 @@ impl<EH: DomainEventHandler> MainProcessor<EH> {
.into_iter()
.filter_map(|eff| {
changed_mappings.insert(eff.id);
let m = self.mappings[compartment].get_mut(&eff.id)?;
let m = get_normal_or_virtual_target_mapping_mut(
&mut self.mappings,
&mut self.mappings_with_virtual_targets,
compartment,
eff.id,
)?;
m.update_activation_from_effect(eff)
})
.collect();
// 3. Target refreshment and determine unused sources
let mut target_activation_changes: Vec<ActivationChange> = vec![];
for m in &mut self.mappings[compartment].values_mut() {
for m in all_mappings_in_compartment_mut(
&mut self.mappings,
&mut self.mappings_with_virtual_targets,
compartment,
) {
if m.target_can_be_affected_by_parameters() {
let context =
ExtendedProcessorContext::new(&self.context, &self.parameters);
Expand Down Expand Up @@ -988,6 +995,7 @@ impl<EH: DomainEventHandler> MainProcessor<EH> {
.collect()
}

// TODO-high Check if we need to call this with include_virtual == true sometimes
fn currently_feedback_enabled_sources(
&self,
compartment: MappingCompartment,
Expand Down Expand Up @@ -1327,3 +1335,32 @@ fn control_main_mappings_virtual(
})
.collect()
}

/// Includes virtual mappings if the controller mapping compartment is queried.
fn all_mappings_in_compartment_mut<'a>(
mappings: &'a mut EnumMap<MappingCompartment, HashMap<MappingId, MainMapping>>,
mappings_with_virtual_targets: &'a mut HashMap<MappingId, MainMapping>,
compartment: MappingCompartment,
) -> impl Iterator<Item = &'a mut MainMapping> {
mappings[compartment].values_mut().chain(
mappings_with_virtual_targets
.values_mut()
// Include virtual target mappings if we are talking about controller compartment.
.filter(move |_| compartment == MappingCompartment::ControllerMappings),
)
}

fn get_normal_or_virtual_target_mapping_mut<'a>(
mappings: &'a mut EnumMap<MappingCompartment, HashMap<MappingId, MainMapping>>,
mappings_with_virtual_targets: &'a mut HashMap<MappingId, MainMapping>,
compartment: MappingCompartment,
id: MappingId,
) -> Option<&'a mut MainMapping> {
mappings[compartment].get_mut(&id).or(
if compartment == MappingCompartment::ControllerMappings {
mappings_with_virtual_targets.get_mut(&id)
} else {
None
},
)
}
10 changes: 5 additions & 5 deletions main/src/domain/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,11 @@ impl MainMapping {
}

pub fn is_active(&self) -> bool {
self.has_virtual_target() || (self.is_active_1 && self.is_active_2)
self.is_active_1 && self.is_active_2
}

fn is_effectively_active(&self) -> bool {
self.has_virtual_target() || (self.is_active() && self.core.options.target_is_active)
self.is_active() && self.core.options.target_is_active
}

pub fn is_effectively_on(&self) -> bool {
Expand Down Expand Up @@ -538,15 +538,15 @@ impl RealTimeMapping {
}

fn is_effectively_active(&self) -> bool {
self.has_virtual_target() || (self.is_active && self.core.options.target_is_active)
self.is_active && self.core.options.target_is_active
}

fn is_effectively_active_ignoring_target_activation(&self) -> bool {
self.has_virtual_target() || self.is_active
self.is_active
}

fn is_effectively_active_ignoring_mapping_activation(&self) -> bool {
self.has_virtual_target() || self.core.options.target_is_active
self.core.options.target_is_active
}

pub fn update_target_activation(&mut self, is_active: bool) {
Expand Down
4 changes: 2 additions & 2 deletions main/src/domain/real_time_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ impl RealTimeProcessor {
self.log_debug_info(normal_task_count);
}
UpdateMappingActivations(compartment, activation_updates) => {
debug!(self.logger, "Update mapping activations...");
debug!(self.logger, "Updating mapping activations...");
// Apply updates
for update in activation_updates.iter() {
if let Some(m) = self.mappings[compartment].get_mut(&update.id) {
Expand Down Expand Up @@ -968,7 +968,7 @@ pub enum NormalRealTimeTask {
},
/// This takes care of propagating target activation states (for non-virtual mappings).
UpdateTargetActivations(MappingCompartment, Vec<ActivationChange>),
/// Updates the activation state of multiple mappings (for non-virtual mappings).
/// Updates the activation state of multiple mappings.
///
/// The given vector contains updates just for affected mappings. This is because when a
/// parameter update occurs we can determine in a very granular way which targets are affected.
Expand Down

0 comments on commit 7b36d86

Please sign in to comment.