First stab at audio initialisation.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-09-19 23:11:50 +01:00
parent 685a645674
commit e06a092b2a
2 changed files with 145 additions and 25 deletions

View File

@ -10,13 +10,20 @@
namespace EightBit { namespace EightBit {
namespace GameBoy { namespace GameBoy {
class Envelope { class Envelope final {
public: public:
Envelope() Envelope() {}
: m_defaultValue(0), m_direction(0), m_stepLength(0) {}
enum Direction { Attenuate, Amplify }; enum Direction { Attenuate, Amplify };
void reset() {
m_defaultValue = m_direction = m_stepLength = 0;
}
bool zeroed() const {
return (default() == 0) && (stepLength() == 0) && (direction() == Attenuate);
}
int default() const { return m_defaultValue; } int default() const { return m_defaultValue; }
void setDefault(int value) { m_defaultValue = value; } void setDefault(int value) { m_defaultValue = value; }
@ -37,13 +44,20 @@ namespace EightBit {
int m_stepLength; int m_stepLength;
}; };
class Sweep { class Sweep final {
public: public:
Sweep() Sweep() {}
: m_time(0), m_direction(0), m_shift(0) {}
enum Direction { Addition, Subtraction }; enum Direction { Addition, Subtraction };
void reset() {
m_time = m_direction = m_shift = 0;
}
bool zeroed() const {
return (time() == 0) && (shift() == 0) && (direction() == Addition);
}
int time() const { return m_time; } int time() const { return m_time; }
void setTime(int value) { m_time = value; } void setTime(int value) { m_time = value; }
@ -66,8 +80,15 @@ namespace EightBit {
class AudioVoice { class AudioVoice {
public: public:
AudioVoice() AudioVoice() {}
: m_counterContinuous(0), m_initialise(0) {}
virtual void reset() {
m_counterContinuous = m_initialise = 0;
}
virtual bool zeroed() const {
return !initialise() && (type() == Continuous);
}
enum Type { Continuous, Counter }; enum Type { Continuous, Counter };
@ -89,8 +110,16 @@ namespace EightBit {
class WaveVoice : public AudioVoice { class WaveVoice : public AudioVoice {
public: public:
WaveVoice() WaveVoice() {}
: m_frequencyLowOrder(0), m_frequencyHighOrder(0) {}
virtual void reset() override {
AudioVoice::reset();
m_frequencyLowOrder = m_frequencyHighOrder = 0;
}
virtual bool zeroed() const override {
return AudioVoice::zeroed() && (frequency() == 0);
}
int frequencyLowOrder() const { return m_frequencyLowOrder; } int frequencyLowOrder() const { return m_frequencyLowOrder; }
@ -135,8 +164,16 @@ namespace EightBit {
class RectangularVoice : public WaveVoice { class RectangularVoice : public WaveVoice {
public: public:
RectangularVoice() RectangularVoice() {}
: m_waveFormDutyCycle(0), m_soundLength(0) {}
virtual void reset() override {
WaveVoice::reset();
m_waveFormDutyCycle = m_soundLength = 0;
}
virtual bool zeroed() const override {
return WaveVoice::zeroed() && (waveFormDutyCycle() == 0) && (length() == 0);
}
int waveFormDutyCycle() const { return m_waveFormDutyCycle; } int waveFormDutyCycle() const { return m_waveFormDutyCycle; }
void setWaveFormDutyCycle(int value) { m_waveFormDutyCycle = value; } void setWaveFormDutyCycle(int value) { m_waveFormDutyCycle = value; }
@ -159,6 +196,15 @@ namespace EightBit {
public: public:
EnvelopedRectangularVoice() {} EnvelopedRectangularVoice() {}
virtual void reset() override {
RectangularVoice::reset();
m_envelope.reset();
}
virtual bool zeroed() const override {
return RectangularVoice::zeroed() && m_envelope.zeroed();
}
Envelope& envelope() { return m_envelope; } Envelope& envelope() { return m_envelope; }
virtual void dump() const override { virtual void dump() const override {
@ -175,6 +221,15 @@ namespace EightBit {
public: public:
SweptEnvelopedRectangularVoice() {} SweptEnvelopedRectangularVoice() {}
virtual void reset() override {
EnvelopedRectangularVoice::reset();
m_sweep.reset();
}
virtual bool zeroed() const override {
return EnvelopedRectangularVoice::zeroed() && m_sweep.zeroed();
}
Sweep& sweep() { return m_sweep; } Sweep& sweep() { return m_sweep; }
virtual void dump() const override { virtual void dump() const override {
@ -189,12 +244,30 @@ namespace EightBit {
// NR3X // NR3X
class UserDefinedWaveVoice : public WaveVoice { class UserDefinedWaveVoice : public WaveVoice {
public: public:
UserDefinedWaveVoice() UserDefinedWaveVoice() {}
: m_enabled(0), m_soundLength(0), m_outputLevel(0) {
virtual void reset() override {
WaveVoice::reset();
m_enabled = m_soundLength = m_outputLevel = 0;
for (auto& datum : m_waveData) for (auto& datum : m_waveData)
datum = 0; datum = 0;
} }
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; } bool enabled() const { return !!m_enabled; }
void setEnabled(bool value) { m_enabled = value; } void setEnabled(bool value) { m_enabled = value; }
@ -231,12 +304,23 @@ namespace EightBit {
// NR4X // NR4X
class WhiteNoiseWaveVoice : public AudioVoice { class WhiteNoiseWaveVoice : public AudioVoice {
public: public:
WhiteNoiseWaveVoice() WhiteNoiseWaveVoice() {}
: m_soundLength(0),
m_polynomialShiftClockFrequency(0), virtual void reset() override {
m_polynomialCounterSteps(0), AudioVoice::reset();
m_frequencyDivisionRatio(0) m_envelope.reset();
{} m_soundLength = m_polynomialShiftClockFrequency = m_polynomialCounterSteps = m_frequencyDivisionRatio = 0;
}
virtual bool zeroed() const override {
return
AudioVoice::zeroed()
&& m_envelope.zeroed()
&& (length() == 0)
&& (polynomialShiftClockFrequency() == 0)
&& (polynomialCounterSteps() == 0)
&& (frequencyDivisionRatio() == 0);
}
Envelope& envelope() { return m_envelope; } Envelope& envelope() { return m_envelope; }
@ -260,14 +344,24 @@ namespace EightBit {
int m_frequencyDivisionRatio; int m_frequencyDivisionRatio;
}; };
class OutputChannel { class OutputChannel final {
public: public:
OutputChannel() OutputChannel() {}
: m_vin(false), m_outputLevel(0) {
void reset() {
m_vin = false;
m_outputLevel = 0;
for (auto& outputVoice : m_outputVoices) for (auto& outputVoice : m_outputVoices)
outputVoice = false; outputVoice = false;
} }
bool zeroed() const {
return
!vin()
&& outputLevel() == 0
&& !m_outputVoices[0] && !m_outputVoices[1] && !m_outputVoices[2] && !m_outputVoices[3];
}
bool vin() const { return m_vin; } bool vin() const { return m_vin; }
void setVin(bool value) { m_vin = value; } void setVin(bool value) { m_vin = value; }
@ -295,7 +389,7 @@ namespace EightBit {
std::array<bool, 4> m_outputVoices; std::array<bool, 4> m_outputVoices;
}; };
class Audio { class Audio final {
public: public:
Audio() Audio()
: m_enabled(false) { : m_enabled(false) {
@ -328,7 +422,30 @@ namespace EightBit {
OutputChannel& channel2() { return channel(1); } OutputChannel& channel2() { return channel(1); }
bool enabled() const { return m_enabled; } bool enabled() const { return m_enabled; }
void setEnabled(bool value) { m_enabled = value; }
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 { void dumpVoice(int i) const {
std::cout << "** Voice " << i + 1 << std::endl; std::cout << "** Voice " << i + 1 << std::endl;

View File

@ -39,6 +39,9 @@ EightBit::GameBoy::Bus::Bus()
void EightBit::GameBoy::Bus::reset() { void EightBit::GameBoy::Bus::reset() {
audio().reset();
assert(audio().zeroed());
poke(BASE + NR52, 0xf1); poke(BASE + NR52, 0xf1);
poke(BASE + LCDC, DisplayBackground | BackgroundCharacterDataSelection | LcdEnable); poke(BASE + LCDC, DisplayBackground | BackgroundCharacterDataSelection | LcdEnable);
m_divCounter.word = 0xabcc; m_divCounter.word = 0xabcc;