1+ #[ cfg( feature = "iai" ) ]
12use iai:: black_box;
23
4+ #[ cfg( not( feature = "iai" ) ) ]
5+ use criterion:: { black_box, criterion_group, criterion_main, Criterion } ;
6+
37use web_audio_api:: context:: BaseAudioContext ;
48use web_audio_api:: context:: OfflineAudioContext ;
59use web_audio_api:: node:: { AudioNode , AudioScheduledSourceNode , PanningModelType } ;
10+ use web_audio_api:: AudioBuffer ;
11+
12+ use std:: fs:: File ;
13+ use std:: sync:: OnceLock ;
614
715const SAMPLE_RATE : f32 = 48000. ;
816const DURATION : usize = 10 ;
917const SAMPLES : usize = SAMPLE_RATE as usize * DURATION ;
18+ const SAMPLES_SHORT : usize = SAMPLE_RATE as usize ; // only 1 second for heavy benchmarks
19+
20+ /// Load an audio buffer and cache the result
21+ ///
22+ /// We don't want to measure the IO and decoding in most of our benchmarks, so by using this static
23+ /// instance we avoid this in the criterion benchmarks because the file is already loaded in the
24+ /// warmup phase.
25+ fn get_audio_buffer ( ctx : & OfflineAudioContext ) -> AudioBuffer {
26+ static BUFFER : OnceLock < AudioBuffer > = OnceLock :: new ( ) ;
27+ BUFFER
28+ . get_or_init ( || {
29+ let file = File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
30+ ctx. decode_audio_data_sync ( file) . unwrap ( )
31+ } )
32+ . clone ( )
33+ }
1034
1135pub fn bench_ctor ( ) {
1236 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
1337 assert_eq ! ( ctx. start_rendering_sync( ) . length( ) , SAMPLES ) ;
1438}
1539
40+ // This benchmark only makes sense in `iai`, because subsequent runs use the cached audiobuffer.
41+ // However we would like to run this test here so the cache is filled for the subsequent benches.
42+ pub fn bench_audio_buffer_decode ( ) {
43+ let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
44+ let buffer = get_audio_buffer ( & ctx) ;
45+ assert_eq ! ( buffer. length( ) , 101129 ) ;
46+ }
47+
1648pub fn bench_sine ( ) {
1749 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
1850 let mut osc = ctx. create_oscillator ( ) ;
@@ -56,9 +88,7 @@ pub fn bench_sine_gain_delay() {
5688
5789pub fn bench_buffer_src ( ) {
5890 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
59-
60- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
61- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
91+ let buffer = get_audio_buffer ( & ctx) ;
6292
6393 let mut src = ctx. create_buffer_source ( ) ;
6494 src. connect ( & ctx. destination ( ) ) ;
@@ -70,9 +100,7 @@ pub fn bench_buffer_src() {
70100
71101pub fn bench_buffer_src_delay ( ) {
72102 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
73-
74- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
75- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
103+ let buffer = get_audio_buffer ( & ctx) ;
76104
77105 let delay = ctx. create_delay ( 0.3 ) ;
78106 delay. delay_time ( ) . set_value ( 0.2 ) ;
@@ -89,8 +117,7 @@ pub fn bench_buffer_src_delay() {
89117
90118pub fn bench_buffer_src_iir ( ) {
91119 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
92- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
93- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
120+ let buffer = get_audio_buffer ( & ctx) ;
94121
95122 // these values correspond to a lowpass filter at 200Hz (calculated from biquad)
96123 let feedforward = vec ! [
@@ -116,8 +143,7 @@ pub fn bench_buffer_src_iir() {
116143
117144pub fn bench_buffer_src_biquad ( ) {
118145 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
119- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
120- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
146+ let buffer = get_audio_buffer ( & ctx) ;
121147
122148 // Create an biquad filter node (defaults to low pass)
123149 let biquad = ctx. create_biquad_filter ( ) ;
@@ -135,8 +161,7 @@ pub fn bench_buffer_src_biquad() {
135161
136162pub fn bench_stereo_positional ( ) {
137163 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
138- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
139- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
164+ let buffer = get_audio_buffer ( & ctx) ;
140165
141166 // Create static panner node
142167 let panner = ctx. create_panner ( ) ;
@@ -159,8 +184,7 @@ pub fn bench_stereo_positional() {
159184
160185pub fn bench_stereo_panning_automation ( ) {
161186 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
162- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
163- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
187+ let buffer = get_audio_buffer ( & ctx) ;
164188
165189 let panner = ctx. create_stereo_panner ( ) ;
166190 panner. connect ( & ctx. destination ( ) ) ;
@@ -181,8 +205,7 @@ pub fn bench_stereo_panning_automation() {
181205// benchmark this in deterministic way [citation needed].
182206pub fn bench_analyser_node ( ) {
183207 let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
184- let file = std:: fs:: File :: open ( "samples/think-stereo-48000.wav" ) . unwrap ( ) ;
185- let buffer = ctx. decode_audio_data_sync ( file) . unwrap ( ) ;
208+ let buffer = get_audio_buffer ( & ctx) ;
186209
187210 let analyser = ctx. create_analyser ( ) ;
188211 analyser. connect ( & ctx. destination ( ) ) ;
@@ -197,7 +220,7 @@ pub fn bench_analyser_node() {
197220}
198221
199222pub fn bench_hrtf_panners ( ) {
200- let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES ) , SAMPLE_RATE ) ;
223+ let ctx = OfflineAudioContext :: new ( 2 , black_box ( SAMPLES_SHORT ) , SAMPLE_RATE ) ;
201224
202225 let mut panner1 = ctx. create_panner ( ) ;
203226 panner1. set_panning_model ( PanningModelType :: HRTF ) ;
@@ -214,11 +237,13 @@ pub fn bench_hrtf_panners() {
214237 osc. connect ( & panner2) ;
215238 osc. start ( ) ;
216239
217- assert_eq ! ( ctx. start_rendering_sync( ) . length( ) , SAMPLES ) ;
240+ assert_eq ! ( ctx. start_rendering_sync( ) . length( ) , SAMPLES_SHORT ) ;
218241}
219242
243+ #[ cfg( feature = "iai" ) ]
220244iai:: main!(
221245 bench_ctor,
246+ bench_audio_buffer_decode,
222247 bench_sine,
223248 bench_sine_gain,
224249 bench_sine_gain_delay,
@@ -231,3 +256,85 @@ iai::main!(
231256 bench_analyser_node,
232257 bench_hrtf_panners,
233258) ;
259+
260+ #[ cfg( not( feature = "iai" ) ) ]
261+ fn criterion_ctor ( c : & mut Criterion ) {
262+ c. bench_function ( "bench_ctor" , |b| b. iter ( bench_ctor) ) ;
263+ }
264+ #[ cfg( not( feature = "iai" ) ) ]
265+ fn criterion_audio_buffer_decode ( c : & mut Criterion ) {
266+ c. bench_function ( "bench_audio_buffer_decode" , |b| {
267+ b. iter ( bench_audio_buffer_decode)
268+ } ) ;
269+ }
270+ #[ cfg( not( feature = "iai" ) ) ]
271+ fn criterion_sine ( c : & mut Criterion ) {
272+ c. bench_function ( "bench_sine" , |b| b. iter ( bench_sine) ) ;
273+ }
274+ #[ cfg( not( feature = "iai" ) ) ]
275+ fn criterion_sine_gain ( c : & mut Criterion ) {
276+ c. bench_function ( "bench_sine_gain" , |b| b. iter ( bench_sine_gain) ) ;
277+ }
278+ #[ cfg( not( feature = "iai" ) ) ]
279+ fn criterion_sine_gain_delay ( c : & mut Criterion ) {
280+ c. bench_function ( "bench_sine_gain_delay" , |b| b. iter ( bench_sine_gain_delay) ) ;
281+ }
282+ #[ cfg( not( feature = "iai" ) ) ]
283+ fn criterion_buffer_src ( c : & mut Criterion ) {
284+ c. bench_function ( "bench_buffer_src" , |b| b. iter ( bench_buffer_src) ) ;
285+ }
286+ #[ cfg( not( feature = "iai" ) ) ]
287+ fn criterion_buffer_src_delay ( c : & mut Criterion ) {
288+ c. bench_function ( "bench_buffer_src_delay" , |b| b. iter ( bench_buffer_src_delay) ) ;
289+ }
290+ #[ cfg( not( feature = "iai" ) ) ]
291+ fn criterion_buffer_src_iir ( c : & mut Criterion ) {
292+ c. bench_function ( "bench_buffer_src_iir" , |b| b. iter ( bench_buffer_src_iir) ) ;
293+ }
294+ #[ cfg( not( feature = "iai" ) ) ]
295+ fn criterion_buffer_src_biquad ( c : & mut Criterion ) {
296+ c. bench_function ( "bench_buffer_src_biquad" , |b| {
297+ b. iter ( bench_buffer_src_biquad)
298+ } ) ;
299+ }
300+ #[ cfg( not( feature = "iai" ) ) ]
301+ fn criterion_stereo_positional ( c : & mut Criterion ) {
302+ c. bench_function ( "bench_stereo_positional" , |b| {
303+ b. iter ( bench_stereo_positional)
304+ } ) ;
305+ }
306+ #[ cfg( not( feature = "iai" ) ) ]
307+ fn criterion_stereo_panning_automation ( c : & mut Criterion ) {
308+ c. bench_function ( "bench_stereo_panning_automation" , |b| {
309+ b. iter ( bench_stereo_panning_automation)
310+ } ) ;
311+ }
312+ #[ cfg( not( feature = "iai" ) ) ]
313+ fn criterion_analyser_node ( c : & mut Criterion ) {
314+ c. bench_function ( "bench_analyser_node" , |b| b. iter ( bench_analyser_node) ) ;
315+ }
316+ #[ cfg( not( feature = "iai" ) ) ]
317+ fn criterion_hrtf_panners ( c : & mut Criterion ) {
318+ c. bench_function ( "bench_hrtf_panners" , |b| b. iter ( bench_hrtf_panners) ) ;
319+ }
320+
321+ #[ cfg( not( feature = "iai" ) ) ]
322+ criterion_group ! (
323+ benches,
324+ criterion_ctor,
325+ criterion_audio_buffer_decode,
326+ criterion_sine,
327+ criterion_sine_gain,
328+ criterion_sine_gain_delay,
329+ criterion_buffer_src,
330+ criterion_buffer_src_delay,
331+ criterion_buffer_src_iir,
332+ criterion_buffer_src_biquad,
333+ criterion_stereo_positional,
334+ criterion_stereo_panning_automation,
335+ criterion_analyser_node,
336+ criterion_hrtf_panners
337+ ) ;
338+
339+ #[ cfg( not( feature = "iai" ) ) ]
340+ criterion_main ! ( benches) ;
0 commit comments