Skip to content

Commit d086a96

Browse files
b-maorottier
authored andcommitted
refactor: use message passing
1 parent d432715 commit d086a96

File tree

1 file changed

+34
-39
lines changed

1 file changed

+34
-39
lines changed

src/node/panner.rs

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::any::Any;
22
use std::f32::consts::PI;
33
use std::sync::atomic::{AtomicU8, Ordering};
44

5-
use crossbeam_channel::{Receiver, Sender};
65
use float_eq::float_eq;
76
use hrtf::{HrirSphere, HrtfContext, HrtfProcessor, Vec3};
87

@@ -118,13 +117,13 @@ impl Default for PannerOptions {
118117
#[derive(Debug, Copy, Clone)]
119118
enum ControlMessage {
120119
DistanceModel(u8),
120+
PanningModel(u8),
121121
RefDistance(f64),
122122
MaxDistance(f64),
123123
RollOffFactor(f64),
124124
ConeInnerAngle(f64),
125125
ConeOuterAngle(f64),
126126
ConeOuterGain(f64),
127-
// Panning // @todo
128127
}
129128

130129
/// Assert that the channel count is valid for the PannerNode
@@ -291,8 +290,6 @@ pub struct PannerNode {
291290
max_distance: AtomicF64,
292291
rolloff_factor: AtomicF64,
293292
panning_model: AtomicU8,
294-
/// HRTF message bus to the renderer
295-
sender: Sender<Option<HrtfState>>,
296293
}
297294

298295
impl AudioNode for PannerNode {
@@ -385,9 +382,11 @@ impl PannerNode {
385382
param_oy.set_value_at_time(orientation_y, 0.);
386383
param_oz.set_value_at_time(orientation_z, 0.);
387384

388-
// Channel to send a HRTF processor to the renderer. A capacity of 1 suffices, it will
389-
// simply block the control thread when used concurrently
390-
let (sender, receiver) = crossbeam_channel::bounded(1);
385+
// @note - we just pass the hrtf engine to every created panner node
386+
// this might not be the best solution in terms of memory footprint
387+
let resource = include_bytes!("../../resources/IRC_1003_C.bin");
388+
let sample_rate = context.sample_rate() as u32;
389+
let hrir_sphere = HrirSphere::new(&resource[..], sample_rate).unwrap();
391390

392391
let render = PannerRenderer {
393392
position_x: render_px,
@@ -403,8 +402,10 @@ impl PannerNode {
403402
cone_inner_angle,
404403
cone_outer_angle,
405404
cone_outer_gain,
406-
hrtf_state: None,
407-
receiver,
405+
panning_model,
406+
// @note - The `Some`is just here as a dirty workaround of borrow
407+
// stuff in PannerRenderer::process
408+
hrtf_state: Some(HrtfState::new(hrir_sphere)),
408409
tail_time_counter: 0,
409410
};
410411

@@ -424,12 +425,9 @@ impl PannerNode {
424425
cone_inner_angle: AtomicF64::new(cone_inner_angle),
425426
cone_outer_angle: AtomicF64::new(cone_outer_angle),
426427
cone_outer_gain: AtomicF64::new(cone_outer_gain),
427-
sender,
428-
panning_model: AtomicU8::new(0),
428+
panning_model: AtomicU8::new(panning_model as u8),
429429
};
430430

431-
node.set_panning_model(panning_model);
432-
433431
// instruct to BaseContext to add the AudioListener if it has not already
434432
context.base().ensure_audio_listener_present();
435433

@@ -543,21 +541,11 @@ impl PannerNode {
543541
self.panning_model.load(Ordering::Acquire).into()
544542
}
545543

546-
// can panic when loading HRIR-sphere
547-
#[allow(clippy::missing_panics_doc)]
548544
pub fn set_panning_model(&self, value: PanningModelType) {
549-
let hrtf_option = match value {
550-
PanningModelType::EqualPower => None,
551-
PanningModelType::HRTF => {
552-
let resource = include_bytes!("../../resources/IRC_1003_C.bin");
553-
let sample_rate = self.context().sample_rate() as u32;
554-
let hrir_sphere = HrirSphere::new(&resource[..], sample_rate).unwrap();
555-
Some(HrtfState::new(hrir_sphere))
556-
}
557-
};
558-
559-
let _ = self.sender.send(hrtf_option); // can fail when render thread shut down
560-
self.panning_model.store(value as u8, Ordering::Release);
545+
let value = value as u8;
546+
self.panning_model.store(value, Ordering::Release);
547+
self.registration
548+
.post_message(ControlMessage::PanningModel(value));
561549
}
562550
}
563551

@@ -577,13 +565,16 @@ struct PannerRenderer {
577565
orientation_y: AudioParamId,
578566
orientation_z: AudioParamId,
579567
distance_model: DistanceModelType,
568+
panning_model: PanningModelType,
580569
ref_distance: f64,
581570
max_distance: f64,
582571
rolloff_factor: f64,
583572
cone_inner_angle: f64,
584573
cone_outer_angle: f64,
585574
cone_outer_gain: f64,
586-
receiver: Receiver<Option<HrtfState>>,
575+
// hrtf engine to be used if panning model is set to "hrtf"
576+
// @note - we keep the Some as a workaround of borrow reasons in process,
577+
// this is quite dirty should be improved
587578
hrtf_state: Option<HrtfState>,
588579
tail_time_counter: usize,
589580
}
@@ -606,30 +597,30 @@ impl AudioProcessor for PannerRenderer {
606597
// only handle mono for now (todo issue #44)
607598
output.mix(1, ChannelInterpretation::Speakers);
608599

600+
// for borrow reasons, take the hrtf_state out of self
601+
let mut hrtf_state = self.hrtf_state.take();
602+
609603
// early exit for silence
610604
if input.is_silent() {
611605
// HRTF panner has tail time equal to the max length of the impulse response buffers
612606
// (12 ms)
613-
let tail_time = match &self.hrtf_state {
614-
None => false,
615-
Some(hrtf_state) => hrtf_state.tail_time_samples() > self.tail_time_counter,
607+
let tail_time = match self.panning_model {
608+
PanningModelType::EqualPower => false,
609+
PanningModelType::HRTF => {
610+
hrtf_state.as_ref().unwrap().tail_time_samples() > self.tail_time_counter
611+
}
616612
};
613+
617614
if !tail_time {
618615
return false;
619616
}
617+
620618
self.tail_time_counter += RENDER_QUANTUM_SIZE;
621619
}
622620

623621
// convert mono to identical stereo
624622
output.mix(2, ChannelInterpretation::Speakers);
625623

626-
// handle changes in panning_model_type mandated from control thread
627-
if let Ok(hrtf_state) = self.receiver.try_recv() {
628-
self.hrtf_state = hrtf_state;
629-
}
630-
// for borrow reasons, take the hrtf_state out of self
631-
let mut hrtf_state = self.hrtf_state.take();
632-
633624
// source parameters (Panner)
634625
let source_position_x = params.get(&self.position_x);
635626
let source_position_y = params.get(&self.position_y);
@@ -695,14 +686,17 @@ impl AudioProcessor for PannerRenderer {
695686
}
696687
});
697688

698-
if let Some(hrtf_state) = &mut hrtf_state {
689+
if self.panning_model == PanningModelType::HRTF {
690+
let Some(hrtf_state) = &mut hrtf_state else { unreachable!() };
691+
699692
// HRTF panning - always k-rate so take a single value from the a-rate iter
700693
let SpatialParams {
701694
dist_gain,
702695
cone_gain,
703696
azimuth,
704697
elevation,
705698
} = a_rate_params.next().unwrap();
699+
706700
let new_distance_gain = cone_gain * dist_gain;
707701

708702
// convert az/el to cartesian coordinates to determine unit direction
@@ -797,6 +791,7 @@ impl AudioProcessor for PannerRenderer {
797791
if let Some(control) = msg.downcast_ref::<ControlMessage>() {
798792
match control {
799793
ControlMessage::DistanceModel(value) => self.distance_model = (*value).into(),
794+
ControlMessage::PanningModel(value) => self.panning_model = (*value).into(),
800795
ControlMessage::RefDistance(value) => self.ref_distance = *value,
801796
ControlMessage::MaxDistance(value) => self.max_distance = *value,
802797
ControlMessage::RollOffFactor(value) => self.rolloff_factor = *value,

0 commit comments

Comments
 (0)