1
1
use std:: any:: Any ;
2
+ use std:: collections:: HashMap ;
2
3
use std:: f32:: consts:: PI ;
4
+ use std:: sync:: { Mutex , OnceLock } ;
3
5
4
6
use float_eq:: float_eq;
5
7
use hrtf:: { HrirSphere , HrtfContext , HrtfProcessor , Vec3 } ;
@@ -13,6 +15,24 @@ use super::{
13
15
AudioNode , ChannelConfig , ChannelConfigOptions , ChannelCountMode , ChannelInterpretation ,
14
16
} ;
15
17
18
+ /// Load the HRIR sphere for the given sample_rate
19
+ ///
20
+ /// The included data contains the impulse responses at 44100 Hertz, so it needs to be resampled
21
+ /// for other values (which can easily take 100s of milliseconds). Therefore cache the result (per
22
+ /// sample rate) in a global variable and clone it every time a new panner is created.
23
+ fn load_hrir_sphere ( sample_rate : u32 ) -> HrirSphere {
24
+ static INSTANCE : OnceLock < Mutex < HashMap < u32 , HrirSphere > > > = OnceLock :: new ( ) ;
25
+ let cache = INSTANCE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
26
+ let mut guard = cache. lock ( ) . unwrap ( ) ;
27
+ guard
28
+ . entry ( sample_rate)
29
+ . or_insert_with ( || {
30
+ let resource = include_bytes ! ( "../../resources/IRC_1003_C.bin" ) ;
31
+ HrirSphere :: new ( & resource[ ..] , sample_rate) . unwrap ( )
32
+ } )
33
+ . clone ( )
34
+ }
35
+
16
36
/// Spatialization algorithm used to position the audio in 3D space
17
37
#[ derive( Debug , Copy , Clone , PartialEq , Eq , Default ) ]
18
38
pub enum PanningModelType {
@@ -549,9 +569,8 @@ impl PannerNode {
549
569
let hrtf_option = match value {
550
570
PanningModelType :: EqualPower => None ,
551
571
PanningModelType :: HRTF => {
552
- let resource = include_bytes ! ( "../../resources/IRC_1003_C.bin" ) ;
553
572
let sample_rate = self . context ( ) . sample_rate ( ) as u32 ;
554
- let hrir_sphere = HrirSphere :: new ( & resource [ .. ] , sample_rate) . unwrap ( ) ;
573
+ let hrir_sphere = load_hrir_sphere ( sample_rate) ;
555
574
Some ( HrtfState :: new ( hrir_sphere) )
556
575
}
557
576
} ;
0 commit comments