From 531d5d6d6b261781e0986ed39d231d6deea58b8b Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Thu, 21 Sep 2017 23:43:33 +0100 Subject: [PATCH] Refactor the Audio header into declaration/definition files. Signed-off-by: Adrian.Conlon --- LR35902/inc/Audio.h | 750 ++++++------------------ LR35902/src/Audio.cpp | 849 ++++++++++++++++++++++++++++ LR35902/src/LR35902.vcxproj | 1 + LR35902/src/LR35902.vcxproj.filters | 3 + 4 files changed, 1027 insertions(+), 576 deletions(-) create mode 100644 LR35902/src/Audio.cpp diff --git a/LR35902/inc/Audio.h b/LR35902/inc/Audio.h index 4b9f3d9..d0845f0 100644 --- a/LR35902/inc/Audio.h +++ b/LR35902/inc/Audio.h @@ -5,8 +5,6 @@ #include #include -#include - #include "AudioFrame.h" namespace EightBit { @@ -14,31 +12,24 @@ namespace EightBit { class Envelope final { public: - Envelope() {} + Envelope(); enum Direction { Attenuate, Amplify }; - void reset() { - m_defaultValue = m_direction = m_stepLength = 0; - } + void reset(); + bool zeroed() const; - bool zeroed() const { - return (default() == 0) && (stepLength() == 0) && (direction() == Attenuate); - } + int default() const; + void setDefault(int value); - int default() const { return m_defaultValue; } - void setDefault(int value) { m_defaultValue = value; } + Direction direction() const; + void setDirection(int value); + void setDirection(Direction value); - Direction direction() const { return (Direction)m_direction; } - void setDirection(int value) { m_direction = value; } - void setDirection(Direction value) { setDirection((int)value); } + int stepLength() const; + void setStepLength(int value); - int stepLength() const { return m_stepLength; } - void setStepLength(int value) { m_stepLength = value; } - - void dump() const { - std::cout << "Envelope: default=" << default() << ",direction=" << direction() << ",step length=" << stepLength() << std::endl; - } + void dump() const; private: int m_defaultValue; @@ -48,31 +39,24 @@ namespace EightBit { class Sweep final { public: - Sweep() {} + Sweep(); enum Direction { Addition, Subtraction }; - void reset() { - m_time = m_direction = m_shift = 0; - } + void reset(); + bool zeroed() const; - bool zeroed() const { - return (time() == 0) && (shift() == 0) && (direction() == Addition); - } + int time() const; + void setTime(int value); - int time() const { return m_time; } - void setTime(int value) { m_time = value; } + Direction direction() const; + void setDirection(int value); + void setDirection(Direction value); - Direction direction() const { return (Direction)m_direction; } - void setDirection(int value) { m_direction = value; } - void setDirection(Direction value) { setDirection((int)value); } + int shift() const; + void setShift(int value); - int shift() const { return m_shift; } - void setShift(int value) { m_shift = value; } - - void dump() const { - std::cout << "Sweep: time=" << time() << ",direction=" << direction() << ",shift=" << shift() << std::endl; - } + void dump() const; private: int m_time; @@ -82,28 +66,21 @@ namespace EightBit { class AudioVoice { public: - AudioVoice() {} + AudioVoice(); - virtual void reset() { - m_counterContinuous = m_initialise = 0; - } - - virtual bool zeroed() const { - return !initialise() && (type() == Continuous); - } + virtual void reset(); + virtual bool zeroed() const; enum Type { Continuous, Counter }; - Type type() const { return (Type)m_counterContinuous; } - void setType(int value) { m_counterContinuous = value; } - void setType(Type value) { setType((int)value); } + Type type() const; + void setType(int value); + void setType(Type value); - bool initialise() const { return !!m_initialise; } - void setInitialise(bool value) { m_initialise = value; } + bool initialise() const; + void setInitialise(bool value); - virtual void dump() const { - std::cout << "Audio Voice: type=" << type() << ",initialise=" << initialise() << std::endl; - } + virtual void dump() const; private: int m_counterContinuous; @@ -112,52 +89,22 @@ namespace EightBit { class WaveVoice : public AudioVoice { public: - WaveVoice(int cyclesPerSecond) - : m_cyclesPerSecond(cyclesPerSecond) {} + WaveVoice(int cyclesPerSecond); - virtual void reset() override { - AudioVoice::reset(); - m_frequencyLowOrder = m_frequencyHighOrder = 0; - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - return AudioVoice::zeroed() && (frequency() == 0); - } + int frequencyLowOrder() const; + void setFrequencyLowOrder(int value); + int frequencyHighOrder() const; + void setFrequencyHighOrder(int value); - int frequencyLowOrder() const { return m_frequencyLowOrder; } + int frequency() const; + void setFrequency(int value); - void setFrequencyLowOrder(int value) { - assert(value < Processor::Bit8); - m_frequencyLowOrder = value; - } + int hertz() const; - int frequencyHighOrder() const { return m_frequencyHighOrder; } - - void setFrequencyHighOrder(int value) { - assert(value < Processor::Bit3); - m_frequencyHighOrder = value; - } - - int frequency() const { - return (m_frequencyHighOrder << 8) | m_frequencyLowOrder; - } - - int hertz() const { - // f = 4194304 / (4 x 8 x (2048 - X)) Hz - auto division = 4 * 8 * (2048 - frequency()); - return m_cyclesPerSecond / division; - } - - void setFrequency(int value) { - assert(value < Processor::Bit11); - m_frequencyHighOrder = (value >> 8) & Processor::Mask3; - m_frequencyLowOrder = value & Processor::Mask8; - } - - virtual void dump() const override { - AudioVoice::dump(); - std::cout << "Wave Voice: frequency=" << frequency() << " (" << hertz() << ")" << std::endl; - } + virtual void dump() const override; private: const int m_cyclesPerSecond; @@ -167,28 +114,18 @@ namespace EightBit { class RectangularVoice : public WaveVoice { public: - RectangularVoice(int cyclesPerSecond) - : WaveVoice(cyclesPerSecond) {} + RectangularVoice(int cyclesPerSecond); - virtual void reset() override { - WaveVoice::reset(); - m_waveFormDutyCycle = m_soundLength = 0; - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - return WaveVoice::zeroed() && (waveFormDutyCycle() == 0) && (length() == 0); - } + int waveFormDutyCycle() const; + void setWaveFormDutyCycle(int value); - int waveFormDutyCycle() const { return m_waveFormDutyCycle; } - void setWaveFormDutyCycle(int value) { m_waveFormDutyCycle = value; } + int length() const; + void setLength(int value); - int length() const { return m_soundLength; } - void setLength(int value) { m_soundLength = value; } - - virtual void dump() const override { - WaveVoice::dump(); - std::cout << "Rectangular Voice: wave form duty=" << waveFormDutyCycle() << ",length=" << length() << std::endl; - } + virtual void dump() const override; private: int m_waveFormDutyCycle; @@ -198,24 +135,14 @@ namespace EightBit { // NR2X class EnvelopedRectangularVoice : public RectangularVoice { public: - EnvelopedRectangularVoice(int cyclesPerSecond) - : RectangularVoice(cyclesPerSecond) {} + EnvelopedRectangularVoice(int cyclesPerSecond); - virtual void reset() override { - RectangularVoice::reset(); - m_envelope.reset(); - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - return RectangularVoice::zeroed() && m_envelope.zeroed(); - } + Envelope& envelope(); - Envelope& envelope() { return m_envelope; } - - virtual void dump() const override { - RectangularVoice::dump(); - m_envelope.dump(); - } + virtual void dump() const override; private: Envelope m_envelope; @@ -224,24 +151,14 @@ namespace EightBit { // NR1X class SweptEnvelopedRectangularVoice : public EnvelopedRectangularVoice { public: - SweptEnvelopedRectangularVoice(int cyclesPerSecond) - : EnvelopedRectangularVoice(cyclesPerSecond) {} + SweptEnvelopedRectangularVoice(int cyclesPerSecond); - virtual void reset() override { - EnvelopedRectangularVoice::reset(); - m_sweep.reset(); - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - return EnvelopedRectangularVoice::zeroed() && m_sweep.zeroed(); - } + Sweep& sweep(); - Sweep& sweep() { return m_sweep; } - - virtual void dump() const override { - EnvelopedRectangularVoice::dump(); - m_sweep.dump(); - } + virtual void dump() const override; private: Sweep m_sweep; @@ -250,56 +167,23 @@ namespace EightBit { // NR3X class UserDefinedWaveVoice : public WaveVoice { public: - UserDefinedWaveVoice(int cyclesPerSecond) - : WaveVoice(cyclesPerSecond) {} + UserDefinedWaveVoice(int cyclesPerSecond); - virtual void reset() override { - WaveVoice::reset(); - m_enabled = m_soundLength = m_outputLevel = 0; - for (auto& datum : m_waveData) - datum = 0; - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - bool dataZeroed = true; - for (const auto& datum : m_waveData) { - if (datum != 0) { - dataZeroed = false; - break; - } - } - return - WaveVoice::zeroed() - && dataZeroed - && !enabled() - && (length() == 0) - && (level() == 0); - } - - bool enabled() const { return !!m_enabled; } - void setEnabled(bool value) { m_enabled = value; } + bool enabled() const; + void setEnabled(bool value); - int length() const { return m_soundLength; } - void setLength(int value) { m_soundLength = value; } + int length() const; + void setLength(int value); - int level() const { return m_outputLevel; } - void setLevel(int value) { m_outputLevel = value; } + int level() const; + void setLevel(int value); - int packedWaveDatum(int i) const { - assert(i < 16); - return m_waveData[i]; - } - - void setPackedWaveDatum(int i, uint8_t value) { - assert(i < 16); - m_waveData[i] = value; - } - - int waveDatum(int i) const { - assert(i < 32); - const auto packed = packedWaveDatum(i >> 1); - return i & 1 ? Processor::lowNibble(packed) : Processor::highNibble(packed); - } + int packedWaveDatum(int i) const; + void setPackedWaveDatum(int i, uint8_t value); + int waveDatum(int i) const; private: int m_enabled; @@ -311,37 +195,24 @@ namespace EightBit { // NR4X class WhiteNoiseWaveVoice : public AudioVoice { public: - WhiteNoiseWaveVoice() {} + WhiteNoiseWaveVoice(); - virtual void reset() override { - AudioVoice::reset(); - m_envelope.reset(); - m_soundLength = m_polynomialShiftClockFrequency = m_polynomialCounterSteps = m_frequencyDivisionRatio = 0; - } + virtual void reset() override; + virtual bool zeroed() const override; - virtual bool zeroed() const override { - return - AudioVoice::zeroed() - && m_envelope.zeroed() - && (length() == 0) - && (polynomialShiftClockFrequency() == 0) - && (polynomialCounterSteps() == 0) - && (frequencyDivisionRatio() == 0); - } + Envelope& envelope(); - Envelope& envelope() { return m_envelope; } + int length() const; + void setLength(int value); - int length() const { return m_soundLength; } - void setLength(int value) { m_soundLength = value; } + int polynomialShiftClockFrequency() const; + void setPolynomialShiftClockFrequency(int value); - int polynomialShiftClockFrequency() const { return m_polynomialShiftClockFrequency; } - void setPolynomialShiftClockFrequency(int value) { m_polynomialShiftClockFrequency = value; } + int polynomialCounterSteps() const; + void setPolynomialCounterSteps(int value); - int polynomialCounterSteps() const { return m_polynomialCounterSteps; } - void setPolynomialCounterSteps(int value) { m_polynomialCounterSteps = value; } - - int frequencyDivisionRatio() const { return m_frequencyDivisionRatio; } - void setFrequencyDivisionRatio(int value) { m_frequencyDivisionRatio = value; } + int frequencyDivisionRatio() const; + void setFrequencyDivisionRatio(int value); private: Envelope m_envelope; @@ -353,42 +224,24 @@ namespace EightBit { class OutputChannel final { public: - OutputChannel() {} + OutputChannel(); - void reset() { - m_vin = false; - m_outputLevel = 0; - for (auto& outputVoice : m_outputVoices) - outputVoice = false; - } + void reset(); + bool zeroed() const; - bool zeroed() const { - return - !vin() - && outputLevel() == 0 - && !m_outputVoices[0] && !m_outputVoices[1] && !m_outputVoices[2] && !m_outputVoices[3]; - } + bool vin() const; + void setVin(bool value); - bool vin() const { return m_vin; } - void setVin(bool value) { m_vin = value; } + int outputLevel() const; + void setOutputLevel(int value); - int outputLevel() const { return m_outputLevel; } - void setOutputLevel(int value) { m_outputLevel = value; } + bool& outputVoice(int voice); + bool& outputVoice1(); + bool& outputVoice2(); + bool& outputVoice3(); + bool& outputVoice4(); - bool& outputVoice(int voice) { return m_outputVoices[voice]; } - bool& outputVoice1() { return m_outputVoices[0]; } - bool& outputVoice2() { return m_outputVoices[1]; } - bool& outputVoice3() { return m_outputVoices[2]; } - bool& outputVoice4() { return m_outputVoices[3]; } - - void dump() const { - std::cout - << "Output channel: " - << "Vin:" << vin() - << ",Output level=" << outputLevel() - << ",Voices:" << (int)m_outputVoices[0] << (int)m_outputVoices[1] << (int)m_outputVoices[2] << (int)m_outputVoices[3] - << std::endl; - } + void dump() const; private: bool m_vin; @@ -398,396 +251,141 @@ namespace EightBit { class Audio final { public: - Audio(int cyclesPerSecond) - : m_frameSequencer(cyclesPerSecond), - m_enabled(false) { + Audio(int cyclesPerSecond); - m_voices[0] = std::make_shared(cyclesPerSecond); - m_voices[1] = std::make_shared(cyclesPerSecond); - m_voices[2] = std::make_shared(cyclesPerSecond); - m_voices[3] = std::make_shared(); + std::shared_ptr voice(int i); + SweptEnvelopedRectangularVoice* voice1(); + EnvelopedRectangularVoice* voice2(); + UserDefinedWaveVoice* voice3(); + WhiteNoiseWaveVoice* voice4(); - m_frameSequencer.FrameStep.connect(std::bind(&Audio::Sequencer_FrameStep, this, std::placeholders::_1)); - m_frameSequencer.LengthStep.connect(std::bind(&Audio::Sequencer_LengthStep, this, std::placeholders::_1)); - m_frameSequencer.VolumeStep.connect(std::bind(&Audio::Sequencer_VolumeStep, this, std::placeholders::_1)); - m_frameSequencer.SweepStep.connect(std::bind(&Audio::Sequencer_SweepStep, this, std::placeholders::_1)); - } + OutputChannel& channel(int i); + OutputChannel& channel1(); + OutputChannel& channel2(); - std::shared_ptr voice(int i) { return m_voices[i]; } + bool enabled() const; + void setEnabled(bool value); - SweptEnvelopedRectangularVoice* voice1() { - return (SweptEnvelopedRectangularVoice*)voice(0).get(); - } + void reset(); + bool zeroed() const; - EnvelopedRectangularVoice* voice2() { - return (EnvelopedRectangularVoice*)voice(1).get(); - } - - UserDefinedWaveVoice* voice3() { - return (UserDefinedWaveVoice*)voice(2).get(); - } - - WhiteNoiseWaveVoice* voice4() { - return (WhiteNoiseWaveVoice*)voice(3).get(); - } - - OutputChannel& channel(int i) { return m_channels[i]; } - OutputChannel& channel1() { return channel(0); } - OutputChannel& channel2() { return channel(1); } - - bool enabled() const { return m_enabled; } - - void setEnabled(bool value) { - m_enabled = value; - if (!enabled()) - reset(); - } - - void reset() { - m_enabled = false; - for (auto voice : m_voices) - voice->reset(); - for (auto& channel : m_channels) - channel.reset(); - } - - bool zeroed() const { - auto channelsZeroed = m_channels[0].zeroed() && m_channels[1].zeroed(); - auto voice1Zero = m_voices[0]->zeroed(); - auto voice2Zero = m_voices[1]->zeroed(); - auto voice3Zero = m_voices[2]->zeroed(); - auto voice4Zero = m_voices[3]->zeroed(); - auto voicesZeroed = voice1Zero && voice2Zero && voice3Zero && voice4Zero; - return !enabled() && channelsZeroed && voicesZeroed; - } - - void dumpVoice(int i) const { - std::cout << "** Voice " << i + 1 << std::endl; - m_voices[i]->dump(); - } - - void dumpVoices() const { - for (int i = 0; i < 4; ++i) - dumpVoice(i); - } - - void dumpChannel(int i) const { - std::cout << "** Channel " << i + 1 << std::endl; - m_channels[i].dump(); - } - - void dumpChannels() const { - for (int i = 0; i < 2; ++i) - dumpChannel(i); - } - - void dump() const { - dumpVoices(); - dumpChannels(); - } + void dumpVoice(int i) const; + void dumpVoices() const; + void dumpChannel(int i) const; + void dumpChannels() const; + void dump() const; // - bool voice1On() const { return true; } - bool voice2On() const { return true; } - bool voice3On() const { return true; } - bool voice4On() const { return true; } + bool voice1On() const; + bool voice2On() const; + bool voice3On() const; + bool voice4On() const; // - uint8_t toNRx1(int i) { - auto voice = (RectangularVoice*)m_voices[i].get(); - return - (voice->waveFormDutyCycle() << 6) - | Processor::Mask6; - } + uint8_t toNRx1(int i); + void fromNRx1(int i, uint8_t value); - void fromNRx1(int i, uint8_t value) { - auto voice = (RectangularVoice*)m_voices[i].get(); - voice->setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 - voice->setLength(value & Processor::Mask6); // Bits 0-5 - } + uint8_t toNRx2(int i); + void fromNRx2(int i, uint8_t value); - uint8_t toNRx2(int i) { - auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); - auto& envelope = voice->envelope(); - return - (envelope.default() << 4) - | (envelope.direction() << 3) - | envelope.stepLength(); - } - - void fromNRx2(int i, uint8_t value) { - auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); - auto& envelope = voice->envelope(); - envelope.setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 - envelope.setDirection((value >> 3) & Processor::Mask1); // Bit 3 - envelope.setStepLength(value & Processor::Mask3); // Bits 0-2 - } - - uint8_t toNRx3(int i) { - return Processor::Mask8; - } - - void fromNRx3(int i, uint8_t value) { - auto voice = (WaveVoice*)m_voices[i].get(); - voice->setFrequencyLowOrder(value); - } + uint8_t toNRx3(int i); + void fromNRx3(int i, uint8_t value); // Sound mode 1 register: Sweep - - uint8_t toNR10() { - auto& sweep = voice1()->sweep(); - return - Processor::Bit7 - | (sweep.time() << 4) - | (sweep.direction() << 3) - | sweep.shift(); - } - - void fromNR10(uint8_t value) { - auto& sweep = voice1()->sweep(); - sweep.setTime((value >> 4) & Processor::Mask3); // Bits 4-6 - sweep.setDirection((value >> 3) & Processor::Mask1); // Bit 3 - sweep.setShift(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR10(); + void fromNR10(uint8_t value); // Sound mode 1 register: Sound length / Wave pattern duty - uint8_t toNR11() { return toNRx1(0); } - void fromNR11(uint8_t value) { fromNRx1(0, value); } + uint8_t toNR11(); + void fromNR11(uint8_t value); // Sound mode 1 register: Envelope - uint8_t toNR12() { return toNRx2(0); } - void fromNR12(uint8_t value) { fromNRx2(0, value); } + uint8_t toNR12(); + void fromNR12(uint8_t value); // Sound mode 1 register: Frequency lo - uint8_t toNR13() { return toNRx3(0); } - void fromNR13(uint8_t value) { fromNRx3(0, value); } + uint8_t toNR13(); + void fromNR13(uint8_t value); // Sound mode 1 register: Frequency hi - - uint8_t toNR14() { - return - Processor::Bit7 - | (voice1()->type() << 6) - | Processor::Mask6; - } - - void fromNR14(uint8_t value) { - voice1()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice1()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice1()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR14(); + void fromNR14(uint8_t value); // Sound mode 2 register: Sound length / Wave pattern duty - uint8_t toNR21() { return toNRx1(1); } - void fromNR21(uint8_t value) { fromNRx1(1, value); } + uint8_t toNR21(); + void fromNR21(uint8_t value); // Sound mode 2 register: Envelope - uint8_t toNR22() { return toNRx2(1); } - void fromNR22(uint8_t value) { fromNRx2(1, value); } + uint8_t toNR22(); + void fromNR22(uint8_t value); // Sound mode 2 register: Frequency lo - uint8_t toNR23() { return toNRx3(1); } - void fromNR23(uint8_t value) { fromNRx3(1, value); } + uint8_t toNR23(); + void fromNR23(uint8_t value); // Sound mode 2 register: Frequency hi - - uint8_t toNR24() { - return - Processor::Bit7 - | (voice2()->type() << 6) - | Processor::Mask6; - } - - void fromNR24(uint8_t value) { - voice2()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice2()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice2()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR24(); + void fromNR24(uint8_t value); // Sound mode 3 register: Sound on/off - - uint8_t toNR30() { - return - (voice3()->enabled() << 7) - | Processor::Mask7; - } - - void fromNR30(uint8_t value) { - voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 - } + uint8_t toNR30(); + void fromNR30(uint8_t value); // Sound mode 3 register: Sound length - - uint8_t toNR31() { - return voice3()->length(); - } - - void fromNR31(uint8_t value) { - voice3()->setLength(value); - } + uint8_t toNR31(); + void fromNR31(uint8_t value); // Sound mode 3 register: Select output level - - uint8_t toNR32() { - return - Processor::Bit7 - | Processor::Bit6 - | voice3()->level() << 5 - | Processor::Mask5; - } - - void fromNR32(uint8_t value) { - voice3()->setLevel((value >> 5) & Processor::Mask2); // Bits 6-5 - } + uint8_t toNR32(); + void fromNR32(uint8_t value); // Sound mode 3 register: Frequency lo - uint8_t toNR33() { return toNRx3(2); } - void fromNR33(uint8_t value) { fromNRx3(2, value); } + uint8_t toNR33(); + void fromNR33(uint8_t value); // Sound mode 3 register: Frequency hi - - uint8_t toNR34() { - return - Processor::Bit7 - | (voice3()->type() << 6) - | Processor::Mask6; - } - - void fromNR34(uint8_t value) { - voice3()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 - voice3()->setType((value >> 6) & Processor::Mask1); // Bits 6 - voice3()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR34(); + void fromNR34(uint8_t value); // Sound mode 4 register: Sound length - - uint8_t toNR41() { - return - Processor::Bit7 - | Processor::Bit6 - | voice4()->length(); - } - - void fromNR41(uint8_t value) { - voice4()->setLength(value); - } + uint8_t toNR41(); + void fromNR41(uint8_t value); // Sound mode 4 register: Envelope - uint8_t toNR42() { return toNRx2(3); } - void fromNR42(uint8_t value) { fromNRx2(3, value); } + uint8_t toNR42(); + void fromNR42(uint8_t value); // Sound mode 4 register: Polynomial counter - - uint8_t toNR43() { - return - (voice4()->polynomialShiftClockFrequency() << 4) - | voice4()->polynomialCounterSteps() << 3 - | voice4()->frequencyDivisionRatio(); - } - - void fromNR43(uint8_t value) { - voice4()->setPolynomialShiftClockFrequency((value >> 4) & Processor::Mask4); // Bits 4-7 - voice4()->setPolynomialCounterSteps((value >> 3) & Processor::Mask1); // Bit 3 - voice4()->setFrequencyDivisionRatio(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR43(); + void fromNR43(uint8_t value); // Sound mode 4 register: counter/consecutive; inital - - uint8_t toNR44() { - return - Processor::Bit7 - | (voice4()->type() << 6) - | Processor::Mask6; - } - - void fromNR44(uint8_t value) { - voice4()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 - voice4()->setType((value >> 6) & Processor::Mask1); // Bit 6 - } + uint8_t toNR44(); + void fromNR44(uint8_t value); // Channel control: on-off/volume - - uint8_t toNR50() { - return - (channel2().vin() << 7) - | (channel2().outputLevel() << 4) - | (channel2().vin() << 3) - | channel2().outputLevel(); - } - - void fromNR50(uint8_t value) { - channel2().setVin((value >> 7) & Processor::Mask1); // Bit 7 - channel2().setOutputLevel((value >> 4) & Processor::Mask3); // Bits 4-6 - channel1().setVin((value >> 3) & Processor::Mask1); // Bit 3 - channel1().setOutputLevel(value & Processor::Mask3); // Bits 0-2 - } + uint8_t toNR50(); + void fromNR50(uint8_t value); // Selection of Sound output terminal - - uint8_t toNR51() { - return - (channel2().outputVoice4() << 7) - | (channel2().outputVoice3() << 6) - | (channel2().outputVoice2() << 5) - | (channel2().outputVoice1() << 4) - | (channel1().outputVoice4() << 3) - | (channel1().outputVoice3() << 2) - | (channel1().outputVoice2() << 1) - | (int)channel1().outputVoice1(); - } - - void fromNR51(uint8_t value) { - channel2().outputVoice4() = (value >> 7) & Processor::Mask1; // Bit 7 - channel2().outputVoice3() = (value >> 6) & Processor::Mask1; // Bit 6 - channel2().outputVoice2() = (value >> 5) & Processor::Mask1; // Bit 5 - channel2().outputVoice1() = (value >> 4) & Processor::Mask1; // Bit 4 - channel1().outputVoice4() = (value >> 3) & Processor::Mask1; // Bit 3 - channel1().outputVoice3() = (value >> 2) & Processor::Mask1; // Bit 2 - channel1().outputVoice2() = (value >> 1) & Processor::Mask1; // Bit 1 - channel1().outputVoice1() = value & Processor::Mask1; // Bit 0 - } + uint8_t toNR51(); + void fromNR51(uint8_t value); // Sound on/off + uint8_t toNR52(); + void fromNR52(uint8_t value); - uint8_t toNR52() { - return - (enabled() << 7) - | Processor::Bit6 | Processor::Bit5 | Processor::Bit4 - | (voice4On() << 3) - | (voice3On() << 2) - | (voice2On() << 1) - | (int)voice1On(); - } + void setPackedWaveDatum(int i, uint8_t value); + uint8_t packedWaveDatum(int i); - void fromNR52(uint8_t value) { - setEnabled((value >> 7) & Processor::Mask1); // Bit 7 - } + void stepFrame(int cycles); - void setPackedWaveDatum(int i, uint8_t value) { - voice3()->setPackedWaveDatum(i, value); - } - - uint8_t packedWaveDatum(int i) { - return voice3()->packedWaveDatum(i); - } - - void stepFrame(int cycles) { - m_frameSequencer.step(cycles); - } - - void Sequencer_FrameStep(const int step) { - } - - void Sequencer_LengthStep(const int step) { - } - - void Sequencer_VolumeStep(const int step) { - } - - void Sequencer_SweepStep(const int step) { - } + void Sequencer_FrameStep(int step); + void Sequencer_LengthStep(int step); + void Sequencer_VolumeStep(int step); + void Sequencer_SweepStep(int step); private: AudioFrame m_frameSequencer; diff --git a/LR35902/src/Audio.cpp b/LR35902/src/Audio.cpp new file mode 100644 index 0000000..47eae82 --- /dev/null +++ b/LR35902/src/Audio.cpp @@ -0,0 +1,849 @@ +#include "stdafx.h" +#include "Audio.h" + +// + +EightBit::GameBoy::Envelope::Envelope() {} + +void EightBit::GameBoy::Envelope::reset() { + m_defaultValue = m_direction = m_stepLength = 0; +} + +bool EightBit::GameBoy::Envelope::zeroed() const { + return (default() == 0) && (stepLength() == 0) && (direction() == Attenuate); +} + +int EightBit::GameBoy::Envelope::default() const { + return m_defaultValue; +} + +void EightBit::GameBoy::Envelope::setDefault(int value) { + m_defaultValue = value; +} + +EightBit::GameBoy::Envelope::Direction EightBit::GameBoy::Envelope::direction() const { + return (Direction)m_direction; +} + +void EightBit::GameBoy::Envelope::setDirection(int value) { + m_direction = value; +} + +void EightBit::GameBoy::Envelope::setDirection(Direction value) { + setDirection((int)value); +} + +int EightBit::GameBoy::Envelope::stepLength() const { + return m_stepLength; +} + +void EightBit::GameBoy::Envelope::setStepLength(int value) { + m_stepLength = value; +} + +void EightBit::GameBoy::Envelope::dump() const { + std::cout << "Envelope: default=" << default() << ",direction=" << direction() << ",step length=" << stepLength() << std::endl; +} + +// + +EightBit::GameBoy::Sweep::Sweep() {} + +void EightBit::GameBoy::Sweep::reset() { + m_time = m_direction = m_shift = 0; +} + +bool EightBit::GameBoy::Sweep::zeroed() const { + return (time() == 0) && (shift() == 0) && (direction() == Addition); +} + +int EightBit::GameBoy::Sweep::time() const { + return m_time; +} + +void EightBit::GameBoy::Sweep::setTime(int value) { + m_time = value; +} + +EightBit::GameBoy::Sweep::Direction EightBit::GameBoy::Sweep::direction() const { + return (Direction)m_direction; +} + +void EightBit::GameBoy::Sweep::setDirection(int value) { + m_direction = value; +} + +void EightBit::GameBoy::Sweep::setDirection(Direction value) { + setDirection((int)value); +} + +int EightBit::GameBoy::Sweep::shift() const { + return m_shift; +} + +void EightBit::GameBoy::Sweep::setShift(int value) { + m_shift = value; +} + +void EightBit::GameBoy::Sweep::dump() const { + std::cout << "Sweep: time=" << time() << ",direction=" << direction() << ",shift=" << shift() << std::endl; +} + +// + +EightBit::GameBoy::AudioVoice::AudioVoice() {} + +void EightBit::GameBoy::AudioVoice::reset() { + m_counterContinuous = m_initialise = 0; +} + +bool EightBit::GameBoy::AudioVoice::zeroed() const { + return !initialise() && (type() == Continuous); +} + +EightBit::GameBoy::AudioVoice::Type EightBit::GameBoy::AudioVoice::type() const { + return (Type)m_counterContinuous; +} +void EightBit::GameBoy::AudioVoice::setType(int value) { + m_counterContinuous = value; +} +void EightBit::GameBoy::AudioVoice::setType(Type value) { + setType((int)value); +} + +bool EightBit::GameBoy::AudioVoice::initialise() const { + return !!m_initialise; +} +void EightBit::GameBoy::AudioVoice::setInitialise(bool value) { + m_initialise = value; +} + +void EightBit::GameBoy::AudioVoice::dump() const { + std::cout << "Audio Voice: type=" << type() << ",initialise=" << initialise() << std::endl; +} + +// + +EightBit::GameBoy::WaveVoice::WaveVoice(int cyclesPerSecond) +: m_cyclesPerSecond(cyclesPerSecond) {} + +void EightBit::GameBoy::WaveVoice::reset() { + AudioVoice::reset(); + m_frequencyLowOrder = m_frequencyHighOrder = 0; +} + +bool EightBit::GameBoy::WaveVoice::zeroed() const { + return AudioVoice::zeroed() && (frequency() == 0); +} + +int EightBit::GameBoy::WaveVoice::frequencyLowOrder() const { + return m_frequencyLowOrder; +} + +void EightBit::GameBoy::WaveVoice::setFrequencyLowOrder(int value) { + assert(value < Processor::Bit8); + m_frequencyLowOrder = value; +} + +int EightBit::GameBoy::WaveVoice::frequencyHighOrder() const { + return m_frequencyHighOrder; +} + +void EightBit::GameBoy::WaveVoice::setFrequencyHighOrder(int value) { + assert(value < Processor::Bit3); + m_frequencyHighOrder = value; +} + +int EightBit::GameBoy::WaveVoice::frequency() const { + return (m_frequencyHighOrder << 8) | m_frequencyLowOrder; +} + +int EightBit::GameBoy::WaveVoice::hertz() const { + // f = 4194304 / (4 x 8 x (2048 - X)) Hz + auto division = 4 * 8 * (2048 - frequency()); + return m_cyclesPerSecond / division; +} + +void EightBit::GameBoy::WaveVoice::setFrequency(int value) { + assert(value < Processor::Bit11); + m_frequencyHighOrder = (value >> 8) & Processor::Mask3; + m_frequencyLowOrder = value & Processor::Mask8; +} + +void EightBit::GameBoy::WaveVoice::dump() const { + AudioVoice::dump(); + std::cout << "Wave Voice: frequency=" << frequency() << " (" << hertz() << ")" << std::endl; +} + +// + +EightBit::GameBoy::RectangularVoice::RectangularVoice(int cyclesPerSecond) +: WaveVoice(cyclesPerSecond) {} + +void EightBit::GameBoy::RectangularVoice::reset() { + WaveVoice::reset(); + m_waveFormDutyCycle = m_soundLength = 0; +} + +bool EightBit::GameBoy::RectangularVoice::zeroed() const { + return WaveVoice::zeroed() && (waveFormDutyCycle() == 0) && (length() == 0); +} + +int EightBit::GameBoy::RectangularVoice::waveFormDutyCycle() const { + return m_waveFormDutyCycle; +} + +void EightBit::GameBoy::RectangularVoice::setWaveFormDutyCycle(int value) { + m_waveFormDutyCycle = value; +} + +int EightBit::GameBoy::RectangularVoice::length() const { + return m_soundLength; +} + +void EightBit::GameBoy::RectangularVoice::setLength(int value) { + m_soundLength = value; +} + +void EightBit::GameBoy::RectangularVoice::dump() const { + WaveVoice::dump(); + std::cout << "Rectangular Voice: wave form duty=" << waveFormDutyCycle() << ",length=" << length() << std::endl; +} + +// + +EightBit::GameBoy::EnvelopedRectangularVoice::EnvelopedRectangularVoice(int cyclesPerSecond) +: RectangularVoice(cyclesPerSecond) {} + +void EightBit::GameBoy::EnvelopedRectangularVoice::reset() { + RectangularVoice::reset(); + m_envelope.reset(); +} + +bool EightBit::GameBoy::EnvelopedRectangularVoice::zeroed() const { + return RectangularVoice::zeroed() && m_envelope.zeroed(); +} + +EightBit::GameBoy::Envelope& EightBit::GameBoy::EnvelopedRectangularVoice::envelope() { + return m_envelope; +} + +void EightBit::GameBoy::EnvelopedRectangularVoice::dump() const { + RectangularVoice::dump(); + m_envelope.dump(); +} + +// + +EightBit::GameBoy::SweptEnvelopedRectangularVoice::SweptEnvelopedRectangularVoice(int cyclesPerSecond) +: EnvelopedRectangularVoice(cyclesPerSecond) {} + +void EightBit::GameBoy::SweptEnvelopedRectangularVoice::reset() { + EnvelopedRectangularVoice::reset(); + m_sweep.reset(); +} + +bool EightBit::GameBoy::SweptEnvelopedRectangularVoice::zeroed() const { + return EnvelopedRectangularVoice::zeroed() && m_sweep.zeroed(); +} + +EightBit::GameBoy::Sweep& EightBit::GameBoy::SweptEnvelopedRectangularVoice::sweep() { + return m_sweep; +} + +void EightBit::GameBoy::SweptEnvelopedRectangularVoice::dump() const { + EnvelopedRectangularVoice::dump(); + m_sweep.dump(); +} + +// + +EightBit::GameBoy::UserDefinedWaveVoice::UserDefinedWaveVoice(int cyclesPerSecond) +: WaveVoice(cyclesPerSecond) {} + +void EightBit::GameBoy::UserDefinedWaveVoice::reset() { + WaveVoice::reset(); + m_enabled = m_soundLength = m_outputLevel = 0; + for (auto& datum : m_waveData) + datum = 0; +} + +bool EightBit::GameBoy::UserDefinedWaveVoice::zeroed() const { + bool dataZeroed = true; + for (const auto& datum : m_waveData) { + if (datum != 0) { + dataZeroed = false; + break; + } + } + return WaveVoice::zeroed() && dataZeroed && !enabled() && (length() == 0) && (level() == 0); +} + +bool EightBit::GameBoy::UserDefinedWaveVoice::enabled() const { + return !!m_enabled; +} + +void EightBit::GameBoy::UserDefinedWaveVoice::setEnabled(bool value) { + m_enabled = value; +} + +int EightBit::GameBoy::UserDefinedWaveVoice::length() const { + return m_soundLength; +} + +void EightBit::GameBoy::UserDefinedWaveVoice::setLength(int value) { + m_soundLength = value; +} + +int EightBit::GameBoy::UserDefinedWaveVoice::level() const { + return m_outputLevel; +} + +void EightBit::GameBoy::UserDefinedWaveVoice::setLevel(int value) { + m_outputLevel = value; +} + +int EightBit::GameBoy::UserDefinedWaveVoice::packedWaveDatum(int i) const { + assert(i < 16); + return m_waveData[i]; +} + +void EightBit::GameBoy::UserDefinedWaveVoice::setPackedWaveDatum(int i, uint8_t value) { + assert(i < 16); + m_waveData[i] = value; +} + +int EightBit::GameBoy::UserDefinedWaveVoice::waveDatum(int i) const { + assert(i < 32); + const auto packed = packedWaveDatum(i >> 1); + return i & 1 ? Processor::lowNibble(packed) : Processor::highNibble(packed); +} + +// + +EightBit::GameBoy::WhiteNoiseWaveVoice::WhiteNoiseWaveVoice() {} + +void EightBit::GameBoy::WhiteNoiseWaveVoice::reset() { + AudioVoice::reset(); + m_envelope.reset(); + m_soundLength = m_polynomialShiftClockFrequency = m_polynomialCounterSteps = m_frequencyDivisionRatio = 0; +} + +bool EightBit::GameBoy::WhiteNoiseWaveVoice::zeroed() const { + return + AudioVoice::zeroed() + && m_envelope.zeroed() + && (length() == 0) + && (polynomialShiftClockFrequency() == 0) + && (polynomialCounterSteps() == 0) + && (frequencyDivisionRatio() == 0); +} + +EightBit::GameBoy::Envelope& EightBit::GameBoy::WhiteNoiseWaveVoice::envelope() { + return m_envelope; +} + +int EightBit::GameBoy::WhiteNoiseWaveVoice::length() const { + return m_soundLength; +} + +void EightBit::GameBoy::WhiteNoiseWaveVoice::setLength(int value) { + m_soundLength = value; +} + +int EightBit::GameBoy::WhiteNoiseWaveVoice::polynomialShiftClockFrequency() const { + return m_polynomialShiftClockFrequency; +} + +void EightBit::GameBoy::WhiteNoiseWaveVoice::setPolynomialShiftClockFrequency(int value) { + m_polynomialShiftClockFrequency = value; +} + +int EightBit::GameBoy::WhiteNoiseWaveVoice::polynomialCounterSteps() const { + return m_polynomialCounterSteps; +} + +void EightBit::GameBoy::WhiteNoiseWaveVoice::setPolynomialCounterSteps(int value) { + m_polynomialCounterSteps = value; +} + +int EightBit::GameBoy::WhiteNoiseWaveVoice::frequencyDivisionRatio() const { + return m_frequencyDivisionRatio; +} + +void EightBit::GameBoy::WhiteNoiseWaveVoice::setFrequencyDivisionRatio(int value) { + m_frequencyDivisionRatio = value; +} + +// + +EightBit::GameBoy::OutputChannel::OutputChannel() {} + +void EightBit::GameBoy::OutputChannel::reset() { + m_vin = false; + m_outputLevel = 0; + for (auto& outputVoice : m_outputVoices) + outputVoice = false; +} + +bool EightBit::GameBoy::OutputChannel::zeroed() const { + return + !vin() + && outputLevel() == 0 + && !m_outputVoices[0] && !m_outputVoices[1] && !m_outputVoices[2] && !m_outputVoices[3]; +} + +bool EightBit::GameBoy::OutputChannel::vin() const { + return m_vin; +} +void EightBit::GameBoy::OutputChannel::setVin(bool value) { + m_vin = value; +} + +int EightBit::GameBoy::OutputChannel::outputLevel() const { + return m_outputLevel; +} +void EightBit::GameBoy::OutputChannel::setOutputLevel(int value) { + m_outputLevel = value; +} + +bool& EightBit::GameBoy::OutputChannel::outputVoice(int voice) { + return m_outputVoices[voice]; +} +bool& EightBit::GameBoy::OutputChannel::outputVoice1() { + return m_outputVoices[0]; +} +bool& EightBit::GameBoy::OutputChannel::outputVoice2() { + return m_outputVoices[1]; +} +bool& EightBit::GameBoy::OutputChannel::outputVoice3() { + return m_outputVoices[2]; +} +bool& EightBit::GameBoy::OutputChannel::outputVoice4() { + return m_outputVoices[3]; +} + +void EightBit::GameBoy::OutputChannel::dump() const { + std::cout + << "Output channel: " + << "Vin:" << vin() + << ",Output level=" << outputLevel() + << ",Voices:" << (int)m_outputVoices[0] << (int)m_outputVoices[1] << (int)m_outputVoices[2] << (int)m_outputVoices[3] + << std::endl; +} + + +EightBit::GameBoy::Audio::Audio(int cyclesPerSecond) +: m_frameSequencer(cyclesPerSecond), + m_enabled(false) { + + m_voices[0] = std::make_shared(cyclesPerSecond); + m_voices[1] = std::make_shared(cyclesPerSecond); + m_voices[2] = std::make_shared(cyclesPerSecond); + m_voices[3] = std::make_shared(); + + m_frameSequencer.FrameStep.connect(std::bind(&Audio::Sequencer_FrameStep, this, std::placeholders::_1)); + m_frameSequencer.LengthStep.connect(std::bind(&Audio::Sequencer_LengthStep, this, std::placeholders::_1)); + m_frameSequencer.VolumeStep.connect(std::bind(&Audio::Sequencer_VolumeStep, this, std::placeholders::_1)); + m_frameSequencer.SweepStep.connect(std::bind(&Audio::Sequencer_SweepStep, this, std::placeholders::_1)); +} + +std::shared_ptr EightBit::GameBoy::Audio::voice(int i) { + return m_voices[i]; +} + +EightBit::GameBoy::SweptEnvelopedRectangularVoice* EightBit::GameBoy::Audio::voice1() { + return (SweptEnvelopedRectangularVoice*)voice(0).get(); +} + +EightBit::GameBoy::EnvelopedRectangularVoice* EightBit::GameBoy::Audio::voice2() { + return (EnvelopedRectangularVoice*)voice(1).get(); +} + +EightBit::GameBoy::UserDefinedWaveVoice* EightBit::GameBoy::Audio::voice3() { + return (UserDefinedWaveVoice*)voice(2).get(); +} + +EightBit::GameBoy::WhiteNoiseWaveVoice* EightBit::GameBoy::Audio::voice4() { + return (WhiteNoiseWaveVoice*)voice(3).get(); +} + +EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel(int i) { + return m_channels[i]; +} +EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel1() { + return channel(0); +} +EightBit::GameBoy::OutputChannel& EightBit::GameBoy::Audio::channel2() { + return channel(1); +} + +bool EightBit::GameBoy::Audio::enabled() const { + return m_enabled; +} + +void EightBit::GameBoy::Audio::setEnabled(bool value) { + m_enabled = value; + if (!enabled()) + reset(); +} + +void EightBit::GameBoy::Audio::reset() { + m_enabled = false; + for (auto voice : m_voices) + voice->reset(); + for (auto& channel : m_channels) + channel.reset(); +} + +bool EightBit::GameBoy::Audio::zeroed() const { + auto channelsZeroed = m_channels[0].zeroed() && m_channels[1].zeroed(); + auto voice1Zero = m_voices[0]->zeroed(); + auto voice2Zero = m_voices[1]->zeroed(); + auto voice3Zero = m_voices[2]->zeroed(); + auto voice4Zero = m_voices[3]->zeroed(); + auto voicesZeroed = voice1Zero && voice2Zero && voice3Zero && voice4Zero; + return !enabled() && channelsZeroed && voicesZeroed; +} + +void EightBit::GameBoy::Audio::dumpVoice(int i) const { + std::cout << "** Voice " << i + 1 << std::endl; + m_voices[i]->dump(); +} + +void EightBit::GameBoy::Audio::dumpVoices() const { + for (int i = 0; i < 4; ++i) + dumpVoice(i); +} + +void EightBit::GameBoy::Audio::dumpChannel(int i) const { + std::cout << "** Channel " << i + 1 << std::endl; + m_channels[i].dump(); +} + +void EightBit::GameBoy::Audio::dumpChannels() const { + for (int i = 0; i < 2; ++i) + dumpChannel(i); +} + +void EightBit::GameBoy::Audio::dump() const { + dumpVoices(); + dumpChannels(); +} + +// + +bool EightBit::GameBoy::Audio::voice1On() const { + return true; +} +bool EightBit::GameBoy::Audio::voice2On() const { + return true; +} +bool EightBit::GameBoy::Audio::voice3On() const { + return true; +} +bool EightBit::GameBoy::Audio::voice4On() const { + return true; +} + +// + +uint8_t EightBit::GameBoy::Audio::toNRx1(int i) { + auto voice = (RectangularVoice*)m_voices[i].get(); + return (voice->waveFormDutyCycle() << 6) | Processor::Mask6; +} + +void EightBit::GameBoy::Audio::fromNRx1(int i, uint8_t value) { + auto voice = (RectangularVoice*)m_voices[i].get(); + voice->setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 + voice->setLength(value & Processor::Mask6); // Bits 0-5 +} + +uint8_t EightBit::GameBoy::Audio::toNRx2(int i) { + auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); + auto& envelope = voice->envelope(); + return (envelope.default() << 4) | (envelope.direction() << 3) | envelope.stepLength(); +} + +void EightBit::GameBoy::Audio::fromNRx2(int i, uint8_t value) { + auto voice = (EnvelopedRectangularVoice*)m_voices[i].get(); + auto& envelope = voice->envelope(); + envelope.setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 + envelope.setDirection((value >> 3) & Processor::Mask1); // Bit 3 + envelope.setStepLength(value & Processor::Mask3); // Bits 0-2 +} + +uint8_t EightBit::GameBoy::Audio::toNRx3(int i) { + return Processor::Mask8; +} + +void EightBit::GameBoy::Audio::fromNRx3(int i, uint8_t value) { + auto voice = (WaveVoice*)m_voices[i].get(); + voice->setFrequencyLowOrder(value); +} + +// Sound mode 1 register: Sweep + +uint8_t EightBit::GameBoy::Audio::toNR10() { + auto& sweep = voice1()->sweep(); + return + Processor::Bit7 + | (sweep.time() << 4) + | (sweep.direction() << 3) + | sweep.shift(); +} + +void EightBit::GameBoy::Audio::fromNR10(uint8_t value) { + auto& sweep = voice1()->sweep(); + sweep.setTime((value >> 4) & Processor::Mask3); // Bits 4-6 + sweep.setDirection((value >> 3) & Processor::Mask1); // Bit 3 + sweep.setShift(value & Processor::Mask3); // Bits 0-2 +} + +// Sound mode 1 register: Sound length / Wave pattern duty +uint8_t EightBit::GameBoy::Audio::toNR11() { + return toNRx1(0); +} +void EightBit::GameBoy::Audio::fromNR11(uint8_t value) { + fromNRx1(0, value); +} + +// Sound mode 1 register: Envelope +uint8_t EightBit::GameBoy::Audio::toNR12() { + return toNRx2(0); +} +void EightBit::GameBoy::Audio::fromNR12(uint8_t value) { + fromNRx2(0, value); +} + +// Sound mode 1 register: Frequency lo +uint8_t EightBit::GameBoy::Audio::toNR13() { + return toNRx3(0); +} +void EightBit::GameBoy::Audio::fromNR13(uint8_t value) { + fromNRx3(0, value); +} + +// Sound mode 1 register: Frequency hi + +uint8_t EightBit::GameBoy::Audio::toNR14() { + return Processor::Bit7 | (voice1()->type() << 6) | Processor::Mask6; +} + +void EightBit::GameBoy::Audio::fromNR14(uint8_t value) { + voice1()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 + voice1()->setType((value >> 6) & Processor::Mask1); // Bits 6 + voice1()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 +} + +// Sound mode 2 register: Sound length / Wave pattern duty +uint8_t EightBit::GameBoy::Audio::toNR21() { + return toNRx1(1); +} +void EightBit::GameBoy::Audio::fromNR21(uint8_t value) { + fromNRx1(1, value); +} + +// Sound mode 2 register: Envelope +uint8_t EightBit::GameBoy::Audio::toNR22() { + return toNRx2(1); +} +void EightBit::GameBoy::Audio::fromNR22(uint8_t value) { + fromNRx2(1, value); +} + +// Sound mode 2 register: Frequency lo +uint8_t EightBit::GameBoy::Audio::toNR23() { + return toNRx3(1); +} +void EightBit::GameBoy::Audio::fromNR23(uint8_t value) { + fromNRx3(1, value); +} + +// Sound mode 2 register: Frequency hi + +uint8_t EightBit::GameBoy::Audio::toNR24() { + return Processor::Bit7 | (voice2()->type() << 6) | Processor::Mask6; +} + +void EightBit::GameBoy::Audio::fromNR24(uint8_t value) { + voice2()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 + voice2()->setType((value >> 6) & Processor::Mask1); // Bits 6 + voice2()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 +} + +// Sound mode 3 register: Sound on/off + +uint8_t EightBit::GameBoy::Audio::toNR30() { + return (voice3()->enabled() << 7) | Processor::Mask7; +} + +void EightBit::GameBoy::Audio::fromNR30(uint8_t value) { + voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 +} + +// Sound mode 3 register: Sound length + +uint8_t EightBit::GameBoy::Audio::toNR31() { + return voice3()->length(); +} + +void EightBit::GameBoy::Audio::fromNR31(uint8_t value) { + voice3()->setLength(value); +} + +// Sound mode 3 register: Select output level + +uint8_t EightBit::GameBoy::Audio::toNR32() { + return Processor::Bit7 | Processor::Bit6 | voice3()->level() << 5 | Processor::Mask5; +} + +void EightBit::GameBoy::Audio::fromNR32(uint8_t value) { + voice3()->setLevel((value >> 5) & Processor::Mask2); // Bits 6-5 +} + +// Sound mode 3 register: Frequency lo +uint8_t EightBit::GameBoy::Audio::toNR33() { + return toNRx3(2); +} +void EightBit::GameBoy::Audio::fromNR33(uint8_t value) { + fromNRx3(2, value); +} + +// Sound mode 3 register: Frequency hi + +uint8_t EightBit::GameBoy::Audio::toNR34() { + return Processor::Bit7 | (voice3()->type() << 6) | Processor::Mask6; +} + +void EightBit::GameBoy::Audio::fromNR34(uint8_t value) { + voice3()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 + voice3()->setType((value >> 6) & Processor::Mask1); // Bits 6 + voice3()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 +} + +// Sound mode 4 register: Sound length + +uint8_t EightBit::GameBoy::Audio::toNR41() { + return Processor::Bit7 | Processor::Bit6 | voice4()->length(); +} + +void EightBit::GameBoy::Audio::fromNR41(uint8_t value) { + voice4()->setLength(value); +} + +// Sound mode 4 register: Envelope +uint8_t EightBit::GameBoy::Audio::toNR42() { + return toNRx2(3); +} +void EightBit::GameBoy::Audio::fromNR42(uint8_t value) { + fromNRx2(3, value); +} + +// Sound mode 4 register: Polynomial counter + +uint8_t EightBit::GameBoy::Audio::toNR43() { + return + (voice4()->polynomialShiftClockFrequency() << 4) + | voice4()->polynomialCounterSteps() << 3 + | voice4()->frequencyDivisionRatio(); +} + +void EightBit::GameBoy::Audio::fromNR43(uint8_t value) { + voice4()->setPolynomialShiftClockFrequency((value >> 4) & Processor::Mask4); // Bits 4-7 + voice4()->setPolynomialCounterSteps((value >> 3) & Processor::Mask1); // Bit 3 + voice4()->setFrequencyDivisionRatio(value & Processor::Mask3); // Bits 0-2 +} + +// Sound mode 4 register: counter/consecutive; inital + +uint8_t EightBit::GameBoy::Audio::toNR44() { + return Processor::Bit7 | (voice4()->type() << 6) | Processor::Mask6; +} + +void EightBit::GameBoy::Audio::fromNR44(uint8_t value) { + voice4()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 + voice4()->setType((value >> 6) & Processor::Mask1); // Bit 6 +} + +// Channel control: on-off/volume + +uint8_t EightBit::GameBoy::Audio::toNR50() { + return + (channel2().vin() << 7) + | (channel2().outputLevel() << 4) + | (channel2().vin() << 3) + | channel2().outputLevel(); +} + +void EightBit::GameBoy::Audio::fromNR50(uint8_t value) { + channel2().setVin((value >> 7) & Processor::Mask1); // Bit 7 + channel2().setOutputLevel((value >> 4) & Processor::Mask3); // Bits 4-6 + channel1().setVin((value >> 3) & Processor::Mask1); // Bit 3 + channel1().setOutputLevel(value & Processor::Mask3); // Bits 0-2 +} + +// Selection of Sound output terminal + +uint8_t EightBit::GameBoy::Audio::toNR51() { + return + (channel2().outputVoice4() << 7) + | (channel2().outputVoice3() << 6) + | (channel2().outputVoice2() << 5) + | (channel2().outputVoice1() << 4) + | (channel1().outputVoice4() << 3) + | (channel1().outputVoice3() << 2) + | (channel1().outputVoice2() << 1) + | (int)channel1().outputVoice1(); +} + +void EightBit::GameBoy::Audio::fromNR51(uint8_t value) { + channel2().outputVoice4() = (value >> 7) & Processor::Mask1; // Bit 7 + channel2().outputVoice3() = (value >> 6) & Processor::Mask1; // Bit 6 + channel2().outputVoice2() = (value >> 5) & Processor::Mask1; // Bit 5 + channel2().outputVoice1() = (value >> 4) & Processor::Mask1; // Bit 4 + channel1().outputVoice4() = (value >> 3) & Processor::Mask1; // Bit 3 + channel1().outputVoice3() = (value >> 2) & Processor::Mask1; // Bit 2 + channel1().outputVoice2() = (value >> 1) & Processor::Mask1; // Bit 1 + channel1().outputVoice1() = value & Processor::Mask1; // Bit 0 +} + +// Sound on/off + +uint8_t EightBit::GameBoy::Audio::toNR52() { + return + (enabled() << 7) + | Processor::Bit6 | Processor::Bit5 | Processor::Bit4 + | (voice4On() << 3) + | (voice3On() << 2) + | (voice2On() << 1) + | (int)voice1On(); +} + +void EightBit::GameBoy::Audio::fromNR52(uint8_t value) { + setEnabled((value >> 7) & Processor::Mask1); // Bit 7 +} + +void EightBit::GameBoy::Audio::setPackedWaveDatum(int i, uint8_t value) { + voice3()->setPackedWaveDatum(i, value); +} + +uint8_t EightBit::GameBoy::Audio::packedWaveDatum(int i) { + return voice3()->packedWaveDatum(i); +} + +void EightBit::GameBoy::Audio::stepFrame(int cycles) { + m_frameSequencer.step(cycles); +} + +void EightBit::GameBoy::Audio::Sequencer_FrameStep(const int step) { +} + +void EightBit::GameBoy::Audio::Sequencer_LengthStep(const int step) { +} + +void EightBit::GameBoy::Audio::Sequencer_VolumeStep(const int step) { +} + +void EightBit::GameBoy::Audio::Sequencer_SweepStep(const int step) { +} diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj index 4260982..20e1024 100644 --- a/LR35902/src/LR35902.vcxproj +++ b/LR35902/src/LR35902.vcxproj @@ -152,6 +152,7 @@ + diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters index 74335be..8fd974c 100644 --- a/LR35902/src/LR35902.vcxproj.filters +++ b/LR35902/src/LR35902.vcxproj.filters @@ -64,5 +64,8 @@ Source Files + + Source Files + \ No newline at end of file