games: rotate through foley takes on every play, not just by v
Take-selection was keyed only on the caller's v, but callers pass small constants (chip is always v:0), so only the first take of each sound ever played. Add a per-name cursor that advances every call: consecutive plays now walk the takes, v just offsets simultaneous sounds and drives pitch.
This commit is contained in:
@@ -147,6 +147,13 @@
|
|||||||
var buffers = {};
|
var buffers = {};
|
||||||
var warmed = false;
|
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.
|
// 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;
|
// decodeAudioData exists in a modern promise flavour and an old callback one;
|
||||||
// this handles both so the foley works on older Safari too.
|
// this handles both so the foley works on older Safari too.
|
||||||
@@ -179,14 +186,17 @@
|
|||||||
function sample(name, t0, v) {
|
function sample(name, t0, v) {
|
||||||
var cfg = SAMPLES[name];
|
var cfg = SAMPLES[name];
|
||||||
if (!cfg) return false;
|
if (!cfg) return false;
|
||||||
var i = Math.abs(Math.round(v));
|
// Advance the cursor, then offset it by v. The cursor guarantees consecutive
|
||||||
var buf = buffers[cfg.files[i % cfg.files.length]];
|
// 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
|
if (!buf) return false; // not decoded yet, or failed: let synth cover it
|
||||||
var src = ctx.createBufferSource();
|
var src = ctx.createBufferSource();
|
||||||
src.buffer = buf;
|
src.buffer = buf;
|
||||||
// A few percent off pitch, spread across a small range keyed to v, so a run of
|
// A few percent off pitch, walking with the same cursor, so even a single-take
|
||||||
// the same sound never reads as a loop.
|
// sound like the shuffle isn't pitch-identical twice in a row.
|
||||||
if (cfg.vary) src.playbackRate.value = 1 + (((i % 5) - 2) * cfg.vary);
|
if (cfg.vary) src.playbackRate.value = 1 + (((k % 5) - 2) * cfg.vary);
|
||||||
var g = ctx.createGain();
|
var g = ctx.createGain();
|
||||||
g.gain.value = cfg.gain == null ? 0.6 : cfg.gain;
|
g.gain.value = cfg.gain == null ? 0.6 : cfg.gain;
|
||||||
src.connect(g).connect(master);
|
src.connect(g).connect(master);
|
||||||
|
|||||||
Reference in New Issue
Block a user