@@ -114,10 +114,10 @@ impl Default for PannerOptions {
114
114
}
115
115
}
116
116
117
- #[ derive( Debug , Copy , Clone ) ]
118
117
enum ControlMessage {
119
118
DistanceModel ( u8 ) ,
120
- PanningModel ( u8 ) ,
119
+ // Box this payload - one large variant can penalize the memory layout of this enum
120
+ PanningModel ( Box < Option < HrtfState > > ) ,
121
121
RefDistance ( f64 ) ,
122
122
MaxDistance ( f64 ) ,
123
123
RollOffFactor ( f64 ) ,
@@ -340,7 +340,7 @@ impl PannerNode {
340
340
/// Can panic when loading HRIR-sphere
341
341
#[ allow( clippy:: missing_panics_doc) ]
342
342
pub fn new < C : BaseAudioContext > ( context : & C , options : PannerOptions ) -> Self {
343
- let node = context. register ( move |registration| {
343
+ let node = context. register ( |registration| {
344
344
use crate :: spatial:: PARAM_OPTS ;
345
345
346
346
let PannerOptions {
@@ -382,12 +382,6 @@ impl PannerNode {
382
382
param_oy. set_value_at_time ( orientation_y, 0. ) ;
383
383
param_oz. set_value_at_time ( orientation_z, 0. ) ;
384
384
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 ( ) ;
390
-
391
385
let render = PannerRenderer {
392
386
position_x : render_px,
393
387
position_y : render_py,
@@ -402,10 +396,7 @@ impl PannerNode {
402
396
cone_inner_angle,
403
397
cone_outer_angle,
404
398
cone_outer_gain,
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) ) ,
399
+ hrtf_state : None ,
409
400
tail_time_counter : 0 ,
410
401
} ;
411
402
@@ -439,6 +430,9 @@ impl PannerNode {
439
430
. base ( )
440
431
. connect_listener_to_panner ( node. registration ( ) . id ( ) ) ;
441
432
433
+ // load the HRTF sphere if requested
434
+ node. set_panning_model ( options. panning_model ) ;
435
+
442
436
node
443
437
}
444
438
@@ -553,11 +547,21 @@ impl PannerNode {
553
547
self . panning_model . load ( Ordering :: Acquire ) . into ( )
554
548
}
555
549
550
+ #[ allow( clippy:: missing_panics_doc) ] // loading the provided HRTF will not panic
556
551
pub fn set_panning_model ( & self , value : PanningModelType ) {
557
- let value = value as u8 ;
558
- self . panning_model . store ( value, Ordering :: Release ) ;
552
+ let hrtf_option = match value {
553
+ PanningModelType :: EqualPower => None ,
554
+ PanningModelType :: HRTF => {
555
+ let resource = include_bytes ! ( "../../resources/IRC_1003_C.bin" ) ;
556
+ let sample_rate = self . context ( ) . sample_rate ( ) as u32 ;
557
+ let hrir_sphere = HrirSphere :: new ( & resource[ ..] , sample_rate) . unwrap ( ) ;
558
+ Some ( HrtfState :: new ( hrir_sphere) )
559
+ }
560
+ } ;
561
+
562
+ self . panning_model . store ( value as u8 , Ordering :: Release ) ;
559
563
self . registration
560
- . post_message ( ControlMessage :: PanningModel ( value ) ) ;
564
+ . post_message ( ControlMessage :: PanningModel ( Box :: new ( hrtf_option ) ) ) ;
561
565
}
562
566
}
563
567
@@ -577,17 +581,13 @@ struct PannerRenderer {
577
581
orientation_y : AudioParamId ,
578
582
orientation_z : AudioParamId ,
579
583
distance_model : DistanceModelType ,
580
- panning_model : PanningModelType ,
581
584
ref_distance : f64 ,
582
585
max_distance : f64 ,
583
586
rolloff_factor : f64 ,
584
587
cone_inner_angle : f64 ,
585
588
cone_outer_angle : f64 ,
586
589
cone_outer_gain : f64 ,
587
- // hrtf engine to be used if panning model is set to "hrtf"
588
- // @note - we keep the Some as a workaround of borrow reasons in process,
589
- // this is quite dirty should be improved
590
- hrtf_state : Option < HrtfState > ,
590
+ hrtf_state : Option < HrtfState > , // use EqualPower panning model if `None`
591
591
tail_time_counter : usize ,
592
592
}
593
593
@@ -609,20 +609,14 @@ impl AudioProcessor for PannerRenderer {
609
609
// only handle mono for now (todo issue #44)
610
610
output. mix ( 1 , ChannelInterpretation :: Speakers ) ;
611
611
612
- // for borrow reasons, take the hrtf_state out of self
613
- let mut hrtf_state = self . hrtf_state . take ( ) ;
614
-
615
612
// early exit for silence
616
613
if input. is_silent ( ) {
617
614
// HRTF panner has tail time equal to the max length of the impulse response buffers
618
615
// (12 ms)
619
- let tail_time = match self . panning_model {
620
- PanningModelType :: EqualPower => false ,
621
- PanningModelType :: HRTF => {
622
- hrtf_state. as_ref ( ) . unwrap ( ) . tail_time_samples ( ) > self . tail_time_counter
623
- }
616
+ let tail_time = match & self . hrtf_state {
617
+ None => false ,
618
+ Some ( hrtf_state) => hrtf_state. tail_time_samples ( ) > self . tail_time_counter ,
624
619
} ;
625
-
626
620
if !tail_time {
627
621
return false ;
628
622
}
@@ -633,6 +627,9 @@ impl AudioProcessor for PannerRenderer {
633
627
// convert mono to identical stereo
634
628
output. mix ( 2 , ChannelInterpretation :: Speakers ) ;
635
629
630
+ // for borrow reasons, take the hrtf_state out of self
631
+ let mut hrtf_state = self . hrtf_state . take ( ) ;
632
+
636
633
// source parameters (Panner)
637
634
let source_position_x = params. get ( & self . position_x ) ;
638
635
let source_position_y = params. get ( & self . position_y ) ;
@@ -698,9 +695,7 @@ impl AudioProcessor for PannerRenderer {
698
695
}
699
696
} ) ;
700
697
701
- if self . panning_model == PanningModelType :: HRTF {
702
- let Some ( hrtf_state) = & mut hrtf_state else { unreachable ! ( ) } ;
703
-
698
+ if let Some ( hrtf_state) = & mut hrtf_state {
704
699
// HRTF panning - always k-rate so take a single value from the a-rate iter
705
700
let SpatialParams {
706
701
dist_gain,
@@ -800,16 +795,16 @@ impl AudioProcessor for PannerRenderer {
800
795
}
801
796
802
797
fn onmessage ( & mut self , msg : & mut dyn Any ) {
803
- if let Some ( control) = msg. downcast_ref :: < ControlMessage > ( ) {
798
+ if let Some ( control) = msg. downcast_mut :: < ControlMessage > ( ) {
804
799
match control {
805
800
ControlMessage :: DistanceModel ( value) => self . distance_model = ( * value) . into ( ) ,
806
- ControlMessage :: PanningModel ( value) => self . panning_model = ( * value) . into ( ) ,
807
801
ControlMessage :: RefDistance ( value) => self . ref_distance = * value,
808
802
ControlMessage :: MaxDistance ( value) => self . max_distance = * value,
809
803
ControlMessage :: RollOffFactor ( value) => self . rolloff_factor = * value,
810
804
ControlMessage :: ConeInnerAngle ( value) => self . cone_inner_angle = * value,
811
805
ControlMessage :: ConeOuterAngle ( value) => self . cone_outer_angle = * value,
812
806
ControlMessage :: ConeOuterGain ( value) => self . cone_outer_gain = * value,
807
+ ControlMessage :: PanningModel ( value) => self . hrtf_state = value. take ( ) ,
813
808
}
814
809
815
810
return ;
0 commit comments