|
1 | 1 | //! AudioParam interface
|
2 | 2 | use std::any::Any;
|
3 | 3 | use std::slice::{Iter, IterMut};
|
4 |
| -use std::sync::atomic::{Ordering}; |
5 |
| -use std::sync::{Arc, OnceLock}; |
| 4 | +use std::sync::atomic::Ordering; |
| 5 | +use std::sync::{Arc, Mutex, OnceLock}; |
6 | 6 |
|
7 | 7 | use arrayvec::ArrayVec;
|
8 | 8 |
|
@@ -274,11 +274,9 @@ pub(crate) struct AudioParamRaw {
|
274 | 274 | default_value: f32, // immutable
|
275 | 275 | min_value: f32, // immutable
|
276 | 276 | max_value: f32, // immutable
|
277 |
| - automation_rate: AutomationRate, |
278 | 277 | automation_rate_constrained: bool,
|
| 278 | + automation_rate: Arc<Mutex<AutomationRate>>, |
279 | 279 | current_value: Arc<AtomicF32>,
|
280 |
| - // TODO Use `Weak` instead of `Arc`. The `AudioParamProcessor` is the owner. |
281 |
| - // shared_parts: Arc<AudioParamShared>, |
282 | 280 | }
|
283 | 281 |
|
284 | 282 | impl AudioNode for AudioParam {
|
@@ -320,21 +318,24 @@ impl AudioNode for AudioParam {
|
320 | 318 | impl AudioParam {
|
321 | 319 | /// Current value of the automation rate of the AudioParam
|
322 | 320 | pub fn automation_rate(&self) -> AutomationRate {
|
323 |
| - self.raw_parts.automation_rate |
| 321 | + *self.raw_parts.automation_rate.lock().unwrap() |
324 | 322 | }
|
325 | 323 |
|
326 | 324 | /// Update the current value of the automation rate of the AudioParam
|
327 | 325 | ///
|
328 | 326 | /// # Panics
|
329 | 327 | ///
|
330 | 328 | /// Some nodes have automation rate constraints and may panic when updating the value.
|
331 |
| - pub fn set_automation_rate(&mut self, value: AutomationRate) { |
| 329 | + pub fn set_automation_rate(&self, value: AutomationRate) { |
332 | 330 | if self.raw_parts.automation_rate_constrained && value != self.automation_rate() {
|
333 | 331 | panic!("InvalidStateError: automation rate cannot be changed for this param");
|
334 | 332 | }
|
335 | 333 |
|
336 |
| - self.raw_parts.automation_rate = value; |
| 334 | + let mut guard = self.raw_parts.automation_rate.lock().unwrap(); |
| 335 | + *guard = value; |
337 | 336 | self.registration().post_message(value);
|
| 337 | + drop(guard); // drop guard after sending message to prevent out of order arrivals on |
| 338 | + // concurrent access |
338 | 339 | }
|
339 | 340 |
|
340 | 341 | pub(crate) fn set_automation_rate_constrained(&mut self, value: bool) {
|
@@ -387,7 +388,9 @@ impl AudioParam {
|
387 | 388 | assert_is_finite(value);
|
388 | 389 | // current_value should always be clamped
|
389 | 390 | let clamped = value.clamp(self.raw_parts.min_value, self.raw_parts.max_value);
|
390 |
| - self.raw_parts.current_value.store(clamped, Ordering::Release); |
| 391 | + self.raw_parts |
| 392 | + .current_value |
| 393 | + .store(clamped, Ordering::Release); |
391 | 394 |
|
392 | 395 | // this event is meant to update param intrinsic value before any calculation
|
393 | 396 | // is done, will behave as SetValueAtTime with `time == block_timestamp`
|
@@ -1583,8 +1586,8 @@ pub(crate) fn audio_param_pair(
|
1583 | 1586 | default_value,
|
1584 | 1587 | max_value,
|
1585 | 1588 | min_value,
|
1586 |
| - automation_rate, |
1587 | 1589 | automation_rate_constrained: false,
|
| 1590 | + automation_rate: Arc::new(Mutex::new(automation_rate)), |
1588 | 1591 | current_value: Arc::clone(¤t_value),
|
1589 | 1592 | },
|
1590 | 1593 | };
|
@@ -1679,7 +1682,7 @@ mod tests {
|
1679 | 1682 | min_value: 0.,
|
1680 | 1683 | max_value: 1.,
|
1681 | 1684 | };
|
1682 |
| - let (mut param, _render) = audio_param_pair(opts, context.mock_registration()); |
| 1685 | + let (param, _render) = audio_param_pair(opts, context.mock_registration()); |
1683 | 1686 |
|
1684 | 1687 | param.set_automation_rate(AutomationRate::K);
|
1685 | 1688 | assert_eq!(param.automation_rate(), AutomationRate::K);
|
|
0 commit comments