mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-01-11 02:29:50 +00:00
First stab at audio initialisation.
Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
parent
685a645674
commit
e06a092b2a
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user