zeroed-some/dougk / ce1a9c2

Browse files

rewrite sound: high pass fileter, granular texture, soft envelope, lower voluem

Authored by espadonne
SHA
ce1a9c2879d876bd1ea81eb9227479d5842e44ec
Parents
82408db
Tree
72b6249

1 changed file

StatusFile+-
M src/renderers/three/sounds.js 76 78
src/renderers/three/sounds.jsmodified
@@ -19,89 +19,87 @@ export function playMonch() {
1919
     ctx.resume()
2020
   }
2121
 
22
-  // Create noise buffer for the crunch texture
23
-  const noiseLength = 0.15
24
-  const bufferSize = ctx.sampleRate * noiseLength
25
-  const noiseBuffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate)
26
-  const noiseData = noiseBuffer.getChannelData(0)
27
-
28
-  // Fill with noise
29
-  for (let i = 0; i < bufferSize; i++) {
30
-    noiseData[i] = Math.random() * 2 - 1
22
+  // Master output - keep it gentle
23
+  const master = ctx.createGain()
24
+  master.gain.value = 0.25
25
+  master.connect(ctx.destination)
26
+
27
+  // High-pass to remove speaker-popping low frequencies
28
+  const highPass = ctx.createBiquadFilter()
29
+  highPass.type = 'highpass'
30
+  highPass.frequency.value = 150
31
+  highPass.connect(master)
32
+
33
+  // Create multiple small crunch "grains" for texture
34
+  const grainCount = 5
35
+  for (let i = 0; i < grainCount; i++) {
36
+    const delay = i * 0.018 + Math.random() * 0.01
37
+    const grainTime = now + delay
38
+
39
+    // Each grain is a short filtered noise burst
40
+    const grainLength = 0.04 + Math.random() * 0.03
41
+    const bufferSize = Math.floor(ctx.sampleRate * grainLength)
42
+    const noiseBuffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate)
43
+    const noiseData = noiseBuffer.getChannelData(0)
44
+
45
+    // Softer noise - not full amplitude
46
+    for (let j = 0; j < bufferSize; j++) {
47
+      noiseData[j] = (Math.random() * 2 - 1) * 0.7
48
+    }
49
+
50
+    const grain = ctx.createBufferSource()
51
+    grain.buffer = noiseBuffer
52
+
53
+    // Bandpass for crunch character - varied per grain
54
+    const filter = ctx.createBiquadFilter()
55
+    filter.type = 'bandpass'
56
+    filter.frequency.value = 300 + Math.random() * 400
57
+    filter.Q.value = 2 + Math.random() * 2
58
+
59
+    // Gentle envelope - no sharp attacks
60
+    const env = ctx.createGain()
61
+    const peakGain = 0.3 + Math.random() * 0.2
62
+    env.gain.setValueAtTime(0, grainTime)
63
+    env.gain.linearRampToValueAtTime(peakGain, grainTime + 0.008) // Soft attack
64
+    env.gain.linearRampToValueAtTime(peakGain * 0.6, grainTime + 0.02)
65
+    env.gain.linearRampToValueAtTime(0, grainTime + grainLength) // Soft release
66
+
67
+    grain.connect(filter)
68
+    filter.connect(env)
69
+    env.connect(highPass)
70
+
71
+    grain.start(grainTime)
72
+    grain.stop(grainTime + grainLength)
3173
   }
3274
 
