11use std:: any:: Any ;
2+ use std:: collections:: HashMap ;
23use std:: f32:: consts:: PI ;
4+ use std:: sync:: { Mutex , OnceLock } ;
35
46use float_eq:: float_eq;
57use hrtf:: { HrirSphere , HrtfContext , HrtfProcessor , Vec3 } ;
@@ -13,6 +15,31 @@ use super::{
1315 AudioNode , ChannelConfig , ChannelConfigOptions , ChannelCountMode , ChannelInterpretation ,
1416} ;
1517
18+ /// Load the HRTF processor 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+ pub ( crate ) fn load_hrtf_processor ( sample_rate : u32 ) -> ( HrtfProcessor , usize ) {
24+ static INSTANCE : OnceLock < Mutex < HashMap < u32 , ( HrtfProcessor , usize ) > > > = 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+ let hrir_sphere = HrirSphere :: new ( & resource[ ..] , sample_rate) . unwrap ( ) ;
32+ let len = hrir_sphere. len ( ) ;
33+
34+ let interpolation_steps = 1 ; // TODO?
35+ let samples_per_step = RENDER_QUANTUM_SIZE / interpolation_steps;
36+ let processor = HrtfProcessor :: new ( hrir_sphere, interpolation_steps, samples_per_step) ;
37+
38+ ( processor, len)
39+ } )
40+ . clone ( )
41+ }
42+
1643/// Spatialization algorithm used to position the audio in 3D space
1744#[ derive( Debug , Copy , Clone , PartialEq , Eq , Default ) ]
1845pub enum PanningModelType {
@@ -167,14 +194,7 @@ struct HrtfState {
167194}
168195
169196impl HrtfState {
170- fn new ( hrir_sphere : HrirSphere ) -> Self {
171- let len = hrir_sphere. len ( ) ;
172-
173- let interpolation_steps = 1 ;
174- let samples_per_step = RENDER_QUANTUM_SIZE / interpolation_steps;
175-
176- let processor = HrtfProcessor :: new ( hrir_sphere, interpolation_steps, samples_per_step) ;
177-
197+ fn new ( processor : HrtfProcessor , len : usize ) -> Self {
178198 Self {
179199 len,
180200 processor,
@@ -549,10 +569,9 @@ impl PannerNode {
549569 let hrtf_option = match value {
550570 PanningModelType :: EqualPower => None ,
551571 PanningModelType :: HRTF => {
552- let resource = include_bytes ! ( "../../resources/IRC_1003_C.bin" ) ;
553572 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 ) )
573+ let ( processor , len ) = load_hrtf_processor ( sample_rate ) ;
574+ Some ( HrtfState :: new ( processor , len ) )
556575 }
557576 } ;
558577
0 commit comments