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 <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-09-18 19:17:38 +01:00
parent 735ebe3e85
commit 685a645674
2 changed files with 88 additions and 26 deletions

View File

@ -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<bool, 4> m_outputVoice;
std::array<bool, 4> m_outputVoices;
};
class Audio {
public:
Audio() {
Audio()
: m_enabled(false) {
m_voices[0] = std::make_shared<SweptEnvelopedRectangularVoice>();
m_voices[1] = std::make_shared<EnvelopedRectangularVoice>();
m_voices[2] = std::make_shared<UserDefinedWaveVoice>();
@ -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:

View File

@ -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