33
-  // Noise source
34
-  const noise = ctx.createBufferSource()
35
-  noise.buffer = noiseBuffer
36
-
37
-  // Low-pass filter for the "damp" wet quality
38
-  const dampFilter = ctx.createBiquadFilter()
39
-  dampFilter.type = 'lowpass'
40
-  dampFilter.frequency.setValueAtTime(800, now)
41
-  dampFilter.frequency.exponentialRampToValueAtTime(300, now + 0.08)
42
-  dampFilter.Q.value = 2
43
-
44
-  // Bandpass for crunch character
45
-  const crunchFilter = ctx.createBiquadFilter()
46
-  crunchFilter.type = 'bandpass'
47
-  crunchFilter.frequency.value = 400
48
-  crunchFilter.Q.value = 1.5
49
-
50
-  // Envelope for the noise burst
51
-  const noiseGain = ctx.createGain()
52
-  noiseGain.gain.setValueAtTime(0, now)
53
-  noiseGain.gain.linearRampToValueAtTime(0.4, now + 0.01) // Quick attack
54
-  noiseGain.gain.exponentialRampToValueAtTime(0.15, now + 0.04) // Initial drop
55
-  noiseGain.gain.exponentialRampToValueAtTime(0.01, now + 0.12) // Tail off
56
-
57
-  // Low thump for the bite impact
58
-  const thump = ctx.createOscillator()
59
-  thump.type = 'sine'
60
-  thump.frequency.setValueAtTime(120, now)
61
-  thump.frequency.exponentialRampToValueAtTime(50, now + 0.06)
62
-
63
-  const thumpGain = ctx.createGain()
64
-  thumpGain.gain.setValueAtTime(0, now)
65
-  thumpGain.gain.linearRampToValueAtTime(0.3, now + 0.005)
66
-  thumpGain.gain.exponentialRampToValueAtTime(0.01, now + 0.08)
67
-
68
-  // Secondary squelch - adds wetness
69
-  const squelch = ctx.createOscillator()
70
-  squelch.type = 'triangle'
71
-  squelch.frequency.setValueAtTime(200, now)
72
-  squelch.frequency.exponentialRampToValueAtTime(80, now + 0.05)
73
-
74
-  const squelchGain = ctx.createGain()
75
-  squelchGain.gain.setValueAtTime(0, now + 0.01)
76
-  squelchGain.gain.linearRampToValueAtTime(0.15, now + 0.02)
77
-  squelchGain.gain.exponentialRampToValueAtTime(0.01, now + 0.07)
78
-
79
-  // Master output with slight compression feel
80
-  const master = ctx.createGain()
81
-  master.gain.value = 0.6
75
+  // Soft muffled "body" of the bite - no harsh transients
76
+  const bodyLength = 0.12
77
+  const bodyBuffer = ctx.createBuffer(1, Math.floor(ctx.sampleRate * bodyLength), ctx.sampleRate)
78
+  const bodyData = bodyBuffer.getChannelData(0)
79
+  for (let i = 0; i < bodyData.length; i++) {
80
+    bodyData[i] = (Math.random() * 2 - 1) * 0.5
81
+  }
8282
 
83
-  // Connect noise chain
84
-  noise.connect(dampFilter)
85
-  dampFilter.connect(crunchFilter)
86
-  crunchFilter.connect(noiseGain)
87
-  noiseGain.connect(master)
83
+  const body = ctx.createBufferSource()
84
+  body.buffer = bodyBuffer
8885
 
89
-  // Connect thump
90
-  thump.connect(thumpGain)
91
-  thumpGain.connect(master)
86
+  // Heavy lowpass for muffled wet sound
87
+  const wetFilter = ctx.createBiquadFilter()
88
+  wetFilter.type = 'lowpass'
89
+  wetFilter.frequency.setValueAtTime(600, now)
90
+  wetFilter.frequency.linearRampToValueAtTime(200, now + 0.1)
91
+  wetFilter.Q.value = 1
9292
 
93
-  // Connect squelch
94
-  squelch.connect(squelchGain)
95
-  squelchGain.connect(master)
93
+  const bodyEnv = ctx.createGain()
94
+  bodyEnv.gain.setValueAtTime(0, now)
95
+  bodyEnv.gain.linearRampToValueAtTime(0.25, now + 0.02) // Gentle attack
96
+  bodyEnv.gain.linearRampToValueAtTime(0.15, now + 0.05)
97
+  bodyEnv.gain.linearRampToValueAtTime(0, now + bodyLength)
9698
 
97
-  // Output
98
-  master.connect(ctx.destination)
99
+  body.connect(wetFilter)
100
+  wetFilter.connect(bodyEnv)
101
+  bodyEnv.connect(highPass)
99102
 
100
-  // Play
101
-  noise.start(now)
102
-  noise.stop(now + noiseLength)
103
-  thump.start(now)
104
-  thump.stop(now + 0.1)
105
-  squelch.start(now)
106
-  squelch.stop(now + 0.08)
103
+  body.start(now)
104
+  body.stop(now + bodyLength)
107105
 }