Skip to content

Commit 0107afc

Browse files
committed
fix: weird editor cache issue
1 parent 9ce5fef commit 0107afc

File tree

1 file changed

+66
-97
lines changed

1 file changed

+66
-97
lines changed

src/node/audio_buffer_source.rs

Lines changed: 66 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use std::any::Any;
2-
use std::cell::OnceCell;
3-
use std::sync::atomic::{AtomicBool, Ordering};
2+
use std::cell::{OnceCell, RefCell};
43

54
use crate::buffer::AudioBuffer;
65
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
76
use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
87
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
9-
use crate::AtomicF64;
108
use crate::RENDER_QUANTUM_SIZE;
119

1210
use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
@@ -21,9 +19,10 @@ use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
2119
// float playbackRate = 1;
2220
// };
2321
//
24-
// @note - Does not extend AudioNodeOptions because AudioNodeOptions are
25-
// useless for source nodes as they instruct how to upmix the inputs.
26-
// This is a common source of confusion, see e.g. https://github.com/mdn/content/pull/18472
22+
// @note - Does extend AudioNodeOptions but they are useless for source nodes as
23+
// they instruct how to upmix the inputs.
24+
// This is a common source of confusion, see e.g. https://github.com/mdn/content/pull/18472, and
25+
// an issue in the spec, see discussion in https://github.com/WebAudio/web-audio-api/issues/2496
2726
#[derive(Clone, Debug)]
2827
pub struct AudioBufferSourceOptions {
2928
pub buffer: Option<AudioBuffer>,
@@ -53,54 +52,15 @@ struct PlaybackInfo {
5352
k: f32,
5453
}
5554

56-
// The strategy for loop parameters is as follow: store the given values
57-
// in the `loop_control` thread safe instance which only lives in control
58-
// thread(s) and send a message to the render thread which stores the raw values.
59-
// Values between control and render side might be desynchronised for little while
60-
// but the developer experience will appear more logical, i.e.
61-
// ```no_run
62-
// node.set_loop(true);
63-
// println!("{:?}", node.loop_());
64-
// > true // is guaranteed
65-
// ```
66-
// Note that this seems to be the strategy used by Firefox
67-
#[derive(Debug)]
68-
struct LoopControl {
69-
loop_: AtomicBool,
70-
loop_start: AtomicF64,
71-
loop_end: AtomicF64,
72-
}
73-
74-
// Uses the canonical ordering for handover of values,
75-
// i.e. `Acquire` on load and `Release` on store.
76-
impl LoopControl {
77-
fn loop_(&self) -> bool {
78-
self.loop_.load(Ordering::Acquire)
79-
}
80-
81-
fn set_loop(&self, loop_: bool) {
82-
self.loop_.store(loop_, Ordering::Release);
83-
}
84-
85-
fn loop_start(&self) -> f64 {
86-
self.loop_start.load(Ordering::Acquire)
87-
}
88-
89-
fn set_loop_start(&self, loop_start: f64) {
90-
self.loop_start.store(loop_start, Ordering::Release);
91-
}
92-
93-
fn loop_end(&self) -> f64 {
94-
self.loop_end.load(Ordering::Acquire)
95-
}
96-
97-
fn set_loop_end(&self, loop_end: f64) {
98-
self.loop_end.store(loop_end, Ordering::Release);
99-
}
55+
#[derive(Debug, Clone)]
56+
struct LoopState {
57+
pub is_looping: bool,
58+
pub start: f64,
59+
pub end: f64,
10060
}
10161

10262
/// Instructions to start or stop processing
103-
#[derive(Debug, Copy, Clone)]
63+
#[derive(Debug, Clone)]
10464
enum ControlMessage {
10565
StartWithOffsetAndDuration(f64, f64, f64),
10666
Stop(f64),
@@ -143,12 +103,17 @@ enum ControlMessage {
143103
///
144104
pub struct AudioBufferSourceNode {
145105
registration: AudioContextRegistration,
146-
loop_control: LoopControl,
147106
channel_config: ChannelConfig,
148107
detune: AudioParam, // has constraints, no a-rate
149108
playback_rate: AudioParam, // has constraints, no a-rate
150109
buffer: OnceCell<AudioBuffer>,
151-
source_started: AtomicBool,
110+
inner_state: RefCell<InnerState>,
111+
}
112+
113+
#[derive(Debug, Clone)]
114+
struct InnerState {
115+
loop_state: LoopState,
116+
source_started: bool,
152117
}
153118

154119
impl AudioNode for AudioBufferSourceNode {
@@ -185,9 +150,10 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
185150
}
186151

187152
fn stop_at(&self, when: f64) {
188-
if !self.source_started.load(Ordering::SeqCst) {
189-
panic!("InvalidStateError cannot stop before start");
190-
}
153+
assert!(
154+
self.inner_state.borrow().source_started,
155+
"InvalidStateError cannot stop before start"
156+
);
191157

192158
self.registration.post_message(ControlMessage::Stop(when));
193159
}
@@ -230,35 +196,36 @@ impl AudioBufferSourceNode {
230196
pr_param.set_automation_rate_constrained(true);
231197
pr_param.set_value(playback_rate);
232198

233-
let loop_control = LoopControl {
234-
loop_: AtomicBool::new(loop_),
235-
loop_start: AtomicF64::new(loop_start),
236-
loop_end: AtomicF64::new(loop_end),
199+
let loop_state = LoopState {
200+
is_looping: loop_,
201+
start: loop_start,
202+
end: loop_end,
237203
};
238204

239205
let renderer = AudioBufferSourceRenderer {
240206
start_time: f64::MAX,
241207
stop_time: f64::MAX,
242208
duration: f64::MAX,
243209
offset: 0.,
244-
loop_,
245-
loop_start,
246-
loop_end,
247210
buffer: None,
248211
detune: d_proc,
249212
playback_rate: pr_proc,
213+
loop_state: loop_state.clone(),
250214
render_state: AudioBufferRendererState::default(),
251215
ended_triggered: false,
252216
};
253217

218+
let inner_state = InnerState {
219+
loop_state,
220+
source_started: false,
221+
};
254222
let node = Self {
255223
registration,
256-
loop_control,
257224
channel_config: ChannelConfig::default(),
258225
detune: d_param,
259226
playback_rate: pr_param,
260227
buffer: OnceCell::new(),
261-
source_started: AtomicBool::new(false),
228+
inner_state: RefCell::new(inner_state),
262229
};
263230

264231
if let Some(buf) = buffer {
@@ -284,9 +251,12 @@ impl AudioBufferSourceNode {
284251
///
285252
/// Panics if the source was already started
286253
pub fn start_at_with_offset_and_duration(&self, start: f64, offset: f64, duration: f64) {
287-
if self.source_started.swap(true, Ordering::SeqCst) {
288-
panic!("InvalidStateError: Cannot call `start` twice");
289-
}
254+
let source_started = &mut self.inner_state.borrow_mut().source_started;
255+
assert!(
256+
!*source_started,
257+
"InvalidStateError: Cannot call `start` twice"
258+
);
259+
*source_started = true;
290260

291261
let control = ControlMessage::StartWithOffsetAndDuration(start, offset, duration);
292262
self.registration.post_message(control);
@@ -333,32 +303,32 @@ impl AudioBufferSourceNode {
333303

334304
/// Defines if the playback the [`AudioBuffer`] should be looped
335305
pub fn loop_(&self) -> bool {
336-
self.loop_control.loop_()
306+
self.inner_state.borrow().loop_state.is_looping
337307
}
338308

339309
pub fn set_loop(&self, value: bool) {
340-
self.loop_control.set_loop(value);
310+
self.inner_state.borrow_mut().loop_state.is_looping = value;
341311
self.registration.post_message(ControlMessage::Loop(value));
342312
}
343313

344314
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
345315
pub fn loop_start(&self) -> f64 {
346-
self.loop_control.loop_start()
316+
self.inner_state.borrow().loop_state.start
347317
}
348318

349319
pub fn set_loop_start(&self, value: f64) {
350-
self.loop_control.set_loop_start(value);
320+
self.inner_state.borrow_mut().loop_state.start = value;
351321
self.registration
352322
.post_message(ControlMessage::LoopStart(value));
353323
}
354324

355325
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
356326
pub fn loop_end(&self) -> f64 {
357-
self.loop_control.loop_end()
327+
self.inner_state.borrow().loop_state.end
358328
}
359329

360330
pub fn set_loop_end(&self, value: f64) {
361-
self.loop_control.set_loop_end(value);
331+
self.inner_state.borrow_mut().loop_state.end = value;
362332
self.registration
363333
.post_message(ControlMessage::LoopEnd(value));
364334
}
@@ -389,28 +359,26 @@ struct AudioBufferSourceRenderer {
389359
stop_time: f64,
390360
offset: f64,
391361
duration: f64,
392-
loop_: bool,
393-
loop_start: f64,
394-
loop_end: f64,
395362
buffer: Option<AudioBuffer>,
396363
detune: AudioParamId,
397364
playback_rate: AudioParamId,
365+
loop_state: LoopState,
398366
render_state: AudioBufferRendererState,
399367
ended_triggered: bool,
400368
}
401369

402370
impl AudioBufferSourceRenderer {
403-
fn handle_control_message(&mut self, control: ControlMessage) {
371+
fn handle_control_message(&mut self, control: &ControlMessage) {
404372
match control {
405373
ControlMessage::StartWithOffsetAndDuration(when, offset, duration) => {
406-
self.start_time = when;
407-
self.offset = offset;
408-
self.duration = duration;
374+
self.start_time = *when;
375+
self.offset = *offset;
376+
self.duration = *duration;
409377
}
410-
ControlMessage::Stop(when) => self.stop_time = when,
411-
ControlMessage::Loop(loop_) => self.loop_ = loop_,
412-
ControlMessage::LoopStart(loop_start) => self.loop_start = loop_start,
413-
ControlMessage::LoopEnd(loop_end) => self.loop_end = loop_end,
378+
ControlMessage::Stop(when) => self.stop_time = *when,
379+
ControlMessage::Loop(is_looping) => self.loop_state.is_looping = *is_looping,
380+
ControlMessage::LoopStart(loop_start) => self.loop_state.start = *loop_start,
381+
ControlMessage::LoopEnd(loop_end) => self.loop_state.end = *loop_end,
414382
}
415383
}
416384
}
@@ -431,10 +399,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
431399
let block_duration = dt * RENDER_QUANTUM_SIZE as f64;
432400
let next_block_time = scope.current_time + block_duration;
433401

434-
// grab all timing information
435-
let loop_ = self.loop_;
436-
let loop_start = self.loop_start;
437-
let loop_end = self.loop_end;
402+
let LoopState {
403+
is_looping,
404+
start: loop_start,
405+
end: loop_end,
406+
} = self.loop_state.clone();
438407

439408
// these will only be used if `loop_` is true, so no need for `Option`
440409
let mut actual_loop_start = 0.;
@@ -489,7 +458,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
489458
}
490459

491460
// 3. the end of the buffer has been reached.
492-
if !loop_ {
461+
if !is_looping {
493462
if computed_playback_rate > 0. && self.render_state.buffer_time >= buffer_duration {
494463
output.make_silent(); // also converts to mono
495464
if !self.ended_triggered {
@@ -594,15 +563,15 @@ impl AudioProcessor for AudioBufferSourceRenderer {
594563
*o = if buffer_index < end_index {
595564
buffer_channel[buffer_index]
596565
} else {
597-
if loop_ && buffer_index == end_index {
566+
if is_looping && buffer_index == end_index {
598567
loop_point_index = Some(index);
599568
// reset values for the rest of the block
600569
start_index = 0;
601570
offset = index;
602571
buffer_index = 0;
603572
}
604573

605-
if loop_ {
574+
if is_looping {
606575
buffer_channel[buffer_index]
607576
} else {
608577
0.
@@ -643,7 +612,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
643612
// ---------------------------------------------------------------
644613
// Slow track
645614
// ---------------------------------------------------------------
646-
if loop_ {
615+
if is_looping {
647616
if loop_start >= 0. && loop_end > 0. && loop_start < loop_end {
648617
actual_loop_start = loop_start;
649618
actual_loop_end = loop_end.min(buffer_duration);
@@ -675,19 +644,19 @@ impl AudioProcessor for AudioBufferSourceRenderer {
675644
if !self.render_state.started {
676645
self.offset += current_time - self.start_time;
677646

678-
if loop_ && computed_playback_rate >= 0. && self.offset >= actual_loop_end {
647+
if is_looping && computed_playback_rate >= 0. && self.offset >= actual_loop_end {
679648
self.offset = actual_loop_end;
680649
}
681650

682-
if loop_ && computed_playback_rate < 0. && self.offset < actual_loop_start {
651+
if is_looping && computed_playback_rate < 0. && self.offset < actual_loop_start {
683652
self.offset = actual_loop_start;
684653
}
685654

686655
self.render_state.buffer_time = self.offset;
687656
self.render_state.started = true;
688657
}
689658

690-
if loop_ {
659+
if is_looping {
691660
if !self.render_state.entered_loop {
692661
// playback began before or within loop, and playhead is now past loop start
693662
if self.offset < actual_loop_end
@@ -776,7 +745,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
776745

777746
fn onmessage(&mut self, msg: &mut dyn Any) {
778747
if let Some(control) = msg.downcast_ref::<ControlMessage>() {
779-
self.handle_control_message(*control);
748+
self.handle_control_message(control);
780749
return;
781750
};
782751

0 commit comments

Comments
 (0)