After decimating the enemy forces that have attacked your ship, you are charged with taking out as many of the remaining enemy fighters as possible. 3d space fighter game was initially written while I was testing some 3d routines I was implementing for a flight simulator, but my daughter started playing it and seemed to enjoy it so I added a few sound effects, explosions etc. and so this little game was born.

Dependencies:   mbed

OneBitSound/SoundChannel.cpp

Committer:
taylorza
Date:
2015-01-04
Revision:
1:9ff7384171ec
Child:
4:b857db213f10

File content as of revision 1:9ff7384171ec:

#include "mbed.h"
#include "Fix16.h"
#include "lookupTables.h"
#include "SoundBlock.h"
#include "SoundChannel.h"

SoundChannel::SoundChannel() :
    _state(4)
{
}

void SoundChannel::play(const SoundBlock soundBlocks[], int count)
{
    _soundBlocks = soundBlocks;
    _count = count;    
    _index = 0;   
    _state = 0;   
}

bool SoundChannel::update(bool &pinState)
{
    switch(_state)
    {
        case 0 :
            startSoundBlock();
            break;
        
        case 3 : // Stop sound
            pinState = _pinState = false;
            _state = 4;
            return true;
        
        case 4 : // No sound
            return false;
    }

    if (updateCounters())
    {
        switch(_currentSoundBlock.getToneType())
        {
            case SoundBlock::Tone  : updateTone(); pinState = _pinState; return true;
            case SoundBlock::Noise : updateNoise(); pinState = _pinState; return true;
            case SoundBlock::Pause : return false;
        }
    }
    
    return false;
}

void SoundChannel::updateTone()
{
    switch(_state)
    {
        case 1: // High
        {
            _pinState = true;
            _pitchHighCounter -= fix16_one;
            if (_pitchHighCounter <= 0)
            {            
                _pinState = false;
                _pitchHighCounter += _basePitchHighCount;
                _state = 2;
            }
        }
        break;
            
        case 2: // Low
        {
            _pinState = false;
            _pitchLowCounter -= fix16_one;
            if (_pitchLowCounter <= 0)
            {
                _pinState = true;
                _pitchLowCounter += _basePitchLowCount;
                _state = 1;
            }
        }
        break;
    }    
}

void SoundChannel::updateNoise()
{
    switch(_state)
    {
        case 1: // High/Low        
        {   
            _pitchHighCounter -= fix16_one;
            if (_pitchHighCounter <= 0)
            {            
                _pinState = (SoundChannel::lfsr_rand() & 1) == 1;
                _pitchHighCounter += _basePitchHighCount;                
            }
        }
        break;
    }    
}

void SoundChannel::startSoundBlock()
{
    _currentSoundBlock = _soundBlocks[_index];
            
    _stepCounter = _currentSoundBlock.getStepCount();
    _stepDurationCounter = _currentSoundBlock.getStepDuration();
    _pitchOffset = 0;
    _dutyOffset = 0;
    
    updateAudioCounters();
    _pitchHighCounter = _basePitchHighCount;
    _pitchLowCounter = _basePitchLowCount;
    
    _state = 1;
}

bool SoundChannel::updateCounters()
{
    --_stepDurationCounter;
    if (_stepDurationCounter == 0)
    {    
        --_stepCounter;
        if (_stepCounter == 0)
        {                                
            ++_index;
            if (_index == _count)
            {                    
                _state = 3;
                return false;
            }
            else
            {
                _state = 0;
            }
        }                        
        else
        {  
            fix16_t pitchSlide = _currentSoundBlock.getPitchSlide();
            int8_t dutySlide = _currentSoundBlock.getDutySlide();
            if ( pitchSlide != 0 || dutySlide != 0)
            {
                _pitchOffset += pitchSlide;
                _dutyOffset += dutySlide;
                updateAudioCounters();
            }
        
            _stepDurationCounter = _currentSoundBlock.getStepDuration();
        }
    }
    return true;
}

void SoundChannel::updateAudioCounters()
{
    fix16_t pitch = _currentSoundBlock.getPitch(_pitchOffset);
    if (pitch == 0) pitch = fix16_one;
    
    if (_currentSoundBlock.getToneType() == SoundBlock::Noise)
        pitch = fix16_div(pitch, fix16_100);
        
    _basePitchHighCount = fix16_mul(pitch, g_dutyLookup[_currentSoundBlock.getDuty(_dutyOffset)]);
    _basePitchLowCount = pitch - _basePitchHighCount;    
}

uint16_t SoundChannel::lfsr_rand()
{
    static uint16_t lfsr = 0xACE1u;
    lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB400u);
    return lfsr;
}