Reorganize top-level directories with clearer naming convention

app -> app-desktop-macos, presets -> app-presets, server -> remote-server,
daw-config-reaper -> osc-config-daw, plugin-reaper-realearn -> plugin-reaper-relearn.
Updated run.py and presets.py path references accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Paul Lipscomb
2026-07-15 17:51:05 -04:00
parent e58f06d9fa
commit 7ecc718f5d
2256 changed files with 11 additions and 5 deletions
@@ -0,0 +1,320 @@
use crate::base::eel;
use crate::domain::{
CompartmentParamIndex, CompartmentParams, EffectiveParamValue, ExpressionEvaluator, MappingId,
RawParamValue, COMPARTMENT_PARAMETER_COUNT, EXPRESSION_NONE_VALUE,
};
use base::hash_util::NonCryptoHashSet;
use base::regex;
use helgoboss_learn::AbsoluteValue;
use std::error::Error;
#[derive(Debug)]
pub enum ActivationCondition {
Always,
Modifiers(Vec<ModifierCondition>),
Program {
param_index: CompartmentParamIndex,
program_index: u32,
},
// Boxed in order to keep the enum variants at a similar size (clippy gave that hint)
Eel(Box<EelCondition>),
Expression(Box<ExpressionCondition>),
TargetValue {
lead_mapping: Option<MappingId>,
condition: Box<ExpressionEvaluator>,
},
}
impl ActivationCondition {
/// Returns if this activation condition can be affected by parameter changes in general.
pub fn can_be_affected_by_parameters(&self) -> bool {
!matches!(self, ActivationCondition::Always)
}
/// Returns the referenced lead mapping of this activation condition if it's a target-value
/// based one.
pub fn target_value_lead_mapping(&self) -> Option<MappingId> {
match self {
ActivationCondition::TargetValue {
lead_mapping: Some(m),
..
} => Some(*m),
_ => None,
}
}
/// Returns if this activation condition is fulfilled in presence of the given set of
/// parameters.
///
/// Returns `None` if the condition doesn't depend on parameter values (in which case it must
/// be evaluated in other ways).
pub fn is_fulfilled(&self, params: &CompartmentParams) -> Option<bool> {
use ActivationCondition::*;
let res = match self {
Always => true,
Modifiers(conditions) => modifier_conditions_are_fulfilled(conditions, params),
Program {
param_index,
program_index,
} => program_condition_is_fulfilled(*param_index, *program_index, params),
Eel(condition) => {
condition.notify_params_changed(params);
condition.is_fulfilled()
}
Expression(condition) => condition.is_fulfilled(params),
TargetValue { .. } => return None,
};
Some(res)
}
/// Returns `Some` if the given value update affects the mapping's activation state and if the
/// resulting state is on or off.
///
/// Passing a `None` target value means the target is inactive.
pub fn process_target_value_update(
&self,
lead_mapping_id: MappingId,
target_value: Option<AbsoluteValue>,
) -> Option<bool> {
match self {
ActivationCondition::TargetValue {
lead_mapping: Some(rm),
condition,
} if lead_mapping_id == *rm => {
let y = match target_value {
None => EXPRESSION_NONE_VALUE,
Some(v) => v.to_unit_value().get(),
};
let result = condition.evaluate_with_additional_vars(|name, _| match name {
"none" => Some(EXPRESSION_NONE_VALUE),
"y" => Some(y),
_ => None,
});
result.ok().map(|v| v > 0.0)
}
_ => None,
}
}
/// Returns `Some` if the given value update affects the mapping's activation state and if the
/// resulting state is on or off.
///
/// Other parameters in the given array should not have changed! That's especially important
/// for the EEL activation condition which will ignore the other values in the array for
/// performance reasons and just look at the difference (because it has the array already
/// stored in the EEL VM). For performance reasons as well, the other activation condition types
/// don't store anything and read the given parameter array.
///
/// Attention: For EEL condition, this has a side effect!
/// TODO-low This is not visible because it's &self.
pub fn process_param_update(
&self,
params: &CompartmentParams,
// Changed index
index: CompartmentParamIndex,
// Previous value at changed index
previous_value: RawParamValue,
) -> Option<bool> {
use ActivationCondition::*;
let is_fulfilled = match self {
Modifiers(conditions) => {
let is_affected = conditions.iter().any(|c| {
c.is_affected_by_param_change(
index,
previous_value,
params.at(index).raw_value(),
)
});
if !is_affected {
return None;
}
modifier_conditions_are_fulfilled(conditions, params)
}
Program {
param_index,
program_index,
} => {
if index != *param_index {
return None;
}
program_condition_is_fulfilled(*param_index, *program_index, params)
}
Eel(condition) => {
let is_affected = condition
.notify_param_changed(index, params.at(index).effective_value().into());
if !is_affected {
return None;
}
condition.is_fulfilled()
}
Expression(condition) => condition.is_fulfilled(params),
Always => return None,
// This conditional activation doesn't depend on parameter values, it's evaluated
// in other ways.
TargetValue { .. } => return None,
};
Some(is_fulfilled)
}
}
fn modifier_conditions_are_fulfilled(
conditions: &[ModifierCondition],
params: &CompartmentParams,
) -> bool {
conditions
.iter()
.all(|condition| condition.is_fulfilled(params))
}
fn program_condition_is_fulfilled(
param_index: CompartmentParamIndex,
program_index: u32,
params: &CompartmentParams,
) -> bool {
let current_program_index = match params.at(param_index).effective_value() {
EffectiveParamValue::Continuous(v) => {
// If no count given for the parameter, we just assume a count of 100.
(v * 99.0).round() as u32
}
EffectiveParamValue::Discrete(v) => v,
};
current_program_index == program_index
}
fn param_value_is_on(value: f32) -> bool {
value > 0.0
}
#[derive(Debug)]
pub struct ModifierCondition {
param_index: CompartmentParamIndex,
is_on: bool,
}
impl ModifierCondition {
pub fn new(param_index: CompartmentParamIndex, is_on: bool) -> ModifierCondition {
ModifierCondition { param_index, is_on }
}
pub fn is_affected_by_param_change(
&self,
index: CompartmentParamIndex,
previous_value: RawParamValue,
value: RawParamValue,
) -> bool {
self.param_index == index && param_value_is_on(previous_value) != param_value_is_on(value)
}
/// Returns if this activation condition is fulfilled in presence of the given set of
/// parameters.
pub fn is_fulfilled(&self, params: &CompartmentParams) -> bool {
let param_value = params.at(self.param_index).raw_value();
let is_on = param_value_is_on(param_value);
is_on == self.is_on
}
}
#[derive(Debug)]
pub struct ExpressionCondition {
evaluator: ExpressionEvaluator,
}
impl ExpressionCondition {
pub fn compile(expression: &str) -> Result<Self, Box<dyn Error>> {
let condition = Self {
evaluator: ExpressionEvaluator::compile(expression)?,
};
Ok(condition)
}
pub fn is_fulfilled(&self, params: &CompartmentParams) -> bool {
let result = self.evaluator.evaluate_with_params(params);
result.map(|v| v > 0.0).unwrap_or(false)
}
}
#[derive(Debug)]
pub struct EelCondition {
// Declared above VM in order to be dropped before VM is dropped.
program: eel::Program,
// The existence in memory and the Drop is important.
_vm: eel::Vm,
params: [Option<eel::Variable>; COMPARTMENT_PARAMETER_COUNT as usize],
y: eel::Variable,
}
impl EelCondition {
// Compiles the given script and creates an appropriate condition.
pub fn compile(eel_script: &str) -> Result<EelCondition, String> {
if eel_script.trim().is_empty() {
return Err("script empty".to_string());
}
let vm = eel::Vm::new();
let program = vm.compile(eel_script)?;
let y = vm.register_variable("y");
let params = {
let mut array = [None; COMPARTMENT_PARAMETER_COUNT as usize];
for i in extract_used_param_indexes(eel_script).into_iter() {
let variable_name = format!("p{}", i + 1);
let variable = vm.register_variable(&variable_name);
// Set initial value so we can calculate the initial activation result after
// compilation. All subsequent parameter value changes are done incrementally via
// single parameter updates (which is more efficient).
unsafe {
// We initialize this to zero. It will be constantly updated to current values
// in main processor.
variable.set(0.0);
}
array[i as usize] = Some(variable);
}
array
};
Ok(EelCondition {
program,
_vm: vm,
params,
y,
})
}
pub fn notify_params_changed(&self, params: &CompartmentParams) {
for (i, p) in self.params.iter().enumerate() {
let i = CompartmentParamIndex::try_from(i as u32).unwrap();
if let Some(v) = p {
unsafe {
v.set(params.at(i).effective_value().into());
}
}
}
}
/// Returns true if activation might have changed.
pub fn notify_param_changed(&self, param_index: CompartmentParamIndex, value: f64) -> bool {
if let Some(v) = &self.params[param_index.get() as usize] {
unsafe {
v.set(value);
}
true
} else {
false
}
}
pub fn is_fulfilled(&self) -> bool {
let result = unsafe {
self.program.execute();
self.y.get()
};
result > 0.0
}
}
fn extract_used_param_indexes(eel_script: &str) -> NonCryptoHashSet<u32> {
let param_regex = regex!(r"\bp([0-9]+)\b");
param_regex
.captures_iter(eel_script)
.flat_map(|m| m[1].parse())
.filter(|i| *i >= 1 && *i <= COMPARTMENT_PARAMETER_COUNT)
.map(|i: u32| i - 1)
.collect()
}