Chris Taylor / Mbed 2 deprecated RETRO-CityRally

Dependencies:   mbed

Revision:
0:d85c449aca6d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OneBitSound/SoundChannel.cpp	Wed Jan 28 03:26:07 2015 +0000
@@ -0,0 +1,168 @@
+#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;
+}