Files
DbNesEmulator/nescorelib/emu/aputrl.cpp
2018-12-16 22:19:06 +01:00

175 lines
4.2 KiB
C++

#include "aputrl.h"
// Qt includes
#include <QDataStream>
// local includes
#include "emusettings.h"
#include "apu.h"
ApuTrl::ApuTrl(Apu &apu) :
m_apu(apu)
{
}
void ApuTrl::apuTrlHardReset()
{
m_apuTrlLinerControlFlag = false;
m_apuTrlLinerControlReload = 0;
m_apuTrlTimer = 0;
m_apuTrlLengthEnabled = false;
m_apuTrlLengthCounter = 0;
m_apuTrlLinerControlReloadFlag = false;
m_apuTrlLinerCounter = 0;
m_apuTrlOutput = 0;
m_apuTrlPeriodDevider = 0;
m_apuTrlStep = 0;
m_apuTrlIgnoreReload = false;
}
void ApuTrl::apuTrlSoftReset()
{
apuTrlHardReset();
}
void ApuTrl::apuTrlClock()
{
static constexpr std::array<quint8, 32> stepSeq {
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
m_apuTrlPeriodDevider--;
if (m_apuTrlPeriodDevider <= 0)
{
m_apuTrlPeriodDevider = m_apuTrlTimer + 1;
if (m_apuTrlLengthCounter > 0 && m_apuTrlLinerCounter > 0)
{
if (m_apuTrlTimer >= 4)
{
m_apuTrlStep++;
m_apuTrlStep &= 0x1F;
if (EmuSettings::Audio::ChannelEnabled::TRL)
m_apuTrlOutput = stepSeq[m_apuTrlStep];
}
}
}
}
void ApuTrl::apuTrlClockLength()
{
if (m_apuTrlLengthCounter > 0 && !m_apuTrlLinerControlFlag)
{
m_apuTrlLengthCounter--;
if (m_apu.regAccessHappened())
{
// This is not a hack, there is some hidden mechanism in the nes, that do reload and clock stuff
if (m_apu.regIoAddr() == 0xB && m_apu.regAccessW())
{
m_apuTrlIgnoreReload = true;
}
}
}
}
void ApuTrl::apuTrlClockEnvelope()
{
if (m_apuTrlLinerControlReloadFlag)
{
m_apuTrlLinerCounter = m_apuTrlLinerControlReload;
}
else
{
if (m_apuTrlLinerCounter > 0)
m_apuTrlLinerCounter--;
}
if (!m_apuTrlLinerControlFlag)
m_apuTrlLinerControlReloadFlag = false;
}
void ApuTrl::apuOnRegister4008()
{
// Only writes accepted
if (!m_apu.regAccessW())
return;
m_apuTrlLinerControlFlag = (m_apu.regIoDb() & 0x80) == 0x80;
m_apuTrlLinerControlReload = m_apu.regIoDb() & 0x7F;
}
void ApuTrl::apuOnRegister4009()
{
}
void ApuTrl::apuOnRegister400A()
{
// Only writes accepted
if (!m_apu.regAccessW())
return;
m_apuTrlTimer = (m_apuTrlTimer & 0x7F00) | m_apu.regIoDb();
}
void ApuTrl::apuOnRegister400B()
{
// Only writes accepted
if (!m_apu.regAccessW())
return;
m_apuTrlTimer = (m_apuTrlTimer & 0x00FF) | (m_apu.regIoDb() & 0x7) << 8;
if (m_apuTrlLengthEnabled && !m_apuTrlIgnoreReload)
m_apuTrlLengthCounter = m_apu.m_sqDurationTable[m_apu.regIoDb() >> 3];
if (m_apuTrlIgnoreReload)
m_apuTrlIgnoreReload = false;
m_apuTrlLinerControlReloadFlag = true;
}
void ApuTrl::apuTrlOn4015()
{
m_apuTrlLengthEnabled = (m_apu.regIoDb() & 0x04) != 0;
if (!m_apuTrlLengthEnabled)
m_apuTrlLengthCounter = 0;
}
void ApuTrl::apuTrlRead4015()
{
if (m_apuTrlLengthCounter > 0)
m_apu.setRegIoDb((m_apu.regIoDb() & 0xFB) | 0x04);
}
void ApuTrl::apuTrlWriteState(QDataStream &dataStream) const
{
dataStream
<< m_apuTrlLinerControlFlag
<< m_apuTrlLinerControlReload
<< m_apuTrlTimer
<< m_apuTrlLengthEnabled
<< m_apuTrlLengthCounter
<< m_apuTrlLinerControlReloadFlag
<< m_apuTrlLinerCounter
<< m_apuTrlOutput
<< m_apuTrlPeriodDevider
<< m_apuTrlStep
<< m_apuTrlIgnoreReload;
}
void ApuTrl::apuTrlReadState(QDataStream &dataStream)
{
dataStream
>> m_apuTrlLinerControlFlag
>> m_apuTrlLinerControlReload
>> m_apuTrlTimer
>> m_apuTrlLengthEnabled
>> m_apuTrlLengthCounter
>> m_apuTrlLinerControlReloadFlag
>> m_apuTrlLinerCounter
>> m_apuTrlOutput
>> m_apuTrlPeriodDevider
>> m_apuTrlStep
>> m_apuTrlIgnoreReload;
}
qint32 ApuTrl::output() const
{
return m_apuTrlOutput;
}