conformal_component/parameters/utils/constant_buffer_states.rs
1use std::collections::HashMap;
2
3use crate::{
4 events::NoteID,
5 synth::{
6 NumericGlobalExpression, NumericPerNoteExpression, SwitchGlobalExpression,
7 SynthParamBufferStates, SynthParamStates,
8 },
9};
10
11use super::super::{
12 BufferState, BufferStates, EnumBufferState, InternalValue, NumericBufferState,
13 PiecewiseLinearCurvePoint, States, SwitchBufferState, TimedValue,
14};
15use super::states_map::{StatesMap, SynthStatesMap};
16
17/// Simple implementation of [`BufferStates`] trait where every parameter is
18/// constant throughout the whole buffer.
19///
20/// This is in general useful for testing or other scenarios where you need
21/// to create a [`BufferStates`] object outside of a Conformal wrapper.
22#[derive(Clone, Debug, Default)]
23pub struct ConstantBufferStates<S> {
24 s: S,
25}
26
27impl<S: States> BufferStates for ConstantBufferStates<S> {
28 fn get_by_hash(
29 &self,
30 id_hash: super::super::IdHash,
31 ) -> std::option::Option<
32 BufferState<
33 impl Iterator<Item = PiecewiseLinearCurvePoint> + Clone,
34 impl Iterator<Item = TimedValue<u32>> + Clone,
35 impl Iterator<Item = TimedValue<bool>> + Clone,
36 >,
37 > {
38 match self.s.get_by_hash(id_hash) {
39 Some(InternalValue::Numeric(n)) => {
40 Some(BufferState::Numeric(NumericBufferState::<
41 std::iter::Empty<PiecewiseLinearCurvePoint>,
42 >::Constant(n)))
43 }
44 Some(InternalValue::Enum(e)) => Some(BufferState::Enum(EnumBufferState::<
45 std::iter::Empty<TimedValue<u32>>,
46 >::Constant(e))),
47 Some(InternalValue::Switch(s)) => Some(BufferState::Switch(SwitchBufferState::<
48 std::iter::Empty<TimedValue<bool>>,
49 >::Constant(s))),
50 None => None,
51 }
52 }
53}
54
55impl<S: SynthParamStates> SynthParamBufferStates for ConstantBufferStates<S> {
56 fn get_numeric_global_expression(
57 &self,
58 expression: NumericGlobalExpression,
59 ) -> NumericBufferState<impl Iterator<Item = PiecewiseLinearCurvePoint> + Clone> {
60 NumericBufferState::<std::iter::Empty<PiecewiseLinearCurvePoint>>::Constant(
61 self.s.get_numeric_global_expression(expression),
62 )
63 }
64
65 fn get_switch_global_expression(
66 &self,
67 expression: SwitchGlobalExpression,
68 ) -> SwitchBufferState<impl Iterator<Item = TimedValue<bool>> + Clone> {
69 SwitchBufferState::<std::iter::Empty<TimedValue<bool>>>::Constant(
70 self.s.get_switch_global_expression(expression),
71 )
72 }
73
74 fn get_numeric_expression_for_note(
75 &self,
76 expression: NumericPerNoteExpression,
77 note_id: NoteID,
78 ) -> NumericBufferState<impl Iterator<Item = PiecewiseLinearCurvePoint> + Clone> {
79 NumericBufferState::<std::iter::Empty<PiecewiseLinearCurvePoint>>::Constant(
80 self.s.get_numeric_expression_for_note(expression, note_id),
81 )
82 }
83}
84
85impl<S: States> ConstantBufferStates<S> {
86 /// Create a new [`ConstantBufferStates`] object from a [`States`] object.
87 pub fn new(s: S) -> Self {
88 Self { s }
89 }
90}
91
92impl ConstantBufferStates<StatesMap> {
93 /// Create a new [`ConstantBufferStates`] object from a list of `Info`s and `override`s.
94 ///
95 /// This creates a `ConstantBufferStates` with all parameters set to default values
96 /// for the whole buffer.
97 ///
98 /// Note that if you want to pass this into a synth, you should use
99 /// [`Self::new_override_synth_defaults`] instead.
100 ///
101 /// `overrides` work exactly as in [`override_defaults`].
102 ///
103 /// # Examples
104 ///
105 /// ```
106 /// # use conformal_component::parameters::{StaticInfoRef, InternalValue, TypeSpecificInfoRef, ConstantBufferStates, BufferStates, NumericBufferState};
107 /// let infos = vec![
108 /// StaticInfoRef {
109 /// title: "Numeric",
110 /// short_title: "Numeric",
111 /// unique_id: "numeric",
112 /// flags: Default::default(),
113 /// type_specific: TypeSpecificInfoRef::Numeric {
114 /// default: 0.0,
115 /// valid_range: 0.0..=1.0,
116 /// units: None,
117 /// },
118 /// },
119 /// ];
120 /// let overrides = vec![("numeric", InternalValue::Numeric(0.5))].into_iter().collect();
121 /// let buffer_states = ConstantBufferStates::new_override_defaults(infos, &overrides);
122 /// match buffer_states.get_numeric("numeric") {
123 /// Some(NumericBufferState::Constant(0.5)) => (),
124 /// _ => panic!("Expected constant value of 0.5"),
125 /// };
126 /// ```
127 pub fn new_override_defaults<'a, S: AsRef<str> + 'a>(
128 infos: impl IntoIterator<Item = super::super::InfoRef<'a, S>> + 'a,
129 overrides: &HashMap<&'_ str, InternalValue>,
130 ) -> Self {
131 Self::new(StatesMap::new_override_defaults(infos, overrides))
132 }
133
134 /// Create a new [`ConstantBufferStates`] object from a list of `Info`s.
135 ///
136 /// Each parameter in `Info`s will be set to its default value for the whole buffer.
137 ///
138 /// Note that if you want to pass this into a synth, you should use
139 /// [`Self::new_synth_defaults`] instead.
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// # use conformal_component::parameters::{StaticInfoRef, InternalValue, TypeSpecificInfoRef, ConstantBufferStates, BufferStates, NumericBufferState};
145 /// let infos = vec![
146 /// StaticInfoRef {
147 /// title: "Numeric",
148 /// short_title: "Numeric",
149 /// unique_id: "numeric",
150 /// flags: Default::default(),
151 /// type_specific: TypeSpecificInfoRef::Numeric {
152 /// default: 0.0,
153 /// valid_range: 0.0..=1.0,
154 /// units: None,
155 /// },
156 /// },
157 /// ];
158 ///
159 /// let buffer_states = ConstantBufferStates::new_defaults(infos);
160 /// match buffer_states.get_numeric("numeric") {
161 /// Some(NumericBufferState::Constant(0.0)) => (),
162 /// _ => panic!("Expected constant value of 0.0"),
163 /// };
164 /// ```
165 pub fn new_defaults<'a, S: AsRef<str> + 'a>(
166 infos: impl IntoIterator<Item = super::super::InfoRef<'a, S>> + 'a,
167 ) -> Self {
168 Self::new_override_defaults(infos, &Default::default())
169 }
170}
171
172impl ConstantBufferStates<SynthStatesMap> {
173 /// Create a new [`ConstantBufferStates`] object to pass to a synth from a list of `Info`s and `override`s.
174 ///
175 /// This is similar to [`Self::new_override_defaults`], but it also includes expression controllers.
176 ///
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// # use conformal_component::parameters::{StaticInfoRef, InternalValue, TypeSpecificInfoRef, ConstantBufferStates, BufferStates, NumericBufferState, SynthStatesMap};
182 /// # use conformal_component::synth::{SynthParamBufferStates, NumericGlobalExpression};
183 ///
184 /// let infos = vec![
185 /// StaticInfoRef {
186 /// title: "Numeric",
187 /// short_title: "Numeric",
188 /// unique_id: "numeric",
189 /// flags: Default::default(),
190 /// type_specific: TypeSpecificInfoRef::Numeric {
191 /// default: 0.0,
192 /// valid_range: 0.0..=1.0,
193 /// units: None,
194 /// },
195 /// },
196 /// ];
197 /// let overrides = vec![
198 /// // You can override declared parameters
199 /// ("numeric", InternalValue::Numeric(0.5)),
200 /// ].into_iter().collect();
201 ///
202 /// // and you can override control parameters
203 /// let expression_overrides = vec![
204 /// (NumericGlobalExpression::ModWheel, 0.2),
205 /// ].into_iter().collect();
206 ///
207 /// let buffer_states = ConstantBufferStates::new_override_synth_defaults(infos, &overrides, &expression_overrides, &Default::default());
208 ///
209 /// // Overridden parameters get the values you passed in
210 /// match buffer_states.get_numeric("numeric") {
211 /// Some(NumericBufferState::Constant(0.5)) => (),
212 /// _ => panic!("Expected constant value of 0.5"),
213 /// };
214 /// match buffer_states.get_numeric_global_expression(NumericGlobalExpression::ModWheel) {
215 /// NumericBufferState::Constant(0.2) => (),
216 /// _ => panic!("Expected constant value of 0.2"),
217 /// };
218 ///
219 /// // Other parameters get their default values
220 /// match buffer_states.get_numeric_global_expression(NumericGlobalExpression::PitchBend) {
221 /// NumericBufferState::Constant(0.0) => (),
222 /// _ => panic!("Expected constant value of 0.0"),
223 /// };
224 /// ```
225 pub fn new_override_synth_defaults<'a, 'b: 'a>(
226 infos: impl IntoIterator<Item = super::super::InfoRef<'a, &'b str>> + 'a,
227 overrides: &HashMap<&'_ str, InternalValue>,
228 numeric_expression_overrides: &HashMap<NumericGlobalExpression, f32>,
229 switch_expression_overrides: &HashMap<SwitchGlobalExpression, bool>,
230 ) -> Self {
231 Self::new(SynthStatesMap::new_override_defaults(
232 infos,
233 overrides,
234 numeric_expression_overrides,
235 switch_expression_overrides,
236 ))
237 }
238
239 /// Create a new [`ConstantBufferStates`] object to pass to a synth from a list of `Info`s.
240 ///
241 /// Each parameter in `Info`s will be set to its default value for the whole buffer.
242 ///
243 /// This is similar to [`Self::new_defaults`], but it also includes expression controllers.
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// # use conformal_component::parameters::{StaticInfoRef, InternalValue, TypeSpecificInfoRef, ConstantBufferStates, BufferStates, NumericBufferState, SynthStatesMap};
249 /// # use conformal_component::synth::{SynthParamBufferStates, NumericGlobalExpression};
250 /// let infos = vec![
251 /// StaticInfoRef {
252 /// title: "Numeric",
253 /// short_title: "Numeric",
254 /// unique_id: "numeric",
255 /// flags: Default::default(),
256 /// type_specific: TypeSpecificInfoRef::Numeric {
257 /// default: 0.0,
258 /// valid_range: 0.0..=1.0,
259 /// units: None,
260 /// },
261 /// },
262 /// ];
263 ///
264 /// let buffer_states = ConstantBufferStates::new_synth_defaults(infos);
265 /// match buffer_states.get_numeric("numeric") {
266 /// Some(NumericBufferState::Constant(0.0)) => (),
267 /// _ => panic!("Expected constant value of 0.0"),
268 /// };
269 /// match buffer_states.get_numeric_global_expression(NumericGlobalExpression::ModWheel) {
270 /// NumericBufferState::Constant(0.0) => (),
271 /// _ => panic!("Expected constant value of 0.0"),
272 /// };
273 /// ```
274 pub fn new_synth_defaults<'a, 'b: 'a>(
275 infos: impl IntoIterator<Item = super::super::InfoRef<'a, &'b str>> + 'a,
276 ) -> Self {
277 Self::new_override_synth_defaults(
278 infos,
279 &Default::default(),
280 &Default::default(),
281 &Default::default(),
282 )
283 }
284}