@@ -16,6 +16,47 @@ function noiseDurationSeconds(sound, durationSeconds) {
1616 return Math . min ( durationSeconds , sound . noiseDecayMs / 1000 ) ;
1717}
1818
19+ function createFilteredNoise ( context , sound , durationSeconds ) {
20+ const noise = context . createBufferSource ( ) ;
21+ const noiseFilter = context . createBiquadFilter ( ) ;
22+ const noiseGain = context . createGain ( ) ;
23+ noise . buffer = createNoiseBuffer ( context , durationSeconds ) ;
24+ noiseFilter . type = "lowpass" ;
25+ noiseFilter . frequency . setValueAtTime ( sound . noiseFilterHz , context . currentTime ) ;
26+ noise . connect ( noiseFilter ) ;
27+ noiseFilter . connect ( noiseGain ) ;
28+ noiseGain . connect ( context . destination ) ;
29+ return { noise, noiseGain } ;
30+ }
31+
32+ function startNoiseLayer ( context , sound , now , durationSeconds ) {
33+ const noiseSeconds = noiseDurationSeconds ( sound , durationSeconds ) ;
34+ const noiseStopAt = now + noiseSeconds ;
35+ const { noise, noiseGain } = createFilteredNoise ( context , sound , noiseSeconds ) ;
36+ noiseGain . gain . setValueAtTime ( Math . max ( 0.0001 , sound . volume * sound . noiseAmount * 1.2 ) , now ) ;
37+ noiseGain . gain . exponentialRampToValueAtTime ( 0.0001 , noiseStopAt ) ;
38+ noise . start ( now ) ;
39+ noise . stop ( noiseStopAt ) ;
40+ return noise ;
41+ }
42+
43+ function startPrimaryNoise ( context , sound , now , durationSeconds , attackSeconds ) {
44+ const stopAt = now + durationSeconds ;
45+ const attackEnd = now + attackSeconds ;
46+ const decayEnd = now + Math . min ( durationSeconds , Math . max ( attackSeconds + 0.005 , sound . noiseDecayMs / 1000 ) ) ;
47+ const peakGain = Math . max ( 0.0001 , sound . volume * Math . max ( sound . noiseAmount , 0.05 ) ) ;
48+ const { noise, noiseGain } = createFilteredNoise ( context , sound , durationSeconds ) ;
49+ noiseGain . gain . setValueAtTime ( 0.0001 , now ) ;
50+ noiseGain . gain . linearRampToValueAtTime ( peakGain , attackEnd ) ;
51+ noiseGain . gain . exponentialRampToValueAtTime ( 0.0001 , decayEnd ) ;
52+ if ( decayEnd < stopAt ) {
53+ noiseGain . gain . setValueAtTime ( 0.0001 , stopAt ) ;
54+ }
55+ noise . start ( now ) ;
56+ noise . stop ( stopAt ) ;
57+ return noise ;
58+ }
59+
1960export class AudioSfxEngine {
2061 constructor ( { windowRef = window } = { } ) {
2162 this . context = null ;
@@ -47,43 +88,35 @@ export class AudioSfxEngine {
4788 const stopAt = now + durationSeconds ;
4889 const sustainStart = now + attackSeconds ;
4990 const releaseStart = Math . max ( sustainStart , stopAt - releaseSeconds ) ;
50- const oscillator = context . createOscillator ( ) ;
51- const gain = context . createGain ( ) ;
91+ let primarySource ;
92+ if ( sound . waveform === "noise" ) {
93+ primarySource = startPrimaryNoise ( context , sound , now , durationSeconds , attackSeconds ) ;
94+ } else {
95+ const oscillator = context . createOscillator ( ) ;
96+ const gain = context . createGain ( ) ;
5297
53- oscillator . type = sound . waveform ;
54- oscillator . frequency . setValueAtTime ( sound . frequencyHz , now ) ;
55- oscillator . detune . setValueAtTime ( 0 , now ) ;
56- oscillator . detune . linearRampToValueAtTime ( sound . pitchSweepCents , stopAt ) ;
57- gain . gain . setValueAtTime ( 0.0001 , now ) ;
58- gain . gain . linearRampToValueAtTime ( sound . volume , sustainStart ) ;
59- gain . gain . setValueAtTime ( sound . volume , releaseStart ) ;
60- gain . gain . exponentialRampToValueAtTime ( 0.0001 , stopAt ) ;
98+ oscillator . type = sound . waveform ;
99+ oscillator . frequency . setValueAtTime ( sound . frequencyHz , now ) ;
100+ oscillator . detune . setValueAtTime ( 0 , now ) ;
101+ oscillator . detune . linearRampToValueAtTime ( sound . pitchSweepCents , stopAt ) ;
102+ gain . gain . setValueAtTime ( 0.0001 , now ) ;
103+ gain . gain . linearRampToValueAtTime ( sound . volume , sustainStart ) ;
104+ gain . gain . setValueAtTime ( sound . volume , releaseStart ) ;
105+ gain . gain . exponentialRampToValueAtTime ( 0.0001 , stopAt ) ;
61106
62- oscillator . connect ( gain ) ;
63- gain . connect ( context . destination ) ;
64- oscillator . start ( now ) ;
65- oscillator . stop ( stopAt ) ;
107+ oscillator . connect ( gain ) ;
108+ gain . connect ( context . destination ) ;
109+ oscillator . start ( now ) ;
110+ oscillator . stop ( stopAt ) ;
111+ primarySource = oscillator ;
66112
67- if ( sound . noise ) {
68- const noise = context . createBufferSource ( ) ;
69- const noiseFilter = context . createBiquadFilter ( ) ;
70- const noiseGain = context . createGain ( ) ;
71- const noiseSeconds = noiseDurationSeconds ( sound , durationSeconds ) ;
72- const noiseStopAt = now + noiseSeconds ;
73- noise . buffer = createNoiseBuffer ( context , noiseSeconds ) ;
74- noiseFilter . type = "lowpass" ;
75- noiseFilter . frequency . setValueAtTime ( sound . noiseFilterHz , now ) ;
76- noiseGain . gain . setValueAtTime ( Math . max ( 0.0001 , sound . volume * sound . noiseAmount * 1.2 ) , now ) ;
77- noiseGain . gain . exponentialRampToValueAtTime ( 0.0001 , noiseStopAt ) ;
78- noise . connect ( noiseFilter ) ;
79- noiseFilter . connect ( noiseGain ) ;
80- noiseGain . connect ( context . destination ) ;
81- noise . start ( now ) ;
82- noise . stop ( noiseStopAt ) ;
113+ if ( sound . noise ) {
114+ startNoiseLayer ( context , sound , now , durationSeconds ) ;
115+ }
83116 }
84117
85118 await new Promise ( ( resolve ) => {
86- oscillator . addEventListener ( "ended" , resolve , { once : true } ) ;
119+ primarySource . addEventListener ( "ended" , resolve , { once : true } ) ;
87120 } ) ;
88121 }
89122}
0 commit comments