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,270 @@
use crate::{Interval, UnitIncrement, UnitValue};
use derive_more::Display;
use helgoboss_midi::U7;
use std::cmp;
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::ops::Sub;
/// A positive discrete number most likely representing a step count.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Display)]
pub struct DiscreteValue(u32);
impl DiscreteValue {
/// Creates the discrete value.
pub const fn new(value: u32) -> DiscreteValue {
DiscreteValue(value)
}
/// Returns the underlying number.
pub fn get(&self) -> u32 {
self.0
}
/// Converts this discrete value to a discrete increment, either negative or positive depending
/// on the given signum. Returns `None` if this value is zero.
pub fn to_increment(self, signum: i32) -> Option<DiscreteIncrement> {
if self.is_zero() {
return None;
}
Some(unsafe { DiscreteIncrement::new_unchecked(signum * self.0 as i32) })
}
/// Returns whether this is 0.
pub fn is_zero(&self) -> bool {
self.0 == 0
}
/// Clamps this value to the given interval bounds.
pub fn clamp_to_interval(&self, interval: &Interval<DiscreteValue>) -> DiscreteValue {
DiscreteValue::new(num::clamp(
self.0,
interval.min_val().0,
interval.max_val().0,
))
}
}
impl std::str::FromStr for DiscreteValue {
type Err = &'static str;
fn from_str(source: &str) -> Result<Self, Self::Err> {
let primitive = u32::from_str(source).map_err(|_| "not a valid positive integer")?;
Ok(DiscreteValue(primitive))
}
}
impl Sub for DiscreteValue {
type Output = u32;
fn sub(self, rhs: Self) -> Self::Output {
self.0 - rhs.0
}
}
/// A discrete number representing a positive or negative increment, never 0 (otherwise it wouldn't
/// be an increment after all).
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
#[serde(try_from = "i32")]
pub struct DiscreteIncrement(i32);
impl Display for DiscreteIncrement {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:+}", self.0)
}
}
impl DiscreteIncrement {
pub const NEGATIVE_MIN: Self = Self(-1);
pub const POSITIVE_MIN: Self = Self(1);
/// Creates the discrete increment. Panics if the given number is 0.
pub fn new(increment: i32) -> DiscreteIncrement {
assert_ne!(increment, 0);
DiscreteIncrement(increment)
}
/// Creates the discrete increment. Panics if the given number is 0.
pub fn new_checked(increment: i32) -> Option<DiscreteIncrement> {
if increment == 0 {
return None;
}
Some(DiscreteIncrement(increment))
}
/// Checks preconditions only in debug build. Should only be used if you want to squeeze out
/// every last bit of performance and you are super sure that the number meets the
/// preconditions. This constructor is offered because it's not unlikely that a lot of those
/// values will be constructed in audio thread.
///
/// # Safety
///
/// Make sure the given increment is not zero.
pub unsafe fn new_unchecked(increment: i32) -> DiscreteIncrement {
debug_assert_ne!(increment, 0);
DiscreteIncrement(increment)
}
/// Creates an increment from the given MIDI control-change value assuming that the device
/// emitting the control-change messages uses a protocol which is called "Relative 1" in REAPER.
///
/// - 127 = decrement; 0 = none; 1 = increment
/// - 127 > value > 63 results in higher decrement step sizes (64 possible decrement step sizes)
/// - 1 < value <= 63 results in higher increment step sizes (63 possible increment step sizes)
pub fn from_encoder_1_value(value: U7) -> Result<DiscreteIncrement, &'static str> {
let value = value.get();
if value == 0 {
return Err("increment must not be zero");
}
let increment = if value <= 63 {
// Zero and increment
value as i32
} else {
// Decrement
-((128 - value) as i32)
};
Ok(unsafe { DiscreteIncrement::new_unchecked(increment) })
}
/// Creates an increment from the given MIDI control-change value assuming that the device
/// emitting the control-change messages uses a protocol which is called "Relative 2" in REAPER.
///
/// - 63 = decrement; 64 = none; 65 = increment
/// - 63 > value >= 0 results in higher decrement step sizes (64 possible decrement step sizes)
/// - 65 < value <= 127 results in higher increment step sizes (63 possible increment step
/// sizes)
pub fn from_encoder_2_value(value: U7) -> Result<DiscreteIncrement, &'static str> {
let value = value.get();
if value == 64 {
return Err("increment must not be zero");
}
let increment = if value > 64 {
// Zero and increment
(value - 64) as i32
} else {
// Decrement
-((64 - value) as i32)
};
Ok(unsafe { DiscreteIncrement::new_unchecked(increment) })
}
/// Creates an increment from the given MIDI control-change value assuming that the device
/// emitting the control-change messages uses a protocol which is called "Relative 3" in REAPER.
///
/// - 65 = decrement; 0 = none; 1 = increment
/// - 65 < value <= 127 results in higher decrement step sizes (63 possible decrement step
/// sizes)
/// - 1 < value <= 64 results in higher increment step sizes (64 possible increment step sizes)
pub fn from_encoder_3_value(value: U7) -> Result<DiscreteIncrement, &'static str> {
let value = value.get();
if value == 0 {
return Err("increment must not be zero");
}
let increment = if value <= 64 {
// Zero and increment
value as i32
} else {
// Decrement
-((value - 64) as i32)
};
Ok(unsafe { DiscreteIncrement::new_unchecked(increment) })
}
/// Clamps this increment to the given interval bounds.
pub fn clamp_to_interval(&self, interval: &Interval<DiscreteIncrement>) -> DiscreteIncrement {
// Step count interval: (-3, 4) = -3, -2, -1, 1, 2, 3, 4
// 1 => -3
// 2 => -2
// 7 => 4
// 8 => 4
// Step count interval: (4, 10) = 4, 5, 6, 7, 8, 9, 10
// 1 => 4
// 2 => 5
// 7 => 10
// 8 => 10
let positive_increment = self.0.unsigned_abs();
let min: i32 = interval.min_val().get();
let max: i32 = interval.max_val().get();
let count: u32 = if min < 0 && max > 0 {
(max - min) as u32
} else {
(max - min) as u32 + 1
};
let addend: u32 = cmp::min(positive_increment - 1, count - 1);
let sum = min + addend as i32;
let skip_zero_sum = if min < 0 && sum >= 0 { sum + 1 } else { sum };
let clamped = cmp::min(skip_zero_sum, max);
DiscreteIncrement::new(clamped)
}
/// Converts this discrete increment into a discrete value thereby "losing" its direction.
pub fn to_value(self) -> DiscreteValue {
DiscreteValue::new(self.0.unsigned_abs())
}
/// Switches the direction of this increment (makes a positive one negative and vice versa).
pub fn inverse(&self) -> DiscreteIncrement {
unsafe { DiscreteIncrement::new_unchecked(-self.0) }
}
pub fn with_direction(&self, signum: i32) -> DiscreteIncrement {
let abs = self.0.abs();
let inner = if signum >= 0 { abs } else { -abs };
DiscreteIncrement::new(inner)
}
/// Returns the underlying number.
pub fn get(&self) -> i32 {
self.0
}
/// Returns if this increment is positive.
pub fn is_positive(&self) -> bool {
self.0 >= 0
}
/// Returns the signum (-1 if it's a negative increment, otherwise +1).
pub fn signum(&self) -> i32 {
if self.is_positive() {
1
} else {
-1
}
}
/// Returns a unit increment or None in case of 0.0.
///
/// The unit increment is built by creating a multiple of the given atomic unit value (= minimum
/// step size) and clamping the result if it exceeds the unit interval.
pub fn to_unit_increment(self, atomic_unit_value: UnitValue) -> Option<UnitIncrement> {
let positive_large = self.to_value().get() as f64 * atomic_unit_value.get();
let unit_value = UnitValue::new(num::clamp(positive_large, 0.0, 1.0));
unit_value.to_increment(self.signum())
}
}
impl Sub for DiscreteIncrement {
type Output = i32;
fn sub(self, rhs: Self) -> Self::Output {
self.0 - rhs.0
}
}
impl TryFrom<i32> for DiscreteIncrement {
type Error = &'static str;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value == 0 {
return Err("zero is not an increment");
}
Ok(DiscreteIncrement::new(value))
}
}
/// Convenience method for creating an interval of discrete increments.
pub fn create_discrete_increment_interval(min: i32, max: i32) -> Interval<DiscreteIncrement> {
Interval::new(DiscreteIncrement::new(min), DiscreteIncrement::new(max))
}