Skip to main content
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.

Don't click me