Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: OneBitSound/SoundChannel.cpp
- 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; +}