Platform game written for the GHI/OutrageousCircuits RETRO game device. Navigate the caves collecting all the pickups and avoiding the creatures and haunted mine carts that patrol the caves. Oh and remember to watch out for the poisonous plants... This game demonstrates the ability to have multiple animated sprites where the sprites can overlap the background environment. See how the player moves past the fence and climbs the wall in the 3rd screen.

Dependencies:   mbed

Revision:
5:a758c7d4da03
Child:
12:1394b0c6e8b0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OneBitSound/SoundChannel.cpp	Fri Jan 02 01:55:12 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;
+}