Stereo, because I can.

In the midst of all this trauma, I need something to take my mind off things. This will only take a few moments: I’m going to add stereo to the Asteroids game.

The sound function can take a number of optional parameters:

sound(name, volume, pitch, pan, loop)
-- name of sound asset
-- volume between 0 and 1
-- pitch with 1.0 normal pitch
-- pan, stereo pan between -1 and 1
-- loop, true to loop the sound

These parameters only apply to sounds from a sound asset pack. There is also the ability to produce randomly generated sounds of various types, with a raft of parameters provided in a table. Our sounds are assets, and a simple test showed that the pan variable does affect them.

So I built this complex function:

function Universe:playStereo(aSound, anObject)
    sound(aSound, 1, 1, 2*anObject.pos.x/WIDTH - 1)
end

The expression 2*anObject.pos.x/WIDTH - 1 maps values 0-WIDTH to the interval [-1,1]. Things over at WIDTH should be heard from the right speaker, those down at 0 should be heard from the left, and so on. First I tried it for the ship’s power:

function Ship:actualShipMove()
    if U.button.go then
        U:playStereo(U.sounds.thrust, self)
        local accel = vec2(0.015,0):rotate(self.radians)
        self.step = self.step + accel
        self.step = maximize(self.step, 3)
    end
    self:finallyMove()
end

And sure enough, as you cruise across the screen, the brr sound moves across as well.

So let’s do all the ones that make sense:

function Ship:fireMissile()
    U:playStereo(U.sounds.fire, self)
    self.holdFire = true
    Missile(self)
end


function splitAsteroid(asteroid, asteroids)
    if asteroid.scale == 16 then
        U:playStereo(U.sounds.bangLarge, asteroid)
    elseif asteroid.scale == 8 then
        U:playStereo(U.sounds.bangMedium, asteroid, asteroid)
    elseif asteroid.scale == 4 then
        U:playStereo(U.sounds.bangSmall, asteroid)
        Splat(asteroid.pos)
        DeadAsteroids[asteroid] = asteroid
        return
    end
    asteroid.scale = asteroid.scale//2
    asteroid.angle = math.random()*2*math.pi
    local new = Asteroid()
    new.pos = asteroid.pos
    new.scale = asteroid.scale
    asteroids[new] = new
    Splat(asteroid.pos)
end

Now all the explosions and firing and accelerating noises have a stereo effect. The original Asteroids didn’t have that, but I’m sure they would have if they had thought of it.

That’s it. Stereo. A few moments of untroubled concentration. I hope you have untroubled times as well, and I hope we all do what we can for a more fair and just society.

Zipped Code