diff --git a/internal/web/static/js/casino-sfx.js b/internal/web/static/js/casino-sfx.js index 340b9b0..c96ea06 100644 --- a/internal/web/static/js/casino-sfx.js +++ b/internal/web/static/js/casino-sfx.js @@ -147,6 +147,13 @@ var buffers = {}; var warmed = false; + // A rotating cursor per sound, so that even a run of identical calls walks + // through the takes rather than replaying the first one. Callers pass `v` to + // separate simultaneous sounds (the cards of one deal), but many pass the same + // constant every time — the cursor is what keeps a stack of chips from being the + // same click over and over. + var turn = {}; + // decode fetches a file and turns it into a buffer, exactly once per filename. // decodeAudioData exists in a modern promise flavour and an old callback one; // this handles both so the foley works on older Safari too. @@ -179,14 +186,17 @@ function sample(name, t0, v) { var cfg = SAMPLES[name]; if (!cfg) return false; - var i = Math.abs(Math.round(v)); - var buf = buffers[cfg.files[i % cfg.files.length]]; + // Advance the cursor, then offset it by v. The cursor guarantees consecutive + // calls move to the next take; v spreads apart sounds fired together (one + // deal's cards) so they don't all land on the same take at once. + var k = (turn[name] = (turn[name] || 0) + 1) + Math.abs(Math.round(v)); + var buf = buffers[cfg.files[k % cfg.files.length]]; if (!buf) return false; // not decoded yet, or failed: let synth cover it var src = ctx.createBufferSource(); src.buffer = buf; - // A few percent off pitch, spread across a small range keyed to v, so a run of - // the same sound never reads as a loop. - if (cfg.vary) src.playbackRate.value = 1 + (((i % 5) - 2) * cfg.vary); + // A few percent off pitch, walking with the same cursor, so even a single-take + // sound like the shuffle isn't pitch-identical twice in a row. + if (cfg.vary) src.playbackRate.value = 1 + (((k % 5) - 2) * cfg.vary); var g = ctx.createGain(); g.gain.value = cfg.gain == null ? 0.6 : cfg.gain; src.connect(g).connect(master);