Parker Davis

Scrolling Turkey Part II: The Gobble

In my last post I made a scrolling turkey but quickly realized, it needed to gobble.

I started by getting a few audio files of turkeys gobbling. I assembled the samples into a single file so that I could load them with a single http request but play them as audio sprites. I used OcenAudio to do it manually but I probably should have used the NPM package audiosprite which uses FFMPEG to automatically create audio sprites with associated metadata.

I grabbed the Sprite class from this repo and in its simplicity it works wonders!

class Sprite {
constructor(settingsObj) {
this.src = settingsObj.src;
this.samples = settingsObj.sprite;
this.init();
}
async init() {
// Set up web audio
const AudioCtx = window.AudioContext || window.webkitAudioContext;
this.ctx = new AudioCtx();
// Load file
this.audioBuffer = await this.getFile();
}
async getFile() {
// Request file
const response = await fetch(this.src);
if (!response.ok) {
console.log(`${response.url} ${response.statusText}`);
throw new Error(`${response.url} ${response.statusText}`);
}
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await this.ctx.decodeAudioData(arrayBuffer);
return audioBuffer;
}
play(sampleName) {
const startTime = this.samples[sampleName][0] / 1000;
const duration = this.samples[sampleName][1] / 1000;
const sampleSource = this.ctx.createBufferSource();
sampleSource.buffer = this.audioBuffer;
sampleSource.connect(this.ctx.destination);
sampleSource.start(this.ctx.currentTime, startTime, duration);
}
}

An instance of the class loads the audio file as an audio buffer. You pass in an options object with a path to the audio file in src, and a sprite object with named sprite keys with start times and duration in milliseconds. I just plugged in my audio file and the metadata for the three gobbles named a, b, and c:

const gobble = new Sprite({
src: 'assets/turkey/turkey-sprite.m4a',
sprite: {
a: [0, 1000],
b: [1000, 1000],
c: [2000, 1100],
},
});

I then add an event listener after the page loads to handle when someone clicks the turkey:

window.addEventListener('load', () => {
const turkey = document.querySelector('.turkey');
turkey.addEventListener('click', () => {
const sprites = ['a', 'b', 'c'];
const randomSprite =
sprites[Math.floor(Math.random() * sprites.length)];
gobble.play(randomSprite);
});
});

As a result, I am filled with delight.

Comments

Leave a comment