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
diff -r 000000000000 -r d85c449aca6d OneBitSound/SoundChannel.cpp
--- /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;
+}