Chris Taylor / Mbed 2 deprecated RETRO-CityRally

Dependencies:   mbed

OneBitSound/SoundChannel.cpp

Committer:
taylorza
Date:
2015-01-28
Revision:
0:d85c449aca6d

File content as of revision 0:d85c449aca6d:

#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;
}