rytm_rs/object/sound/page/
lfo.rs

1// All casts in this file are intended or safe within the context of this library.
2//
3// One can change `allow` to `warn` to review them if necessary.
4#![allow(
5    clippy::cast_lossless,
6    clippy::cast_possible_truncation,
7    clippy::cast_sign_loss
8)]
9
10use crate::{
11    error::{ConversionError, ParameterError, RytmError},
12    object::sound::types::{LfoDestination, LfoMode, LfoMultiplier, LfoWaveform},
13    util::{
14        from_s_u16_t, i8_to_u8_midpoint_of_u8_input_range, scale_f32_to_u16, scale_u16_to_f32,
15        to_s_u16_t_union_a, u8_to_i8_midpoint_of_u8_input_range,
16    },
17};
18use rytm_rs_macro::parameter_range;
19use rytm_sys::ar_sound_t;
20use serde::{Deserialize, Serialize};
21
22/// Represents parameters in the lfo page of a sound.
23#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
24pub struct Lfo {
25    speed: i8,
26    multiplier: LfoMultiplier,
27    fade: i8,
28    destination: LfoDestination,
29    waveform: LfoWaveform,
30    start_phase_or_slew: u8,
31    mode: LfoMode,
32    depth: f32,
33}
34
35impl Default for Lfo {
36    fn default() -> Self {
37        Self {
38            speed: 48,
39            multiplier: LfoMultiplier::default(),
40            fade: 0,
41            destination: LfoDestination::default(),
42            waveform: LfoWaveform::default(),
43            start_phase_or_slew: 0,
44            mode: LfoMode::default(),
45            depth: 0.0,
46        }
47    }
48}
49
50impl TryFrom<&ar_sound_t> for Lfo {
51    type Error = ConversionError;
52    fn try_from(raw_sound: &ar_sound_t) -> Result<Self, Self::Error> {
53        // map range of 0..=32767 to -128.0..=127.99
54
55        let depth = scale_u16_to_f32(
56            unsafe { from_s_u16_t(raw_sound.lfo_depth) },
57            0u16,
58            32767u16,
59            -128f32,
60            127.99f32,
61        );
62
63        Ok(Self {
64            speed: u8_to_i8_midpoint_of_u8_input_range(raw_sound.lfo_speed, 0, 127),
65            multiplier: raw_sound.lfo_multiplier.try_into()?,
66            fade: u8_to_i8_midpoint_of_u8_input_range(raw_sound.lfo_fade, 0, 127),
67            destination: raw_sound.lfo_dest.try_into()?,
68            waveform: raw_sound.lfo_wav.try_into()?,
69            start_phase_or_slew: raw_sound.lfo_start_phase,
70            mode: raw_sound.lfo_mode.try_into()?,
71            depth,
72        })
73    }
74}
75
76impl Lfo {
77    pub(crate) fn apply_to_raw_sound(&self, raw_sound: &mut ar_sound_t) {
78        let depth = to_s_u16_t_union_a(scale_f32_to_u16(
79            self.depth, -128f32, 127.99f32, 0u16, 32767u16,
80        ));
81
82        raw_sound.lfo_speed = i8_to_u8_midpoint_of_u8_input_range(self.speed, 0, 127);
83        raw_sound.lfo_multiplier = self.multiplier.into();
84        raw_sound.lfo_fade = i8_to_u8_midpoint_of_u8_input_range(self.fade, 0, 127);
85        raw_sound.lfo_dest = self.destination.into();
86        raw_sound.lfo_wav = self.waveform.into();
87        raw_sound.lfo_start_phase = self.start_phase_or_slew;
88        raw_sound.lfo_mode = self.mode.into();
89        raw_sound.lfo_depth = depth;
90    }
91
92    /// Sets the speed of the LFO.
93    ///
94    /// Range: `-64..=63`
95    #[parameter_range(range = "speed:-64..=63")]
96    pub fn set_speed(&mut self, speed: isize) -> Result<(), RytmError> {
97        self.speed = speed as i8;
98        Ok(())
99    }
100
101    /// Sets the multiplier of the LFO.
102    pub fn set_multiplier(&mut self, multiplier: LfoMultiplier) {
103        self.multiplier = multiplier;
104    }
105
106    /// Sets the fade of the LFO.
107    ///
108    /// Range: `-64..=63`
109    #[parameter_range(range = "fade:-64..=63")]
110    pub fn set_fade(&mut self, fade: isize) -> Result<(), RytmError> {
111        self.fade = fade as i8;
112        Ok(())
113    }
114
115    /// Sets the destination of the LFO.
116    pub fn set_destination(&mut self, destination: LfoDestination) {
117        self.destination = destination;
118    }
119
120    /// Sets the waveform of the LFO.
121    pub fn set_waveform(&mut self, waveform: LfoWaveform) {
122        self.waveform = waveform;
123    }
124
125    /// Sets the depth of the LFO.
126    ///
127    /// Range: `-128.0..=127.99`
128    #[parameter_range(range = "depth:-128.0..=127.99")]
129    pub fn set_depth(&mut self, depth: f32) -> Result<(), RytmError> {
130        self.depth = depth;
131        Ok(())
132    }
133
134    /// Sets the start phase of the LFO.
135    ///
136    /// Range: `0..=127`
137    #[parameter_range(range = "start_phase_or_slew:0..=127")]
138    pub fn set_start_phase(&mut self, start_phase_or_slew: usize) -> Result<(), RytmError> {
139        self.start_phase_or_slew = start_phase_or_slew as u8;
140        Ok(())
141    }
142
143    /// Sets the mode of the LFO.
144    pub fn set_mode(&mut self, mode: LfoMode) {
145        self.mode = mode;
146    }
147
148    /// Returns the speed of the LFO.
149    ///
150    /// Range: `-64..=63`
151    pub const fn speed(&self) -> isize {
152        self.speed as isize
153    }
154
155    /// Returns the multiplier of the LFO.
156    pub const fn multiplier(&self) -> LfoMultiplier {
157        self.multiplier
158    }
159
160    /// Returns the fade of the LFO.
161    ///
162    /// Range: `-64..=63`
163    pub const fn fade(&self) -> isize {
164        self.fade as isize
165    }
166
167    /// Returns the destination of the LFO.
168    pub const fn destination(&self) -> LfoDestination {
169        self.destination
170    }
171
172    /// Returns the waveform of the LFO.
173    pub const fn waveform(&self) -> LfoWaveform {
174        self.waveform
175    }
176
177    /// Returns the start phase of the LFO.
178    ///
179    /// Range: `0..=127`
180    pub const fn start_phase_or_slew(&self) -> usize {
181        self.start_phase_or_slew as usize
182    }
183
184    /// Returns the mode of the LFO.
185    pub const fn mode(&self) -> LfoMode {
186        self.mode
187    }
188
189    /// Returns the depth of the LFO.
190    ///
191    /// Range: `-128.0..=127.99`
192    pub const fn depth(&self) -> f32 {
193        self.depth
194    }
195}