diff --git a/frontend/src/sound.js b/frontend/src/sound.js index 960ad4d..2082345 100644 --- a/frontend/src/sound.js +++ b/frontend/src/sound.js @@ -30,30 +30,41 @@ const noiseBuffer = (c) => { return noise } -// one "tock" of a die hitting the table +// one bounce of a heavy die on a wooden table: a low thump with a dull knock on top const tock = (c, out, t, strength) => { const src = c.createBufferSource() src.buffer = noiseBuffer(c) const f = c.createBiquadFilter() f.type = 'bandpass' - f.frequency.value = 900 + Math.random() * 3200 - f.Q.value = 1.2 + Math.random() * 2 + f.frequency.value = 260 + Math.random() * 900 + f.Q.value = 0.7 + Math.random() const g = c.createGain() g.gain.setValueAtTime(0.0001, t) - g.gain.exponentialRampToValueAtTime(strength, t + 0.003) - g.gain.exponentialRampToValueAtTime(0.0001, t + 0.04 + Math.random() * 0.04) + g.gain.exponentialRampToValueAtTime(strength, t + 0.004) + g.gain.exponentialRampToValueAtTime(0.0001, t + 0.07 + Math.random() * 0.06) src.connect(f).connect(g).connect(out) src.start(t, Math.random() * 0.1) - src.stop(t + 0.12) + src.stop(t + 0.2) + const o = c.createOscillator() // the weight: a sine that drops in pitch + o.type = 'sine' + o.frequency.setValueAtTime(130 + Math.random() * 40, t) + o.frequency.exponentialRampToValueAtTime(48, t + 0.14) + const og = c.createGain() + og.gain.setValueAtTime(0.0001, t) + og.gain.exponentialRampToValueAtTime(strength * 1.1, t + 0.006) + og.gain.exponentialRampToValueAtTime(0.0001, t + 0.16) + o.connect(og).connect(out) + o.start(t) + o.stop(t + 0.2) } -const tone = (c, out, t, freq, len, type = 'sine', vol = 0.25) => { +const tone = (c, out, t, freq, len, type = 'triangle', vol = 0.25) => { const o = c.createOscillator() o.type = type o.frequency.value = freq const g = c.createGain() g.gain.setValueAtTime(0.0001, t) - g.gain.exponentialRampToValueAtTime(vol, t + 0.015) + g.gain.exponentialRampToValueAtTime(vol, t + 0.02) g.gain.exponentialRampToValueAtTime(0.0001, t + len) o.connect(g).connect(out) o.start(t) @@ -67,21 +78,24 @@ export function playRoll(n, outcome) { if (!c) return const out = c.createGain() out.gain.value = sound.volume - out.connect(c.destination) + const dull = c.createBiquadFilter() // takes the brightness off everything + dull.type = 'lowpass' + dull.frequency.value = 2200 + const comp = c.createDynamicsCompressor() + out.connect(dull).connect(comp).connect(c.destination) const t0 = c.currentTime + 0.02 let end = 0 for (let i = 0; i < Math.min(n, 10); i++) { - const start = t0 + i * 0.09 - let t = start - for (let k = 0; k < 6; k++) { // bounces get softer and further apart - tock(c, out, t, 0.9 * Math.pow(0.62, k) * (0.7 + Math.random() * 0.3)) - t += 0.045 + k * 0.035 + Math.random() * 0.03 + let t = t0 + i * 0.11 + for (let k = 0; k < 5; k++) { // fewer, heavier bounces that die away quickly + tock(c, out, t, 0.85 * Math.pow(0.55, k) * (0.75 + Math.random() * 0.25)) + t += 0.07 + k * 0.05 + Math.random() * 0.03 } end = Math.max(end, t) } - const t1 = end + 0.12 - if (outcome === 'crit_success') { tone(c, out, t1, 784, 0.35, 'sine', 0.22); tone(c, out, t1 + 0.12, 1175, 0.5, 'sine', 0.22); tone(c, out, t1 + 0.12, 1568, 0.5, 'sine', 0.08) } - else if (outcome === 'success') tone(c, out, t1, 698, 0.3, 'sine', 0.2) - else if (outcome === 'failure') tone(c, out, t1, 196, 0.28, 'triangle', 0.22) - else if (outcome === 'crit_failure') { tone(c, out, t1, 220, 0.3, 'sawtooth', 0.12); tone(c, out, t1 + 0.18, 147, 0.6, 'sawtooth', 0.14) } + const t1 = end + 0.1 + if (outcome === 'crit_success') { tone(c, out, t1, 196, 0.7, 'triangle', 0.3); tone(c, out, t1 + 0.16, 294, 0.8, 'triangle', 0.28); tone(c, out, t1 + 0.16, 392, 0.9, 'sine', 0.12) } + else if (outcome === 'success') { tone(c, out, t1, 147, 0.5, 'triangle', 0.3); tone(c, out, t1, 220, 0.4, 'sine', 0.1) } + else if (outcome === 'failure') tone(c, out, t1, 82, 0.55, 'triangle', 0.35) + else if (outcome === 'crit_failure') { tone(c, out, t1, 98, 0.5, 'sawtooth', 0.14); tone(c, out, t1 + 0.22, 62, 1.0, 'sawtooth', 0.18) } }