Skip to content

Commit

Permalink
#325 "Navigate within group" target: Skip disabled/inactive mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Sep 16, 2021
1 parent a1f7ad2 commit e581fa0
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 72 deletions.
35 changes: 15 additions & 20 deletions main/src/application/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ pub struct Session {
controller_preset_manager: Box<dyn PresetManager<PresetType = ControllerPreset>>,
main_preset_manager: Box<dyn PresetManager<PresetType = MainPreset>>,
main_preset_link_manager: Box<dyn PresetLinkManager>,
/// The mappings which are on (enabled + control or feedback enabled + mapping active + target active)
on_mappings: Prop<HashSet<QualifiedMappingId>>,
instance_state: SharedInstanceState,
global_feedback_audio_hook_task_sender: &'static RealTimeSender<FeedbackAudioHookTask>,
global_osc_feedback_task_sender: &'static crossbeam_channel::Sender<OscFeedbackTask>,
Expand Down Expand Up @@ -231,7 +229,6 @@ impl Session {
controller_preset_manager: Box::new(controller_manager),
main_preset_manager: Box::new(main_preset_manager),
main_preset_link_manager: Box::new(preset_link_manager),
on_mappings: Default::default(),
instance_state,
global_feedback_audio_hook_task_sender,
global_osc_feedback_task_sender,
Expand Down Expand Up @@ -282,10 +279,11 @@ impl Session {
actual_real_source: &RealSource,
) -> Option<&SharedMapping> {
let actual_virt_source = self.virtualize_if_possible(actual_real_source);
let instance_state = self.instance_state.borrow();
use CompoundMappingSource::*;
self.mappings(compartment).find(|m| {
let m = m.borrow();
if !self.on_mappings.get_ref().contains(&m.qualified_id()) {
if !instance_state.mapping_is_on(m.qualified_id()) {
return false;
}
let mapping_source = m.source_model.create_source();
Expand Down Expand Up @@ -634,6 +632,7 @@ impl Session {
}

fn virtualize_if_possible(&self, source: &RealSource) -> Option<VirtualSource> {
let instance_state = self.instance_state.borrow();
for m in self.mappings(MappingCompartment::ControllerMappings) {
let m = m.borrow();
if !m.control_is_enabled.get() {
Expand All @@ -642,7 +641,7 @@ impl Session {
if m.target_model.category.get() != TargetCategory::Virtual {
continue;
}
if !self.on_mappings.get_ref().contains(&m.qualified_id()) {
if !instance_state.mapping_is_on(m.qualified_id()) {
// Since virtual mappings support conditional activation, too!
continue;
}
Expand Down Expand Up @@ -1777,13 +1776,7 @@ impl Session {
}

pub fn mapping_is_on(&self, id: QualifiedMappingId) -> bool {
self.on_mappings.get_ref().contains(&id)
}

pub fn on_mappings_changed(
&self,
) -> impl LocalObservable<'static, Item = (), Err = ()> + 'static {
self.on_mappings.changed()
self.instance_state.borrow().mapping_is_on(id)
}

fn log_debug_info_internal(&self) {
Expand Down Expand Up @@ -2140,16 +2133,18 @@ impl DomainEventHandler for WeakSession {
.learn_source(source, allow_virtual_sources);
}
UpdatedOnMappings(on_mappings) => {
session.borrow_mut().on_mappings.set(on_mappings);
session
.borrow()
.instance_state
.borrow_mut()
.set_on_mappings(on_mappings);
}
UpdatedSingleMappingOnState(event) => {
session.borrow_mut().on_mappings.mut_in_place(|m| {
if event.is_on {
m.insert(event.id);
} else {
m.remove(&event.id);
}
});
session
.borrow()
.instance_state
.borrow_mut()
.set_mapping_on(event.id, event.is_on);
}
TargetValueChanged(e) => {
// If the session is borrowed already, just let it be. It happens only in a very
Expand Down
7 changes: 7 additions & 0 deletions main/src/domain/eventing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ pub struct TargetValueChangedEvent<'a> {

pub trait DomainEventHandler: Debug {
fn handle_event(&self, event: DomainEvent);

fn notify_mapping_matched(&self, compartment: MappingCompartment, mapping_id: MappingId) {
self.handle_event(DomainEvent::MappingMatched(MappingMatchedEvent::new(
compartment,
mapping_id,
)));
}
}

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
Expand Down
47 changes: 39 additions & 8 deletions main/src/domain/instance_state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::base::AsyncNotifier;
use crate::base::{AsyncNotifier, Prop};
use crate::domain::{
ClipPlayState, ClipSlot, GroupId, MappingCompartment, MappingId, SlotContent, SlotDescriptor,
SlotPlayOptions,
ClipPlayState, ClipSlot, GroupId, MappingCompartment, MappingId, QualifiedMappingId,
SlotContent, SlotDescriptor, SlotPlayOptions,
};
use enum_map::EnumMap;
use helgoboss_learn::UnitValue;
Expand All @@ -11,7 +11,7 @@ use rx_util::Notifier;
use rxrust::prelude::*;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::rc::Rc;

Expand All @@ -26,6 +26,8 @@ pub struct InstanceState {
slot_contents_changed_subject: LocalSubject<'static, (), ()>,
mappings_by_group: EnumMap<MappingCompartment, HashMap<GroupId, Vec<MappingId>>>,
active_mapping_by_group: EnumMap<MappingCompartment, HashMap<GroupId, MappingId>>,
/// The mappings which are on (enabled + control or feedback enabled + mapping active + target active)
on_mappings: Prop<HashSet<QualifiedMappingId>>,
}

impl InstanceState {
Expand All @@ -38,9 +40,34 @@ impl InstanceState {
slot_contents_changed_subject: Default::default(),
mappings_by_group: Default::default(),
active_mapping_by_group: Default::default(),
on_mappings: Default::default(),
}
}

pub fn mapping_is_on(&self, id: QualifiedMappingId) -> bool {
self.on_mappings.get_ref().contains(&id)
}

pub fn on_mappings_changed(
&self,
) -> impl LocalObservable<'static, Item = (), Err = ()> + 'static {
self.on_mappings.changed()
}

pub fn set_on_mappings(&mut self, on_mappings: HashSet<QualifiedMappingId>) {
self.on_mappings.set(on_mappings);
}

pub fn set_mapping_on(&mut self, id: QualifiedMappingId, is_on: bool) {
self.on_mappings.mut_in_place(|m| {
if is_on {
m.insert(id);
} else {
m.remove(&id);
}
});
}

/// Sets the ID of the currently active mapping within the given group.
pub fn set_active_mapping_within_group(
&mut self,
Expand Down Expand Up @@ -94,13 +121,17 @@ impl InstanceState {
}
}

pub fn get_mappings_within_group(
pub fn get_on_mappings_within_group(
&self,
compartment: MappingCompartment,
group_id: GroupId,
) -> Option<&[MappingId]> {
let vec = &self.mappings_by_group[compartment].get(&group_id)?;
Some(&vec)
) -> impl Iterator<Item = MappingId> + '_ {
self.mappings_by_group[compartment]
.get(&group_id)
.into_iter()
.flatten()
.copied()
.filter(move |id| self.mapping_is_on(QualifiedMappingId::new(compartment, *id)))
}

pub fn process_transport_change(&mut self, new_play_state: PlayState) {
Expand Down
21 changes: 8 additions & 13 deletions main/src/domain/main_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use crate::domain::{
FeedbackResolution, FeedbackSendBehavior, FeedbackValue, GroupId, HitInstructionContext,
InstanceFeedbackEvent, InstanceOrchestrationEvent, IoUpdatedEvent, MainMapping,
MainSourceMessage, MappingActivationEffect, MappingCompartment, MappingControlResult,
MappingId, MappingMatchedEvent, MidiDestination, MidiSource, NormalRealTimeTask,
OrderedMappingIdSet, OrderedMappingMap, OscDeviceId, OscFeedbackTask, ProcessorContext,
QualifiedMappingId, QualifiedSource, RealFeedbackValue, RealSource, RealTimeSender,
MappingId, MidiDestination, MidiSource, NormalRealTimeTask, OrderedMappingIdSet,
OrderedMappingMap, OscDeviceId, OscFeedbackTask, ProcessorContext, QualifiedMappingId,
QualifiedSource, RealFeedbackValue, RealSource, RealTimeSender,
RealearnMonitoringFxParameterValueChangedEvent, RealearnTarget, ReaperMessage, ReaperTarget,
SharedInstanceState, SmallAsciiString, SourceFeedbackValue, SourceReleasedEvent,
TargetValueChangedEvent, UpdatedSingleMappingOnStateEvent, VirtualSourceValue, CLIP_SLOT_COUNT,
Expand Down Expand Up @@ -2175,14 +2175,6 @@ impl<EH: DomainEventHandler> Basics<EH> {
}
}

pub fn notify_mapping_matched(&self, compartment: MappingCompartment, mapping_id: MappingId) {
self.event_handler
.handle_event(DomainEvent::MappingMatched(MappingMatchedEvent::new(
compartment,
mapping_id,
)));
}

pub fn process_group_interaction(
&self,
collections: &mut Collections,
Expand Down Expand Up @@ -2417,7 +2409,8 @@ impl<EH: DomainEventHandler> Basics<EH> {
.filter(|m| m.control_is_effectively_on())
.flat_map(|m| {
if let Some(virtual_source_value) = m.control_virtualizing(msg) {
self.notify_mapping_matched(MappingCompartment::ControllerMappings, m.id());
self.event_handler
.notify_mapping_matched(MappingCompartment::ControllerMappings, m.id());
self.process_main_mappings_with_virtual_sources(
main_mappings,
virtual_source_value,
Expand Down Expand Up @@ -2769,7 +2762,9 @@ fn control_mapping_stage_one<EH: DomainEventHandler>(
control_value: ControlValue,
options: ControlOptions,
) -> MappingControlResult {
basics.notify_mapping_matched(m.compartment(), m.id());
basics
.event_handler
.notify_mapping_matched(m.compartment(), m.id());
m.control_from_mode(
control_value,
options,
Expand Down
54 changes: 27 additions & 27 deletions main/src/domain/targets/navigate_within_group_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ pub struct NavigateWithinGroupTarget {
}

impl NavigateWithinGroupTarget {
fn count(&self, context: ControlContext) -> Result<u32, &'static str> {
let count = context
fn count(&self, context: ControlContext) -> u32 {
context
.instance_state
.borrow()
.get_mappings_within_group(self.compartment, self.group_id)
.ok_or("group doesn't exist")?
.len();
Ok(count as _)
.get_on_mappings_within_group(self.compartment, self.group_id)
.count() as _
}
}

Expand All @@ -35,8 +33,8 @@ impl RealearnTarget for NavigateWithinGroupTarget {
(
ControlType::AbsoluteDiscrete {
atomic_step_size: {
let count = self.count(context).unwrap_or(0);
convert_count_to_step_size(count as _)
let count = self.count(context);
convert_count_to_step_size(count)
},
},
TargetCharacter::Discrete,
Expand All @@ -48,13 +46,12 @@ impl RealearnTarget for NavigateWithinGroupTarget {
value: ControlValue,
context: MappingControlContext,
) -> Result<HitInstructionReturnValue, &'static str> {
// TODO-high Exclude control disabled or mapping disabled/inactive mappings
let value = value.to_absolute_value()?;
let mut instance_state = context.control_context.instance_state.borrow_mut();
let desired_mapping_id = {
let mapping_ids = instance_state
.get_mappings_within_group(self.compartment, self.group_id)
.ok_or("group doesn't exist")?;
let mapping_ids: Vec<_> = instance_state
.get_on_mappings_within_group(self.compartment, self.group_id)
.collect();
let count = mapping_ids.len();
let desired_index = match value {
AbsoluteValue::Continuous(v) => convert_unit_to_discrete_value(v, count as _),
Expand Down Expand Up @@ -87,6 +84,9 @@ impl RealearnTarget for NavigateWithinGroupTarget {
} else {
continue;
};
context
.domain_event_handler
.notify_mapping_matched(m.compartment(), m.id());
let res = m.control_from_target_directly(
context.control_context,
context.logger,
Expand Down Expand Up @@ -127,7 +127,7 @@ impl RealearnTarget for NavigateWithinGroupTarget {
input: UnitValue,
context: ControlContext,
) -> Result<u32, &'static str> {
let count = self.count(context)?;
let count = self.count(context);
Ok(convert_unit_to_discrete_value(input, count))
}

Expand All @@ -136,16 +136,17 @@ impl RealearnTarget for NavigateWithinGroupTarget {
value: u32,
context: ControlContext,
) -> Result<UnitValue, &'static str> {
let count = self.count(context)?;
let count = self.count(context);
Ok(convert_discrete_to_unit_value(value, count as _))
}

fn is_available(&self, context: ControlContext) -> bool {
context
.instance_state
.borrow()
.get_mappings_within_group(self.compartment, self.group_id)
.is_some()
.get_on_mappings_within_group(self.compartment, self.group_id)
.count()
> 0
}

fn value_changed_from_instance_feedback_event(
Expand All @@ -171,17 +172,16 @@ impl<'a> Target<'a> for NavigateWithinGroupTarget {
if let Some(mapping_id) =
instance_state.get_active_mapping_within_group(self.compartment, self.group_id)
{
if let Some(mapping_ids) =
instance_state.get_mappings_within_group(self.compartment, self.group_id)
{
if mapping_ids.len() > 0 {
let max_value = mapping_ids.len() - 1;
if let Some(index) = mapping_ids.iter().position(|id| *id == mapping_id) {
return Some(AbsoluteValue::Discrete(Fraction::new(
index as _,
max_value as _,
)));
}
let mapping_ids: Vec<_> = instance_state
.get_on_mappings_within_group(self.compartment, self.group_id)
.collect();
if mapping_ids.len() > 0 {
let max_value = mapping_ids.len() - 1;
if let Some(index) = mapping_ids.iter().position(|id| *id == mapping_id) {
return Some(AbsoluteValue::Discrete(Fraction::new(
index as _,
max_value as _,
)));
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions main/src/infrastructure/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,9 @@ fn send_sessions_to_subscribed_clients() {

pub fn keep_informing_clients_about_session_events(shared_session: &SharedSession) {
let session = shared_session.borrow();
let instance_state = session.instance_state().borrow();
when(
session
instance_state
.on_mappings_changed()
.merge(session.mapping_list_changed().map_to(()))
.merge(session.mapping_changed().map_to(())),
Expand Down Expand Up @@ -914,14 +915,15 @@ fn get_controller_routing(session: &Session) -> ControllerRouting {
id: mp.id().to_string(),
name: mp.name().to_string(),
});
let instance_state = session.instance_state().borrow();
let routes = session
.mappings(MappingCompartment::ControllerMappings)
.filter_map(|m| {
let m = m.borrow();
if !m.visible_in_projection.get() {
return None;
}
let target_descriptor = if session.mapping_is_on(m.qualified_id()) {
let target_descriptor = if instance_state.mapping_is_on(m.qualified_id()) {
if m.target_model.category.get() == TargetCategory::Virtual {
// Virtual
let control_element = m.target_model.create_control_element();
Expand All @@ -932,7 +934,7 @@ fn get_controller_routing(session: &Session) -> ControllerRouting {
mp.visible_in_projection.get()
&& mp.source_model.category.get() == SourceCategory::Virtual
&& mp.source_model.create_control_element() == control_element
&& session.mapping_is_on(mp.qualified_id())
&& instance_state.mapping_is_on(mp.qualified_id())
});
let descriptors: Vec<_> = matching_main_mappings
.map(|m| {
Expand Down
Loading

0 comments on commit e581fa0

Please sign in to comment.