From 685a6456748102ab50052ae2a96a9d942eae23aa Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Mon, 18 Sep 2017 19:17:38 +0100 Subject: [PATCH] 1) Correct frequency hi/lo storage 2) Calculate resultant frequency in Hz. 3) Add extra logging for audio device register writes. Signed-off-by: Adrian.Conlon --- LR35902/inc/Audio.h | 93 +++++++++++++++++++++++++++----------- LR35902/src/GameBoyBus.cpp | 21 +++++++++ 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/LR35902/inc/Audio.h b/LR35902/inc/Audio.h index 99f8657..42a6a7a 100644 --- a/LR35902/inc/Audio.h +++ b/LR35902/inc/Audio.h @@ -12,7 +12,8 @@ namespace EightBit { class Envelope { public: - Envelope() {} + Envelope() + : m_defaultValue(0), m_direction(0), m_stepLength(0) {} enum Direction { Attenuate, Amplify }; @@ -38,7 +39,8 @@ namespace EightBit { class Sweep { public: - Sweep() {} + Sweep() + : m_time(0), m_direction(0), m_shift(0) {} enum Direction { Addition, Subtraction }; @@ -64,7 +66,8 @@ namespace EightBit { class AudioVoice { public: - AudioVoice() {} + AudioVoice() + : m_counterContinuous(0), m_initialise(0) {} enum Type { Continuous, Counter }; @@ -86,7 +89,8 @@ namespace EightBit { class WaveVoice : public AudioVoice { public: - WaveVoice() {} + WaveVoice() + : m_frequencyLowOrder(0), m_frequencyHighOrder(0) {} int frequencyLowOrder() const { return m_frequencyLowOrder; } @@ -103,7 +107,14 @@ namespace EightBit { } int frequency() const { - return (m_frequencyHighOrder >> 8) | m_frequencyLowOrder; + return (m_frequencyHighOrder << 8) | m_frequencyLowOrder; + } + + int hertz() const { + // f = 4194304 / (4 x 8 x (2048 - X)) Hz + auto clock = 4 * 1024 * 1024; + auto division = 4 * 8 * (2048 - frequency()); + return clock / division; } void setFrequency(int value) { @@ -114,7 +125,7 @@ namespace EightBit { virtual void dump() const override { AudioVoice::dump(); - std::cout << "Wave Voice: frequency=" << frequency() << std::endl; + std::cout << "Wave Voice: frequency=" << frequency() << " (" << hertz() << ")" << std::endl; } private: @@ -124,7 +135,8 @@ namespace EightBit { class RectangularVoice : public WaveVoice { public: - RectangularVoice() {} + RectangularVoice() + : m_waveFormDutyCycle(0), m_soundLength(0) {} int waveFormDutyCycle() const { return m_waveFormDutyCycle; } void setWaveFormDutyCycle(int value) { m_waveFormDutyCycle = value; } @@ -177,7 +189,12 @@ namespace EightBit { // NR3X class UserDefinedWaveVoice : public WaveVoice { public: - UserDefinedWaveVoice() {} + UserDefinedWaveVoice() + : m_enabled(0), m_soundLength(0), m_outputLevel(0) { + for (auto& datum : m_waveData) + datum = 0; + } + bool enabled() const { return !!m_enabled; } void setEnabled(bool value) { m_enabled = value; } @@ -214,7 +231,12 @@ namespace EightBit { // NR4X class WhiteNoiseWaveVoice : public AudioVoice { public: - WhiteNoiseWaveVoice() {} + WhiteNoiseWaveVoice() + : m_soundLength(0), + m_polynomialShiftClockFrequency(0), + m_polynomialCounterSteps(0), + m_frequencyDivisionRatio(0) + {} Envelope& envelope() { return m_envelope; } @@ -240,7 +262,11 @@ namespace EightBit { class OutputChannel { public: - OutputChannel() {} + OutputChannel() + : m_vin(false), m_outputLevel(0) { + for (auto& outputVoice : m_outputVoices) + outputVoice = false; + } bool vin() const { return m_vin; } void setVin(bool value) { m_vin = value; } @@ -248,30 +274,31 @@ namespace EightBit { int outputLevel() const { return m_outputLevel; } void setOutputLevel(int value) { m_outputLevel = value; } - bool& outputVoice(int voice) { return m_outputVoice[voice]; } - bool& outputVoice1() { return m_outputVoice[0]; } - bool& outputVoice2() { return m_outputVoice[1]; } - bool& outputVoice3() { return m_outputVoice[2]; } - bool& outputVoice4() { return m_outputVoice[3]; } + 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_outputVoice[0] << (int)m_outputVoice[1] << (int)m_outputVoice[2] << (int)m_outputVoice[3] + << ",Voices:" << (int)m_outputVoices[0] << (int)m_outputVoices[1] << (int)m_outputVoices[2] << (int)m_outputVoices[3] << std::endl; } private: bool m_vin; int m_outputLevel; - std::array m_outputVoice; + std::array m_outputVoices; }; class Audio { public: - Audio() { + Audio() + : m_enabled(false) { m_voices[0] = std::make_shared(); m_voices[1] = std::make_shared(); m_voices[2] = std::make_shared(); @@ -303,15 +330,29 @@ namespace EightBit { bool enabled() const { return m_enabled; } void setEnabled(bool value) { m_enabled = value; } + 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 { - for (int i = 0; i < 4; ++i) { - std::cout << "** Voice " << i + 1 << std::endl; - m_voices[i]->dump(); - } - for (int i = 0; i < 2; ++i) { - std::cout << "** Channel " << i + 1 << std::endl; - m_channels[i].dump(); - } + dumpVoices(); + dumpChannels(); } private: diff --git a/LR35902/src/GameBoyBus.cpp b/LR35902/src/GameBoyBus.cpp index 5800d7e..1e97f86 100644 --- a/LR35902/src/GameBoyBus.cpp +++ b/LR35902/src/GameBoyBus.cpp @@ -145,6 +145,7 @@ void EightBit::GameBoy::Bus::Bus_ReadingByte(const uint16_t address) { case NR51: break; case NR52: + mask(Processor::Bit7 | Processor::Mask4); break; // LCD Display Registers @@ -249,91 +250,109 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { audio().voice1()->sweep().setTime((value >> 4) & Processor::Mask3); // Bits 4-6 audio().voice1()->sweep().setDirection((value >> 3) & Processor::Mask1); // Bit 3 audio().voice1()->sweep().setShift(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(0); break; case BASE + NR11: // Sound mode 1 register: Sound length / Wave pattern duty audio().voice1()->setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 audio().voice1()->setLength(value & Processor::Mask6); // Bits 0-5 + audio().dumpVoice(0); break; case BASE + NR12: // Sound mode 1 register: Envelope audio().voice1()->envelope().setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 audio().voice1()->envelope().setDirection((value >> 3) & Processor::Mask1); // Bit 3 audio().voice1()->envelope().setStepLength(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(0); break; case BASE + NR13: // Sound mode 1 register: Frequency lo audio().voice1()->setFrequencyLowOrder(value); + audio().dumpVoice(0); break; case BASE + NR14: // Sound mode 1 register: Frequency hi audio().voice1()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 audio().voice1()->setType((value >> 6) & Processor::Mask1); // Bits 6 audio().voice1()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(0); break; case BASE + NR21: // Sound mode 2 register: Sound length / Wave pattern duty audio().voice2()->setWaveFormDutyCycle((value >> 6) & Processor::Mask2); // Bits 6-7 audio().voice2()->setLength(value & Processor::Mask6); // Bits 0-5 + audio().dumpVoice(1); break; case BASE + NR22: // Sound mode 2 register: Envelope audio().voice2()->envelope().setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 audio().voice2()->envelope().setDirection((value >> 3) & Processor::Mask1); // Bit 3 audio().voice2()->envelope().setStepLength(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(1); break; case BASE + NR23: // Sound mode 2 register: Frequency lo audio().voice2()->setFrequencyLowOrder(value); + audio().dumpVoice(1); break; case BASE + NR24: // Sound mode 2 register: Frequency hi audio().voice2()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 audio().voice2()->setType((value >> 6) & Processor::Mask1); // Bit 6 audio().voice2()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(1); break; case BASE + NR30: // Sound mode 3 register: Sound on/off audio().voice3()->setEnabled((value >> 7) & Processor::Mask1); // Bit 7 + audio().dumpVoice(2); break; case BASE + NR31: // Sound mode 3 register: Sound length audio().voice3()->setLength(value); + audio().dumpVoice(2); break; case BASE + NR32: // Sound mode 3 register: Select output level audio().voice3()->setLevel(value); + audio().dumpVoice(2); break; case BASE + NR33: // Sound mode 3 register: Frequency lo audio().voice3()->setFrequencyLowOrder(value); + audio().dumpVoice(2); break; case BASE + NR34: // Sound mode 3 register: Frequency hi audio().voice3()->setInitialise((value >> 7) & Processor::Mask1); // Bits 7 audio().voice3()->setType((value >> 6) & Processor::Mask1); // Bits 6 audio().voice3()->setFrequencyHighOrder(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(2); break; case BASE + NR41: // Sound mode 4 register: Sound length audio().voice4()->setLength(value & Processor::Mask6); // Bits 0-5 + audio().dumpVoice(3); break; case BASE + NR42: // Sound mode 4 register: Envelope audio().voice4()->envelope().setDefault((value >> 4) & Processor::Mask4); // Bits 4-7 audio().voice4()->envelope().setDirection((value >> 3) & Processor::Mask1); // Bit 3 audio().voice4()->envelope().setStepLength(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(3); break; case BASE + NR43: // Sound mode 4 register: Polynomial counter audio().voice4()->setPolynomialShiftClockFrequency((value >> 4) & Processor::Mask4); // Bits 4-7 audio().voice4()->setPolynomialCounterSteps((value >> 3) & Processor::Mask1); // Bit 3 audio().voice4()->setFrequencyDivisionRatio(value & Processor::Mask3); // Bits 0-2 + audio().dumpVoice(3); break; case BASE + NR44: // Sound mode 4 register: counter/consecutive; inital audio().voice4()->setInitialise((value >> 7) & Processor::Mask1); // Bit 7 audio().voice4()->setType((value >> 6) & Processor::Mask1); // Bit 6 + audio().dumpVoice(3); break; case BASE + NR50: // Channel control: on-off/volume @@ -341,6 +360,7 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { audio().channel2().setOutputLevel((value >> 4) & Processor::Mask3); // Bits 4-6 audio().channel1().setVin((value >> 3) & Processor::Mask1); // Bit 3 audio().channel1().setOutputLevel(value & Processor::Mask3); // Bits 0-2 + audio().dumpChannels(); break; case BASE + NR51: @@ -352,6 +372,7 @@ void EightBit::GameBoy::Bus::Bus_WrittenByte(const uint16_t address) { audio().channel1().outputVoice3() = (value >> 2) & Processor::Mask1; // Bit 2 audio().channel1().outputVoice2() = (value >> 1) & Processor::Mask1; // Bit 1 audio().channel1().outputVoice1() = value & Processor::Mask1; // Bit 0 + audio().dumpChannels(); break; case BASE + NR52: // Sound on/off