Misc: Make struct member functions file-local

This commit is contained in:
Stenzek 2023-11-18 16:21:51 +10:00
parent bee1f986a9
commit cce7be4723
No known key found for this signature in database
39 changed files with 680 additions and 595 deletions

View file

@ -33,6 +33,7 @@
Log_SetChannel(ByteStream);
namespace {
class FileByteStream : public ByteStream
{
public:
@ -174,10 +175,7 @@ public:
return true;
}
u64 GetPosition() const override
{
return _ftelli64(m_pFile);
}
u64 GetPosition() const override { return _ftelli64(m_pFile); }
u64 GetSize() const override
{
@ -232,10 +230,7 @@ public:
return true;
}
u64 GetPosition() const override
{
return static_cast<u64>(ftello(m_pFile));
}
u64 GetPosition() const override { return static_cast<u64>(ftello(m_pFile)); }
u64 GetSize() const override
{
@ -262,15 +257,9 @@ public:
return true;
}
virtual bool Commit() override
{
return true;
}
virtual bool Commit() override { return true; }
virtual bool Discard() override
{
return false;
}
virtual bool Discard() override { return false; }
protected:
FILE* m_pFile;
@ -364,10 +353,15 @@ private:
std::string m_originalFileName;
std::string m_temporaryFileName;
};
} // namespace
NullByteStream::NullByteStream() {}
NullByteStream::NullByteStream()
{
}
NullByteStream::~NullByteStream() {}
NullByteStream::~NullByteStream()
{
}
bool NullByteStream::ReadByte(u8* pDestByte)
{
@ -456,7 +450,9 @@ MemoryByteStream::MemoryByteStream(void* pMemory, u32 MemSize)
m_pMemory = (u8*)pMemory;
}
MemoryByteStream::~MemoryByteStream() {}
MemoryByteStream::~MemoryByteStream()
{
}
bool MemoryByteStream::ReadByte(u8* pDestByte)
{
@ -586,7 +582,9 @@ ReadOnlyMemoryByteStream::ReadOnlyMemoryByteStream(const void* pMemory, u32 MemS
m_pMemory = reinterpret_cast<const u8*>(pMemory);
}
ReadOnlyMemoryByteStream::~ReadOnlyMemoryByteStream() {}
ReadOnlyMemoryByteStream::~ReadOnlyMemoryByteStream()
{
}
bool ReadOnlyMemoryByteStream::ReadByte(u8* pDestByte)
{
@ -1346,6 +1344,7 @@ bool ByteStream::WriteBinaryToStream(ByteStream* stream, const void* data, size_
return stream->Write2(data, static_cast<u32>(data_length));
}
namespace {
class ZstdCompressStream final : public ByteStream
{
public:
@ -1489,12 +1488,14 @@ private:
u8 m_input_buffer[INPUT_BUFFER_SIZE];
u8 m_output_buffer[OUTPUT_BUFFER_SIZE];
};
} // namespace
std::unique_ptr<ByteStream> ByteStream::CreateZstdCompressStream(ByteStream* src_stream, int compression_level)
{
return std::make_unique<ZstdCompressStream>(src_stream, compression_level);
}
namespace {
class ZstdDecompressStream final : public ByteStream
{
public:
@ -1643,6 +1644,7 @@ private:
u8 m_input_buffer[INPUT_BUFFER_SIZE];
u8 m_output_buffer[OUTPUT_BUFFER_SIZE];
};
} // namespace
std::unique_ptr<ByteStream> ByteStream::CreateZstdDecompressStream(ByteStream* src_stream, u32 compressed_size)
{

View file

@ -14,6 +14,7 @@
#include "thirdparty/StackWalker.h"
#include <DbgHelp.h>
namespace {
class CrashHandlerStackWalker : public StackWalker
{
public:
@ -26,6 +27,7 @@ protected:
private:
HANDLE m_out_file;
};
} // namespace
CrashHandlerStackWalker::CrashHandlerStackWalker(HANDLE out_file)
: StackWalker(RetrieveVerbose, nullptr, GetCurrentProcessId(), GetCurrentProcess()), m_out_file(out_file)
@ -213,12 +215,14 @@ void CrashHandler::Uninstall()
#include <unistd.h>
namespace CrashHandler {
namespace {
struct BacktraceBuffer
{
char* buffer;
size_t used;
size_t size;
};
} // namespace
static const char* GetSignalName(int signal_no);
static void AllocateBuffer(BacktraceBuffer* buf);

View file

@ -32,6 +32,8 @@
Log_SetChannel(CDROM);
namespace CDROM {
namespace {
enum : u32
{
RAW_SECTOR_OUTPUT_SIZE = CDImage::RAW_SECTOR_SIZE - CDImage::SECTOR_SYNC_SIZE,
@ -210,6 +212,8 @@ union RequestRegister
BitField<u8, bool, 7, 1> BFRD;
};
} // namespace
static void SoftReset(TickCount ticks_late);
static bool IsDriveIdle();

View file

@ -29,6 +29,8 @@
Log_SetChannel(DMA);
namespace DMA {
namespace {
enum class SyncMode : u32
{
Manual = 0,
@ -40,35 +42,6 @@ enum class SyncMode : u32
static constexpr PhysicalMemoryAddress BASE_ADDRESS_MASK = UINT32_C(0x00FFFFFF);
// static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x001FFFFC);
static u32 GetAddressMask();
static void ClearState();
// is everything enabled for a channel to operate?
static bool CanTransferChannel(Channel channel, bool ignore_halt);
static bool IsTransferHalted();
static void UpdateIRQ();
// returns false if the DMA should now be halted
static TickCount GetTransferSliceTicks();
static TickCount GetTransferHaltTicks();
static bool TransferChannel(Channel channel);
static void HaltTransfer(TickCount duration);
static void UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late);
// from device -> memory
static TickCount TransferDeviceToMemory(Channel channel, u32 address, u32 increment, u32 word_count);
// from memory -> device
static TickCount TransferMemoryToDevice(Channel channel, u32 address, u32 increment, u32 word_count);
// configuration
static TickCount s_max_slice_ticks = 1000;
static TickCount s_halt_ticks = 100;
static std::vector<u32> s_transfer_buffer;
static std::unique_ptr<TimingEvent> s_unhalt_event;
static TickCount s_halt_ticks_remaining = 0;
struct ChannelState
{
u32 base_address = 0;
@ -110,8 +83,6 @@ struct ChannelState
bool request = false;
};
static std::array<ChannelState, NUM_CHANNELS> s_state;
union DPCR
{
u32 bits;
@ -133,15 +104,13 @@ union DPCR
BitField<u32, u8, 28, 3> priority_offset;
BitField<u32, bool, 31, 1> unused;
u8 GetPriority(Channel channel) const { return ((bits >> (static_cast<u8>(channel) * 4)) & u32(3)); }
bool GetMasterEnable(Channel channel) const
ALWAYS_INLINE u8 GetPriority(Channel channel) const { return ((bits >> (static_cast<u8>(channel) * 4)) & u32(3)); }
ALWAYS_INLINE bool GetMasterEnable(Channel channel) const
{
return ConvertToBoolUnchecked((bits >> (static_cast<u8>(channel) * 4 + 3)) & u32(1));
}
};
static DPCR s_DPCR = {};
static constexpr u32 DICR_WRITE_MASK = 0b00000000'11111111'10000000'00111111;
static constexpr u32 DICR_RESET_MASK = 0b01111111'00000000'00000000'00000000;
union DICR
@ -166,25 +135,57 @@ union DICR
BitField<u32, bool, 30, 1> OTC_irq_flag;
BitField<u32, bool, 31, 1> master_flag;
bool IsIRQEnabled(Channel channel) const
ALWAYS_INLINE bool IsIRQEnabled(Channel channel) const
{
return ConvertToBoolUnchecked((bits >> (static_cast<u8>(channel) + 16)) & u32(1));
}
bool GetIRQFlag(Channel channel) const
ALWAYS_INLINE bool GetIRQFlag(Channel channel) const
{
return ConvertToBoolUnchecked((bits >> (static_cast<u8>(channel) + 24)) & u32(1));
}
void SetIRQFlag(Channel channel) { bits |= (u32(1) << (static_cast<u8>(channel) + 24)); }
void ClearIRQFlag(Channel channel) { bits &= ~(u32(1) << (static_cast<u8>(channel) + 24)); }
ALWAYS_INLINE void SetIRQFlag(Channel channel) { bits |= (u32(1) << (static_cast<u8>(channel) + 24)); }
ALWAYS_INLINE void ClearIRQFlag(Channel channel) { bits &= ~(u32(1) << (static_cast<u8>(channel) + 24)); }
void UpdateMasterFlag()
ALWAYS_INLINE void UpdateMasterFlag()
{
master_flag = master_enable && ((((bits >> 16) & u32(0b1111111)) & ((bits >> 24) & u32(0b1111111))) != 0);
}
};
} // namespace
static u32 GetAddressMask();
static void ClearState();
// is everything enabled for a channel to operate?
static bool CanTransferChannel(Channel channel, bool ignore_halt);
static bool IsTransferHalted();
static void UpdateIRQ();
// returns false if the DMA should now be halted
static TickCount GetTransferSliceTicks();
static TickCount GetTransferHaltTicks();
static bool TransferChannel(Channel channel);
static void HaltTransfer(TickCount duration);
static void UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late);
// from device -> memory
static TickCount TransferDeviceToMemory(Channel channel, u32 address, u32 increment, u32 word_count);
// from memory -> device
static TickCount TransferMemoryToDevice(Channel channel, u32 address, u32 increment, u32 word_count);
// configuration
static TickCount s_max_slice_ticks = 1000;
static TickCount s_halt_ticks = 100;
static std::vector<u32> s_transfer_buffer;
static std::unique_ptr<TimingEvent> s_unhalt_event;
static TickCount s_halt_ticks_remaining = 0;
static std::array<ChannelState, NUM_CHANNELS> s_state;
static DPCR s_DPCR = {};
static DICR s_DICR = {};
}; // namespace DMA

View file

@ -48,7 +48,7 @@ static bool ParseJsonEntry(Entry* entry, const rapidjson::Value& value);
static bool ParseJsonCodes(u32 index, const rapidjson::Value& value);
static bool LoadTrackHashes();
std::array<const char*, static_cast<u32>(GameDatabase::Trait::Count)> s_trait_names = {{
static std::array<const char*, static_cast<u32>(GameDatabase::Trait::Count)> s_trait_names = {{
"ForceInterpreter",
"ForceSoftwareRenderer",
"ForceSoftwareRendererForReadbacks",

View file

@ -36,6 +36,8 @@ Log_SetChannel(GameList);
#endif
namespace GameList {
namespace {
enum : u32
{
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
@ -54,6 +56,8 @@ struct PlayedTimeEntry
std::time_t total_played_time;
};
} // namespace
using CacheMap = PreferUnorderedStringMap<Entry>;
using PlayedTimeMap = PreferUnorderedStringMap<PlayedTimeEntry>;

View file

@ -162,24 +162,67 @@ ALWAYS_INLINE static u32 TruncateRGB(s32 value)
return static_cast<u32>(value);
}
void Initialize()
static void SetOTZ(s32 value);
static void PushSXY(s32 x, s32 y);
static void PushSZ(s32 value);
static void PushRGBFromMAC();
static u32 UNRDivide(u32 lhs, u32 rhs);
static void MulMatVec(const s16* M_, const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm);
static void MulMatVec(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm);
static void MulMatVecBuggy(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm);
static void InterpolateColor(s64 in_MAC1, s64 in_MAC2, s64 in_MAC3, u8 shift, bool lm);
static void RTPS(const s16 V[3], u8 shift, bool lm, bool last);
static void NCS(const s16 V[3], u8 shift, bool lm);
static void NCCS(const s16 V[3], u8 shift, bool lm);
static void NCDS(const s16 V[3], u8 shift, bool lm);
static void DPCS(const u8 color[3], u8 shift, bool lm);
static void Execute_MVMVA(Instruction inst);
static void Execute_SQR(Instruction inst);
static void Execute_OP(Instruction inst);
static void Execute_RTPS(Instruction inst);
static void Execute_RTPT(Instruction inst);
static void Execute_NCLIP(Instruction inst);
static void Execute_NCLIP_PGXP(Instruction inst);
static void Execute_AVSZ3(Instruction inst);
static void Execute_AVSZ4(Instruction inst);
static void Execute_NCS(Instruction inst);
static void Execute_NCT(Instruction inst);
static void Execute_NCCS(Instruction inst);
static void Execute_NCCT(Instruction inst);
static void Execute_NCDS(Instruction inst);
static void Execute_NCDT(Instruction inst);
static void Execute_CC(Instruction inst);
static void Execute_CDP(Instruction inst);
static void Execute_DPCS(Instruction inst);
static void Execute_DPCT(Instruction inst);
static void Execute_DCPL(Instruction inst);
static void Execute_INTPL(Instruction inst);
static void Execute_GPL(Instruction inst);
static void Execute_GPF(Instruction inst);
} // namespace GTE
void GTE::Initialize()
{
s_aspect_ratio = DisplayAspectRatio::R4_3;
Reset();
}
void Reset()
void GTE::Reset()
{
std::memset(&REGS, 0, sizeof(REGS));
}
bool DoState(StateWrapper& sw)
bool GTE::DoState(StateWrapper& sw)
{
sw.DoArray(REGS.r32, NUM_DATA_REGS + NUM_CONTROL_REGS);
return !sw.HasError();
}
void UpdateAspectRatio()
void GTE::UpdateAspectRatio()
{
if (!g_settings.gpu_widescreen_hack)
{
@ -227,7 +270,7 @@ void UpdateAspectRatio()
s_custom_aspect_ratio_f = static_cast<float>((4.0 / 3.0) / (static_cast<double>(num) / static_cast<double>(denom)));
}
u32 ReadRegister(u32 index)
u32 GTE::ReadRegister(u32 index)
{
DebugAssert(index < countof(REGS.r32));
@ -254,7 +297,7 @@ u32 ReadRegister(u32 index)
}
}
void WriteRegister(u32 index, u32 value)
void GTE::WriteRegister(u32 index, u32 value)
{
#if 0
if (index < 32)
@ -349,12 +392,12 @@ void WriteRegister(u32 index, u32 value)
}
}
u32* GetRegisterPtr(u32 index)
u32* GTE::GetRegisterPtr(u32 index)
{
return &REGS.r32[index];
}
ALWAYS_INLINE static void SetOTZ(s32 value)
ALWAYS_INLINE void GTE::SetOTZ(s32 value)
{
if (value < 0)
{
@ -370,7 +413,7 @@ ALWAYS_INLINE static void SetOTZ(s32 value)
REGS.dr32[7] = static_cast<u32>(value);
}
ALWAYS_INLINE static void PushSXY(s32 x, s32 y)
ALWAYS_INLINE void GTE::PushSXY(s32 x, s32 y)
{
if (x < -1024)
{
@ -399,7 +442,7 @@ ALWAYS_INLINE static void PushSXY(s32 x, s32 y)
REGS.dr32[14] = (static_cast<u32>(x) & 0xFFFFu) | (static_cast<u32>(y) << 16);
}
ALWAYS_INLINE static void PushSZ(s32 value)
ALWAYS_INLINE void GTE::PushSZ(s32 value)
{
if (value < 0)
{
@ -418,7 +461,7 @@ ALWAYS_INLINE static void PushSZ(s32 value)
REGS.dr32[19] = static_cast<u32>(value); // SZ3 <- value
}
static void PushRGBFromMAC()
ALWAYS_INLINE void GTE::PushRGBFromMAC()
{
// Note: SHR 4 used instead of /16 as the results are different.
const u32 r = TruncateRGB<0>(static_cast<u32>(REGS.MAC1 >> 4));
@ -431,7 +474,7 @@ static void PushRGBFromMAC()
REGS.dr32[22] = r | (g << 8) | (b << 16) | (c << 24); // RGB2 <- Value
}
ALWAYS_INLINE static u32 UNRDivide(u32 lhs, u32 rhs)
ALWAYS_INLINE u32 GTE::UNRDivide(u32 lhs, u32 rhs)
{
if (rhs * 2 <= lhs)
{
@ -475,7 +518,7 @@ ALWAYS_INLINE static u32 UNRDivide(u32 lhs, u32 rhs)
return std::min<u32>(0x1FFFF, result);
}
static void MulMatVec(const s16* M_, const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
void GTE::MulMatVec(const s16* M_, const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
{
#define M(i, j) M_[((i)*3) + (j)]
#define dot3(i) \
@ -491,7 +534,7 @@ static void MulMatVec(const s16* M_, const s16 Vx, const s16 Vy, const s16 Vz, u
#undef M
}
static void MulMatVec(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
void GTE::MulMatVec(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
{
#define M(i, j) M_[((i)*3) + (j)]
#define dot3(i) \
@ -509,7 +552,7 @@ static void MulMatVec(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy,
#undef M
}
static void MulMatVecBuggy(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
void GTE::MulMatVecBuggy(const s16* M_, const s32 T[3], const s16 Vx, const s16 Vy, const s16 Vz, u8 shift, bool lm)
{
#define M(i, j) M_[((i)*3) + (j)]
#define dot3(i) \
@ -531,7 +574,7 @@ static void MulMatVecBuggy(const s16* M_, const s32 T[3], const s16 Vx, const s1
#undef M
}
static void Execute_MVMVA(Instruction inst)
void GTE::Execute_MVMVA(Instruction inst)
{
REGS.FLAG.Clear();
@ -576,7 +619,7 @@ static void Execute_MVMVA(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_SQR(Instruction inst)
void GTE::Execute_SQR(Instruction inst)
{
REGS.FLAG.Clear();
@ -594,7 +637,7 @@ static void Execute_SQR(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_OP(Instruction inst)
void GTE::Execute_OP(Instruction inst)
{
REGS.FLAG.Clear();
@ -617,7 +660,7 @@ static void Execute_OP(Instruction inst)
REGS.FLAG.UpdateError();
}
static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
void GTE::RTPS(const s16 V[3], u8 shift, bool lm, bool last)
{
#define dot3(i) \
SignExtendMACResult<i + 1>(SignExtendMACResult<i + 1>((s64(REGS.TR[i]) << 12) + (s64(REGS.RT[i][0]) * s64(V[0]))) + \
@ -763,14 +806,14 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
}
}
static void Execute_RTPS(Instruction inst)
void GTE::Execute_RTPS(Instruction inst)
{
REGS.FLAG.Clear();
RTPS(REGS.V0, inst.GetShift(), inst.lm, true);
REGS.FLAG.UpdateError();
}
static void Execute_RTPT(Instruction inst)
void GTE::Execute_RTPT(Instruction inst)
{
REGS.FLAG.Clear();
@ -784,7 +827,7 @@ static void Execute_RTPT(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_NCLIP(Instruction inst)
void GTE::Execute_NCLIP(Instruction inst)
{
// MAC0 = SX0*SY1 + SX1*SY2 + SX2*SY0 - SX0*SY2 - SX1*SY0 - SX2*SY1
REGS.FLAG.Clear();
@ -797,7 +840,7 @@ static void Execute_NCLIP(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_NCLIP_PGXP(Instruction inst)
void GTE::Execute_NCLIP_PGXP(Instruction inst)
{
if (PGXP::GTE_NCLIP_valid(REGS.dr32[12], REGS.dr32[13], REGS.dr32[14]))
{
@ -810,7 +853,7 @@ static void Execute_NCLIP_PGXP(Instruction inst)
}
}
static void Execute_AVSZ3(Instruction inst)
void GTE::Execute_AVSZ3(Instruction inst)
{
REGS.FLAG.Clear();
@ -821,7 +864,7 @@ static void Execute_AVSZ3(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_AVSZ4(Instruction inst)
void GTE::Execute_AVSZ4(Instruction inst)
{
REGS.FLAG.Clear();
@ -832,7 +875,7 @@ static void Execute_AVSZ4(Instruction inst)
REGS.FLAG.UpdateError();
}
static ALWAYS_INLINE void InterpolateColor(s64 in_MAC1, s64 in_MAC2, s64 in_MAC3, u8 shift, bool lm)
ALWAYS_INLINE void GTE::InterpolateColor(s64 in_MAC1, s64 in_MAC2, s64 in_MAC3, u8 shift, bool lm)
{
// [MAC1,MAC2,MAC3] = MAC+(FC-MAC)*IR0
// [IR1,IR2,IR3] = (([RFC,GFC,BFC] SHL 12) - [MAC1,MAC2,MAC3]) SAR (sf*12)
@ -847,7 +890,7 @@ static ALWAYS_INLINE void InterpolateColor(s64 in_MAC1, s64 in_MAC2, s64 in_MAC3
TruncateAndSetMACAndIR<3>(s64(s32(REGS.IR3) * s32(REGS.IR0)) + in_MAC3, shift, lm);
}
static void NCS(const s16 V[3], u8 shift, bool lm)
void GTE::NCS(const s16 V[3], u8 shift, bool lm)
{
// [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (LLM*V0) SAR (sf*12)
MulMatVec(&REGS.LLM[0][0], V[0], V[1], V[2], shift, lm);
@ -859,7 +902,7 @@ static void NCS(const s16 V[3], u8 shift, bool lm)
PushRGBFromMAC();
}
static void Execute_NCS(Instruction inst)
void GTE::Execute_NCS(Instruction inst)
{
REGS.FLAG.Clear();
@ -868,7 +911,7 @@ static void Execute_NCS(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_NCT(Instruction inst)
void GTE::Execute_NCT(Instruction inst)
{
REGS.FLAG.Clear();
@ -882,7 +925,7 @@ static void Execute_NCT(Instruction inst)
REGS.FLAG.UpdateError();
}
static void NCCS(const s16 V[3], u8 shift, bool lm)
void GTE::NCCS(const s16 V[3], u8 shift, bool lm)
{
// [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (LLM*V0) SAR (sf*12)
MulMatVec(&REGS.LLM[0][0], V[0], V[1], V[2], shift, lm);
@ -900,7 +943,7 @@ static void NCCS(const s16 V[3], u8 shift, bool lm)
PushRGBFromMAC();
}
static void Execute_NCCS(Instruction inst)
void GTE::Execute_NCCS(Instruction inst)
{
REGS.FLAG.Clear();
@ -909,7 +952,7 @@ static void Execute_NCCS(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_NCCT(Instruction inst)
void GTE::Execute_NCCT(Instruction inst)
{
REGS.FLAG.Clear();
@ -923,7 +966,7 @@ static void Execute_NCCT(Instruction inst)
REGS.FLAG.UpdateError();
}
static void NCDS(const s16 V[3], u8 shift, bool lm)
void GTE::NCDS(const s16 V[3], u8 shift, bool lm)
{
// [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (LLM*V0) SAR (sf*12)
MulMatVec(&REGS.LLM[0][0], V[0], V[1], V[2], shift, lm);
@ -944,7 +987,7 @@ static void NCDS(const s16 V[3], u8 shift, bool lm)
PushRGBFromMAC();
}
static void Execute_NCDS(Instruction inst)
void GTE::Execute_NCDS(Instruction inst)
{
REGS.FLAG.Clear();
@ -953,7 +996,7 @@ static void Execute_NCDS(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_NCDT(Instruction inst)
void GTE::Execute_NCDT(Instruction inst)
{
REGS.FLAG.Clear();
@ -967,7 +1010,7 @@ static void Execute_NCDT(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_CC(Instruction inst)
void GTE::Execute_CC(Instruction inst)
{
REGS.FLAG.Clear();
@ -989,7 +1032,7 @@ static void Execute_CC(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_CDP(Instruction inst)
void GTE::Execute_CDP(Instruction inst)
{
REGS.FLAG.Clear();
@ -1015,7 +1058,7 @@ static void Execute_CDP(Instruction inst)
REGS.FLAG.UpdateError();
}
static void DPCS(const u8 color[3], u8 shift, bool lm)
void GTE::DPCS(const u8 color[3], u8 shift, bool lm)
{
// In: [IR1,IR2,IR3]=Vector, FC=Far Color, IR0=Interpolation value, CODE=MSB of RGBC
// [MAC1,MAC2,MAC3] = [R,G,B] SHL 16 ;<--- for DPCS/DPCT
@ -1030,7 +1073,7 @@ static void DPCS(const u8 color[3], u8 shift, bool lm)
PushRGBFromMAC();
}
static void Execute_DPCS(Instruction inst)
void GTE::Execute_DPCS(Instruction inst)
{
REGS.FLAG.Clear();
@ -1039,7 +1082,7 @@ static void Execute_DPCS(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_DPCT(Instruction inst)
void GTE::Execute_DPCT(Instruction inst)
{
REGS.FLAG.Clear();
@ -1052,7 +1095,7 @@ static void Execute_DPCT(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_DCPL(Instruction inst)
void GTE::Execute_DCPL(Instruction inst)
{
REGS.FLAG.Clear();
@ -1074,7 +1117,7 @@ static void Execute_DCPL(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_INTPL(Instruction inst)
void GTE::Execute_INTPL(Instruction inst)
{
REGS.FLAG.Clear();
@ -1092,7 +1135,7 @@ static void Execute_INTPL(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_GPL(Instruction inst)
void GTE::Execute_GPL(Instruction inst)
{
REGS.FLAG.Clear();
@ -1111,7 +1154,7 @@ static void Execute_GPL(Instruction inst)
REGS.FLAG.UpdateError();
}
static void Execute_GPF(Instruction inst)
void GTE::Execute_GPF(Instruction inst)
{
REGS.FLAG.Clear();
@ -1130,7 +1173,7 @@ static void Execute_GPF(Instruction inst)
REGS.FLAG.UpdateError();
}
void ExecuteInstruction(u32 inst_bits)
void GTE::ExecuteInstruction(u32 inst_bits)
{
const Instruction inst{inst_bits};
switch (inst.command)
@ -1256,7 +1299,7 @@ void ExecuteInstruction(u32 inst_bits)
}
}
InstructionImpl GetInstructionImpl(u32 inst_bits, TickCount* ticks)
GTE::InstructionImpl GTE::GetInstructionImpl(u32 inst_bits, TickCount* ticks)
{
const Instruction inst{inst_bits};
switch (inst.command)
@ -1358,5 +1401,3 @@ InstructionImpl GetInstructionImpl(u32 inst_bits, TickCount* ticks)
Panic("Missing handler");
}
}
} // namespace GTE

View file

@ -23,6 +23,8 @@
Log_SetChannel(MDEC);
namespace MDEC {
namespace {
static constexpr u32 DATA_IN_FIFO_SIZE = 1024;
static constexpr u32 DATA_OUT_FIFO_SIZE = 768;
static constexpr u32 NUM_BLOCKS = 6;
@ -89,6 +91,8 @@ union CommandWord
BitField<u32, u16, 0, 16> parameter_word_count;
};
} // namespace
static bool HasPendingBlockCopyOut();
static void SoftReset();

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "memory_card_image.h"
#include "gpu_types.h"
#include "system.h"
#include "util/shiftjis.h"
@ -21,6 +22,7 @@
Log_SetChannel(MemoryCard);
namespace MemoryCardImage {
namespace {
#pragma pack(push, 1)
@ -57,6 +59,8 @@ static_assert(sizeof(TitleFrame) == FRAME_SIZE);
#pragma pack(pop)
} // namespace
static u8 GetChecksum(const u8* frame)
{
u8 checksum = frame[0];
@ -82,24 +86,16 @@ const T* GetFramePtr(const DataArray& data, u32 block, u32 frame)
return reinterpret_cast<const T*>(&data[(block * BLOCK_SIZE) + (frame * FRAME_SIZE)]);
}
static constexpr u32 RGBA5551ToRGBA8888(u16 color)
{
u8 r = Truncate8(color & 31);
u8 g = Truncate8((color >> 5) & 31);
u8 b = Truncate8((color >> 10) & 31);
u8 a = Truncate8((color >> 15) & 1);
static std::optional<u32> GetNextFreeBlock(const DataArray& data);
static bool ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data);
static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data);
static bool ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data);
static bool ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data);
static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd);
static bool ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd);
} // namespace MemoryCardImage
// 00012345 -> 1234545
b = (b << 3) | (b & 0b111);
g = (g << 3) | (g & 0b111);
r = (r << 3) | (r & 0b111);
// a = a ? 255 : 0;
a = (color == 0) ? 0 : 255;
return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24);
}
bool LoadFromFile(DataArray* data, const char* filename)
bool MemoryCardImage::LoadFromFile(DataArray* data, const char* filename)
{
FILESYSTEM_STAT_DATA sd;
if (!FileSystem::StatFile(filename, &sd) || sd.Size != DATA_SIZE)
@ -120,7 +116,7 @@ bool LoadFromFile(DataArray* data, const char* filename)
return true;
}
bool SaveToFile(const DataArray& data, const char* filename)
bool MemoryCardImage::SaveToFile(const DataArray& data, const char* filename)
{
std::unique_ptr<ByteStream> stream =
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE |
@ -142,14 +138,14 @@ bool SaveToFile(const DataArray& data, const char* filename)
return true;
}
bool IsValid(const DataArray& data)
bool MemoryCardImage::IsValid(const DataArray& data)
{
// TODO: Check checksum?
const u8* fptr = GetFramePtr<u8>(data, 0, 0);
return fptr[0] == 'M' && fptr[1] == 'C';
}
void Format(DataArray* data)
void MemoryCardImage::Format(DataArray* data)
{
// fill everything with FF
data->fill(u8(0xFF));
@ -206,7 +202,7 @@ void Format(DataArray* data)
std::memcpy(GetFramePtr<u8>(data, 0, 63), GetFramePtr<u8>(data, 0, 0), FRAME_SIZE);
}
static std::optional<u32> GetNextFreeBlock(const DataArray& data)
std::optional<u32> MemoryCardImage::GetNextFreeBlock(const DataArray& data)
{
for (u32 dir_frame = 1; dir_frame < FRAMES_PER_BLOCK; dir_frame++)
{
@ -218,7 +214,7 @@ static std::optional<u32> GetNextFreeBlock(const DataArray& data)
return std::nullopt;
}
u32 GetFreeBlockCount(const DataArray& data)
u32 MemoryCardImage::GetFreeBlockCount(const DataArray& data)
{
u32 count = 0;
for (u32 dir_frame = 1; dir_frame < FRAMES_PER_BLOCK; dir_frame++)
@ -231,7 +227,7 @@ u32 GetFreeBlockCount(const DataArray& data)
return count;
}
std::vector<FileInfo> EnumerateFiles(const DataArray& data, bool include_deleted)
std::vector<MemoryCardImage::FileInfo> MemoryCardImage::EnumerateFiles(const DataArray& data, bool include_deleted)
{
std::vector<FileInfo> files;
@ -299,8 +295,8 @@ std::vector<FileInfo> EnumerateFiles(const DataArray& data, bool include_deleted
u32* pixels_ptr = fi.icon_frames[icon_frame].pixels;
for (u32 i = 0; i < ICON_WIDTH * ICON_HEIGHT; i += 2)
{
*(pixels_ptr++) = RGBA5551ToRGBA8888(tf->icon_palette[*indices_ptr & 0xF]);
*(pixels_ptr++) = RGBA5551ToRGBA8888(tf->icon_palette[*indices_ptr >> 4]);
*(pixels_ptr++) = VRAMRGBA5551ToRGBA8888(tf->icon_palette[*indices_ptr & 0xF]);
*(pixels_ptr++) = VRAMRGBA5551ToRGBA8888(tf->icon_palette[*indices_ptr >> 4]);
indices_ptr++;
}
}
@ -311,7 +307,7 @@ std::vector<FileInfo> EnumerateFiles(const DataArray& data, bool include_deleted
return files;
}
bool ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer)
bool MemoryCardImage::ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer)
{
buffer->resize(fi.num_blocks * BLOCK_SIZE);
@ -328,7 +324,7 @@ bool ReadFile(const DataArray& data, const FileInfo& fi, std::vector<u8>* buffer
return true;
}
bool WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer)
bool MemoryCardImage::WriteFile(DataArray* data, const std::string_view& filename, const std::vector<u8>& buffer)
{
if (buffer.empty())
{
@ -386,7 +382,7 @@ bool WriteFile(DataArray* data, const std::string_view& filename, const std::vec
return true;
}
bool DeleteFile(DataArray* data, const FileInfo& fi, bool clear_sectors)
bool MemoryCardImage::DeleteFile(DataArray* data, const FileInfo& fi, bool clear_sectors)
{
Log_InfoFmt("Deleting '{}' from memory card ({} blocks)", fi.filename, fi.num_blocks);
@ -417,7 +413,7 @@ bool DeleteFile(DataArray* data, const FileInfo& fi, bool clear_sectors)
return true;
}
bool UndeleteFile(DataArray* data, const FileInfo& fi)
bool MemoryCardImage::UndeleteFile(DataArray* data, const FileInfo& fi)
{
if (!fi.deleted)
{
@ -483,7 +479,7 @@ bool UndeleteFile(DataArray* data, const FileInfo& fi)
return true;
}
static bool ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data)
bool MemoryCardImage::ImportCardMCD(DataArray* data, const char* filename, std::vector<u8> file_data)
{
if (file_data.size() != DATA_SIZE)
{
@ -495,7 +491,7 @@ static bool ImportCardMCD(DataArray* data, const char* filename, std::vector<u8>
return true;
}
static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data)
bool MemoryCardImage::ImportCardGME(DataArray* data, const char* filename, std::vector<u8> file_data)
{
#pragma pack(push, 1)
struct GMEHeader
@ -522,7 +518,7 @@ static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8>
if (file_data.size() < expected_size)
{
Log_WarningFmt("GME memory card '{}' is too small (got {} expected {}), padding with zeroes", filename,
file_data.size(), expected_size);
file_data.size(), expected_size);
file_data.resize(expected_size);
}
@ -531,7 +527,7 @@ static bool ImportCardGME(DataArray* data, const char* filename, std::vector<u8>
return true;
}
static bool ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data)
bool MemoryCardImage::ImportCardVGS(DataArray* data, const char* filename, std::vector<u8> file_data)
{
constexpr u32 HEADER_SIZE = 64;
@ -552,7 +548,7 @@ static bool ImportCardVGS(DataArray* data, const char* filename, std::vector<u8>
return true;
}
static bool ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data)
bool MemoryCardImage::ImportCardPSX(DataArray* data, const char* filename, std::vector<u8> file_data)
{
constexpr u32 HEADER_SIZE = 256;
@ -573,7 +569,7 @@ static bool ImportCardPSX(DataArray* data, const char* filename, std::vector<u8>
return true;
}
bool ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data)
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data)
{
const char* extension = std::strrchr(filename, '.');
if (!extension)
@ -608,7 +604,7 @@ bool ImportCard(DataArray* data, const char* filename, std::vector<u8> file_data
}
}
bool ImportCard(DataArray* data, const char* filename)
bool MemoryCardImage::ImportCard(DataArray* data, const char* filename)
{
std::optional<std::vector<u8>> file_data = FileSystem::ReadBinaryFile(filename);
if (!file_data.has_value())
@ -617,7 +613,7 @@ bool ImportCard(DataArray* data, const char* filename)
return ImportCard(data, filename, std::move(file_data.value()));
}
bool ExportSave(DataArray* data, const FileInfo& fi, const char* filename)
bool MemoryCardImage::ExportSave(DataArray* data, const FileInfo& fi, const char* filename)
{
std::unique_ptr<ByteStream> stream =
ByteStream::OpenFile(filename, BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_TRUNCATE | BYTESTREAM_OPEN_WRITE |
@ -650,7 +646,8 @@ bool ExportSave(DataArray* data, const FileInfo& fi, const char* filename)
return true;
}
static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd)
bool MemoryCardImage::ImportSaveWithDirectoryFrame(DataArray* data, const char* filename,
const FILESYSTEM_STAT_DATA& sd)
{
// Make sure the size of the actual file is valid
if (sd.Size <= FRAME_SIZE || (sd.Size - FRAME_SIZE) % BLOCK_SIZE != 0u || (sd.Size - FRAME_SIZE) / BLOCK_SIZE > 15u)
@ -713,7 +710,7 @@ static bool ImportSaveWithDirectoryFrame(DataArray* data, const char* filename,
return WriteFile(data, df.filename, blocks);
}
static bool ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd)
bool MemoryCardImage::ImportRawSave(DataArray* data, const char* filename, const FILESYSTEM_STAT_DATA& sd)
{
const std::string display_name(FileSystem::GetDisplayNameFromPath(filename));
std::string save_name(Path::GetFileTitle(filename));
@ -759,7 +756,7 @@ static bool ImportRawSave(DataArray* data, const char* filename, const FILESYSTE
return WriteFile(data, save_name, blocks.value());
}
bool ImportSave(DataArray* data, const char* filename)
bool MemoryCardImage::ImportSave(DataArray* data, const char* filename)
{
FILESYSTEM_STAT_DATA sd;
if (!FileSystem::StatFile(filename, &sd))
@ -789,5 +786,3 @@ bool ImportSave(DataArray* data, const char* filename)
return false;
}
}
} // namespace MemoryCardImage

View file

@ -14,6 +14,7 @@
Log_SetChannel(PGXP);
namespace PGXP {
namespace {
enum : u32
{
@ -71,8 +72,13 @@ typedef union
u32 d;
s32 sd;
} psx_value;
} // namespace
static void PGXP_CacheVertex(s16 sx, s16 sy, const PGXP_value& vertex);
static PGXP_value* PGXP_GetCachedVertex(short sx, short sy);
static float TruncateVertexPosition(float p);
static bool IsWithinTolerance(float precise_x, float precise_y, int int_x, int int_y);
static void MakeValid(PGXP_value* pV, u32 psxV);
static void Validate(PGXP_value* pV, u32 psxV);
@ -85,6 +91,9 @@ static double f16Overflow(double in);
static PGXP_value* GetPtr(u32 addr);
static PGXP_value* ReadMem(u32 addr);
static void PGXP_MTC2_int(const PGXP_value& value, u32 reg);
static void CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal);
static const PGXP_value PGXP_value_invalid = {0.f, 0.f, 0.f, {0}, 0};
static const PGXP_value PGXP_value_zero = {0.f, 0.f, 0.f, {VALID_ALL}, 0};
@ -254,7 +263,9 @@ ALWAYS_INLINE_RELEASE static void WriteMem16(const PGXP_value* src, u32 addr)
}
}
void Initialize()
} // namespace PGXP
void PGXP::Initialize()
{
std::memset(CPU_reg, 0, sizeof(CPU_reg));
std::memset(CP0_reg, 0, sizeof(CP0_reg));
@ -285,7 +296,7 @@ void Initialize()
std::memset(vertexCache, 0, sizeof(PGXP_value) * VERTEX_CACHE_SIZE);
}
void Reset()
void PGXP::Reset()
{
std::memset(CPU_reg, 0, sizeof(CPU_reg));
std::memset(CP0_reg, 0, sizeof(CP0_reg));
@ -299,7 +310,7 @@ void Reset()
std::memset(vertexCache, 0, sizeof(PGXP_value) * VERTEX_CACHE_SIZE);
}
void Shutdown()
void PGXP::Shutdown()
{
if (vertexCache)
{
@ -340,7 +351,7 @@ void Shutdown()
#define SXY2 (GTE_regs[14])
#define SXYP (GTE_regs[15])
void GTE_PushSXYZ2f(float x, float y, float z, u32 v)
void PGXP::GTE_PushSXYZ2f(float x, float y, float z, u32 v)
{
// push values down FIFO
SXY0 = SXY1;
@ -360,7 +371,7 @@ void GTE_PushSXYZ2f(float x, float y, float z, u32 v)
#define VY(n) (psxRegs.CP2D.p[n << 1].sw.h)
#define VZ(n) (psxRegs.CP2D.p[(n << 1) + 1].sw.l)
int GTE_NCLIP_valid(u32 sxy0, u32 sxy1, u32 sxy2)
int PGXP::GTE_NCLIP_valid(u32 sxy0, u32 sxy1, u32 sxy2)
{
Validate(&SXY0, sxy0);
Validate(&SXY1, sxy1);
@ -370,7 +381,7 @@ int GTE_NCLIP_valid(u32 sxy0, u32 sxy1, u32 sxy2)
return 0;
}
float GTE_NCLIP()
float PGXP::GTE_NCLIP()
{
float nclip = ((SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1));
@ -395,7 +406,7 @@ float GTE_NCLIP()
return nclip;
}
static void PGXP_MTC2_int(PGXP_value value, u32 reg)
ALWAYS_INLINE_RELEASE void PGXP::PGXP_MTC2_int(const PGXP_value& value, u32 reg)
{
switch (reg)
{
@ -418,7 +429,7 @@ static void PGXP_MTC2_int(PGXP_value value, u32 reg)
// Data transfer tracking
////////////////////////////////////
void CPU_MFC2(u32 instr, u32 rdVal)
void PGXP::CPU_MFC2(u32 instr, u32 rdVal)
{
// CPU[Rt] = GTE_D[Rd]
const u32 idx = cop2idx(instr);
@ -427,7 +438,7 @@ void CPU_MFC2(u32 instr, u32 rdVal)
CPU_reg[rt(instr)].value = rdVal;
}
void CPU_MTC2(u32 instr, u32 rtVal)
void PGXP::CPU_MTC2(u32 instr, u32 rtVal)
{
// GTE_D[Rd] = CPU[Rt]
const u32 idx = cop2idx(instr);
@ -439,7 +450,7 @@ void CPU_MTC2(u32 instr, u32 rtVal)
////////////////////////////////////
// Memory Access
////////////////////////////////////
void CPU_LWC2(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_LWC2(u32 instr, u32 addr, u32 rtVal)
{
// GTE_D[Rt] = Mem[addr]
PGXP_value val;
@ -447,14 +458,14 @@ void CPU_LWC2(u32 instr, u32 addr, u32 rtVal)
PGXP_MTC2_int(val, rt(instr));
}
void CPU_SWC2(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_SWC2(u32 instr, u32 addr, u32 rtVal)
{
// Mem[addr] = GTE_D[Rt]
Validate(&GTE_regs[rt(instr)], rtVal);
WriteMem(&GTE_regs[rt(instr)], addr);
}
ALWAYS_INLINE_RELEASE void PGXP_CacheVertex(s16 sx, s16 sy, const PGXP_value& vertex)
ALWAYS_INLINE_RELEASE void PGXP::PGXP_CacheVertex(s16 sx, s16 sy, const PGXP_value& vertex)
{
if (sx >= -0x800 && sx <= 0x7ff && sy >= -0x800 && sy <= 0x7ff)
{
@ -463,7 +474,7 @@ ALWAYS_INLINE_RELEASE void PGXP_CacheVertex(s16 sx, s16 sy, const PGXP_value& ve
}
}
static ALWAYS_INLINE_RELEASE PGXP_value* PGXP_GetCachedVertex(short sx, short sy)
ALWAYS_INLINE_RELEASE PGXP::PGXP_value* PGXP::PGXP_GetCachedVertex(short sx, short sy)
{
if (sx >= -0x800 && sx <= 0x7ff && sy >= -0x800 && sy <= 0x7ff)
{
@ -474,14 +485,14 @@ static ALWAYS_INLINE_RELEASE PGXP_value* PGXP_GetCachedVertex(short sx, short sy
return nullptr;
}
static ALWAYS_INLINE_RELEASE float TruncateVertexPosition(float p)
ALWAYS_INLINE_RELEASE float PGXP::TruncateVertexPosition(float p)
{
const s32 int_part = static_cast<s32>(p);
const float int_part_f = static_cast<float>(int_part);
return static_cast<float>(static_cast<s16>(int_part << 5) >> 5) + (p - int_part_f);
}
static ALWAYS_INLINE_RELEASE bool IsWithinTolerance(float precise_x, float precise_y, int int_x, int int_y)
ALWAYS_INLINE_RELEASE bool PGXP::IsWithinTolerance(float precise_x, float precise_y, int int_x, int int_y)
{
const float tolerance = g_settings.gpu_pgxp_tolerance;
if (tolerance < 0.0f)
@ -491,7 +502,8 @@ static ALWAYS_INLINE_RELEASE bool IsWithinTolerance(float precise_x, float preci
std::abs(precise_y - static_cast<float>(int_y)) <= tolerance);
}
bool GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, float* out_x, float* out_y, float* out_w)
bool PGXP::GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, float* out_x, float* out_y,
float* out_w)
{
const PGXP_value* vert = ReadMem(addr);
if (vert && ((vert->flags & VALID_01) == VALID_01) && (vert->value == value))
@ -544,35 +556,35 @@ bool GetPreciseVertex(u32 addr, u32 value, int x, int y, int xOffs, int yOffs, f
#define imm_sext(_instr) \
static_cast<s32>(static_cast<s16>(_instr & 0xFFFF)) // The immediate part of the instruction register
void CPU_LW(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_LW(u32 instr, u32 addr, u32 rtVal)
{
// Rt = Mem[Rs + Im]
ValidateAndCopyMem(&CPU_reg[rt(instr)], addr, rtVal);
}
void CPU_LBx(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_LBx(u32 instr, u32 addr, u32 rtVal)
{
CPU_reg[rt(instr)] = PGXP_value_invalid;
}
void CPU_LH(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_LH(u32 instr, u32 addr, u32 rtVal)
{
// Rt = Mem[Rs + Im] (sign extended)
ValidateAndCopyMem16(&CPU_reg[rt(instr)], addr, rtVal, true);
}
void CPU_LHU(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_LHU(u32 instr, u32 addr, u32 rtVal)
{
// Rt = Mem[Rs + Im] (zero extended)
ValidateAndCopyMem16(&CPU_reg[rt(instr)], addr, rtVal, false);
}
void CPU_SB(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_SB(u32 instr, u32 addr, u32 rtVal)
{
WriteMem(&PGXP_value_invalid, addr);
}
void CPU_SH(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_SH(u32 instr, u32 addr, u32 rtVal)
{
PGXP_value* val = &CPU_reg[rt(instr)];
@ -581,7 +593,7 @@ void CPU_SH(u32 instr, u32 addr, u32 rtVal)
WriteMem16(val, addr);
}
void CPU_SW(u32 instr, u32 addr, u32 rtVal)
void PGXP::CPU_SW(u32 instr, u32 addr, u32 rtVal)
{
// Mem[Rs + Im] = Rt
PGXP_value* val = &CPU_reg[rt(instr)];
@ -589,14 +601,14 @@ void CPU_SW(u32 instr, u32 addr, u32 rtVal)
WriteMem(val, addr);
}
void CPU_MOVE(u32 rd_and_rs, u32 rsVal)
void PGXP::CPU_MOVE(u32 rd_and_rs, u32 rsVal)
{
const u32 Rs = (rd_and_rs & 0xFFu);
Validate(&CPU_reg[Rs], rsVal);
CPU_reg[(rd_and_rs >> 8)] = CPU_reg[Rs];
}
void CPU_ADDI(u32 instr, u32 rsVal)
void PGXP::CPU_ADDI(u32 instr, u32 rsVal)
{
// Rt = Rs + Imm (signed)
Validate(&CPU_reg[rs(instr)], rsVal);
@ -624,7 +636,7 @@ void CPU_ADDI(u32 instr, u32 rsVal)
CPU_reg[rt(instr)].value = rsVal + imm_sext(instr);
}
void CPU_ANDI(u32 instr, u32 rsVal)
void PGXP::CPU_ANDI(u32 instr, u32 rsVal)
{
// Rt = Rs & Imm
const u32 rtVal = rsVal & imm(instr);
@ -659,7 +671,7 @@ void CPU_ANDI(u32 instr, u32 rsVal)
CPU_reg[rt(instr)].value = rtVal;
}
void CPU_ORI(u32 instr, u32 rsVal)
void PGXP::CPU_ORI(u32 instr, u32 rsVal)
{
// Rt = Rs | Imm
const u32 rtVal = rsVal | imm(instr);
@ -686,7 +698,7 @@ void CPU_ORI(u32 instr, u32 rsVal)
CPU_reg[rt(instr)] = ret;
}
void CPU_XORI(u32 instr, u32 rsVal)
void PGXP::CPU_XORI(u32 instr, u32 rsVal)
{
// Rt = Rs ^ Imm
const u32 rtVal = rsVal ^ imm(instr);
@ -713,7 +725,7 @@ void CPU_XORI(u32 instr, u32 rsVal)
CPU_reg[rt(instr)] = ret;
}
void CPU_SLTI(u32 instr, u32 rsVal)
void PGXP::CPU_SLTI(u32 instr, u32 rsVal)
{
// Rt = Rs < Imm (signed)
psx_value tempImm;
@ -731,7 +743,7 @@ void CPU_SLTI(u32 instr, u32 rsVal)
CPU_reg[rt(instr)] = ret;
}
void CPU_SLTIU(u32 instr, u32 rsVal)
void PGXP::CPU_SLTIU(u32 instr, u32 rsVal)
{
// Rt = Rs < Imm (Unsigned)
psx_value tempImm;
@ -752,7 +764,7 @@ void CPU_SLTIU(u32 instr, u32 rsVal)
////////////////////////////////////
// Load Upper
////////////////////////////////////
void CPU_LUI(u32 instr)
void PGXP::CPU_LUI(u32 instr)
{
// Rt = Imm << 16
CPU_reg[rt(instr)] = PGXP_value_zero;
@ -765,7 +777,7 @@ void CPU_LUI(u32 instr)
// Register Arithmetic
////////////////////////////////////
void CPU_ADD(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_ADD(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs + Rt (signed)
PGXP_value ret;
@ -813,7 +825,7 @@ void CPU_ADD(u32 instr, u32 rsVal, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SUB(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_SUB(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs - Rt (signed)
PGXP_value ret;
@ -848,7 +860,7 @@ void CPU_SUB(u32 instr, u32 rsVal, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
static void CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal)
ALWAYS_INLINE_RELEASE void PGXP::CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal)
{
// Rd = Rs & Rt
psx_value vald, vals, valt;
@ -937,35 +949,35 @@ static void CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_AND_(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_AND_(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs & Rt
const u32 rdVal = rsVal & rtVal;
CPU_BITWISE(instr, rdVal, rsVal, rtVal);
}
void CPU_OR_(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_OR_(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs | Rt
const u32 rdVal = rsVal | rtVal;
CPU_BITWISE(instr, rdVal, rsVal, rtVal);
}
void CPU_XOR_(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_XOR_(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs ^ Rt
const u32 rdVal = rsVal ^ rtVal;
CPU_BITWISE(instr, rdVal, rsVal, rtVal);
}
void CPU_NOR(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_NOR(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs NOR Rt
const u32 rdVal = ~(rsVal | rtVal);
CPU_BITWISE(instr, rdVal, rsVal, rtVal);
}
void CPU_SLT(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_SLT(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs < Rt (signed)
PGXP_value ret;
@ -991,7 +1003,7 @@ void CPU_SLT(u32 instr, u32 rsVal, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SLTU(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_SLTU(u32 instr, u32 rsVal, u32 rtVal)
{
// Rd = Rs < Rt (unsigned)
PGXP_value ret;
@ -1021,7 +1033,7 @@ void CPU_SLTU(u32 instr, u32 rsVal, u32 rtVal)
// Register mult/div
////////////////////////////////////
void CPU_MULT(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_MULT(u32 instr, u32 rsVal, u32 rtVal)
{
// Hi/Lo = Rs * Rt (signed)
Validate(&CPU_reg[rs(instr)], rsVal);
@ -1069,7 +1081,7 @@ void CPU_MULT(u32 instr, u32 rsVal, u32 rtVal)
CPU_Lo.value = Truncate32(result);
}
void CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
{
// Hi/Lo = Rs * Rt (unsigned)
Validate(&CPU_reg[rs(instr)], rsVal);
@ -1117,7 +1129,7 @@ void CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
CPU_Lo.value = Truncate32(result);
}
void CPU_DIV(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_DIV(u32 instr, u32 rsVal, u32 rtVal)
{
// Lo = Rs / Rt (signed)
// Hi = Rs % Rt (signed)
@ -1166,7 +1178,7 @@ void CPU_DIV(u32 instr, u32 rsVal, u32 rtVal)
}
}
void CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal)
void PGXP::CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal)
{
// Lo = Rs / Rt (unsigned)
// Hi = Rs % Rt (unsigned)
@ -1211,7 +1223,7 @@ void CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal)
////////////////////////////////////
// Shift operations (sa)
////////////////////////////////////
void CPU_SLL(u32 instr, u32 rtVal)
void PGXP::CPU_SLL(u32 instr, u32 rtVal)
{
// Rd = Rt << Sa
const u32 rdVal = rtVal << sa(instr);
@ -1256,7 +1268,7 @@ void CPU_SLL(u32 instr, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SRL(u32 instr, u32 rtVal)
void PGXP::CPU_SRL(u32 instr, u32 rtVal)
{
// Rd = Rt >> Sa
const u32 rdVal = rtVal >> sa(instr);
@ -1320,7 +1332,7 @@ void CPU_SRL(u32 instr, u32 rtVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SRA(u32 instr, u32 rtVal)
void PGXP::CPU_SRA(u32 instr, u32 rtVal)
{
// Rd = Rt >> Sa
const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> sa(instr));
@ -1386,7 +1398,7 @@ void CPU_SRA(u32 instr, u32 rtVal)
////////////////////////////////////
// Shift operations variable
////////////////////////////////////
void CPU_SLLV(u32 instr, u32 rtVal, u32 rsVal)
void PGXP::CPU_SLLV(u32 instr, u32 rtVal, u32 rsVal)
{
// Rd = Rt << Rs
const u32 rdVal = rtVal << rsVal;
@ -1431,7 +1443,7 @@ void CPU_SLLV(u32 instr, u32 rtVal, u32 rsVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SRLV(u32 instr, u32 rtVal, u32 rsVal)
void PGXP::CPU_SRLV(u32 instr, u32 rtVal, u32 rsVal)
{
// Rd = Rt >> Sa
const u32 rdVal = rtVal >> rsVal;
@ -1496,7 +1508,7 @@ void CPU_SRLV(u32 instr, u32 rtVal, u32 rsVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal)
void PGXP::CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal)
{
// Rd = Rt >> Sa
const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> rsVal);
@ -1561,7 +1573,7 @@ void CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal)
CPU_reg[rd(instr)] = ret;
}
void CPU_MFHI(u32 instr, u32 hiVal)
void PGXP::CPU_MFHI(u32 instr, u32 hiVal)
{
// Rd = Hi
Validate(&CPU_Hi, hiVal);
@ -1569,7 +1581,7 @@ void CPU_MFHI(u32 instr, u32 hiVal)
CPU_reg[rd(instr)] = CPU_Hi;
}
void CPU_MTHI(u32 instr, u32 rsVal)
void PGXP::CPU_MTHI(u32 instr, u32 rsVal)
{
// Hi = Rd
Validate(&CPU_reg[rs(instr)], rsVal);
@ -1577,7 +1589,7 @@ void CPU_MTHI(u32 instr, u32 rsVal)
CPU_Hi = CPU_reg[rd(instr)];
}
void CPU_MFLO(u32 instr, u32 loVal)
void PGXP::CPU_MFLO(u32 instr, u32 loVal)
{
// Rd = Lo
Validate(&CPU_Lo, loVal);
@ -1585,7 +1597,7 @@ void CPU_MFLO(u32 instr, u32 loVal)
CPU_reg[rd(instr)] = CPU_Lo;
}
void CPU_MTLO(u32 instr, u32 rsVal)
void PGXP::CPU_MTLO(u32 instr, u32 rsVal)
{
// Lo = Rd
Validate(&CPU_reg[rs(instr)], rsVal);
@ -1593,7 +1605,7 @@ void CPU_MTLO(u32 instr, u32 rsVal)
CPU_Lo = CPU_reg[rd(instr)];
}
void CPU_MFC0(u32 instr, u32 rdVal)
void PGXP::CPU_MFC0(u32 instr, u32 rdVal)
{
// CPU[Rt] = CP0[Rd]
Validate(&CP0_reg[rd(instr)], rdVal);
@ -1601,12 +1613,10 @@ void CPU_MFC0(u32 instr, u32 rdVal)
CPU_reg[rt(instr)].value = rdVal;
}
void CPU_MTC0(u32 instr, u32 rdVal, u32 rtVal)
void PGXP::CPU_MTC0(u32 instr, u32 rdVal, u32 rtVal)
{
// CP0[Rd] = CPU[Rt]
Validate(&CPU_reg[rt(instr)], rtVal);
CP0_reg[rd(instr)] = CPU_reg[rt(instr)];
CP0_reg[rd(instr)].value = rdVal;
}
} // namespace PGXP

View file

@ -19,6 +19,7 @@
Log_SetChannel(SIO);
namespace SIO {
namespace {
union SIO_CTRL
{
@ -64,6 +65,7 @@ union SIO_MODE
BitField<u16, u8, 5, 1> parity_type;
BitField<u16, u8, 6, 2> stop_bit_length;
};
} // namespace
static void SoftReset();
@ -79,7 +81,9 @@ void SIO::Initialize()
Reset();
}
void SIO::Shutdown() {}
void SIO::Shutdown()
{
}
void SIO::Reset()
{

View file

@ -38,6 +38,8 @@ ALWAYS_INLINE static constexpr s32 ApplyVolume(s32 sample, s16 volume)
}
namespace SPU {
namespace {
enum : u32
{
SPU_BASE = 0x1F801C00,
@ -307,6 +309,7 @@ struct ReverbRegisters
u16 rev[NUM_REVERB_REGS];
};
};
} // namespace
static ADSRPhase GetNextADSRPhase(ADSRPhase phase);
@ -350,7 +353,7 @@ static void CreateOutputStream();
static std::unique_ptr<TimingEvent> s_tick_event;
static std::unique_ptr<TimingEvent> s_transfer_event;
static std::unique_ptr<Common::WAVWriter> s_dump_writer;
static std::unique_ptr<WAVWriter> s_dump_writer;
static std::unique_ptr<AudioStream> s_audio_stream;
static std::unique_ptr<AudioStream> s_null_audio_stream;
static bool s_audio_output_muted = false;
@ -405,7 +408,7 @@ static std::array<u8, RAM_SIZE> s_ram{};
#ifdef SPU_DUMP_ALL_VOICES
// +1 for reverb output
static std::array<std::unique_ptr<Common::WAVWriter>, NUM_VOICES + 1> s_voice_dump_writers;
static std::array<std::unique_ptr<WAVWriter>, NUM_VOICES + 1> s_voice_dump_writers;
#endif
} // namespace SPU
@ -1479,7 +1482,7 @@ bool SPU::IsDumpingAudio()
bool SPU::StartDumpingAudio(const char* filename)
{
s_dump_writer.reset();
s_dump_writer = std::make_unique<Common::WAVWriter>();
s_dump_writer = std::make_unique<WAVWriter>();
if (!s_dump_writer->Open(filename, SAMPLE_RATE, 2))
{
Log_ErrorPrintf("Failed to open '%s'", filename);
@ -1491,13 +1494,13 @@ bool SPU::StartDumpingAudio(const char* filename)
for (size_t i = 0; i < s_voice_dump_writers.size(); i++)
{
s_voice_dump_writers[i].reset();
s_voice_dump_writers[i] = std::make_unique<Common::WAVWriter>();
s_voice_dump_writers[i] = std::make_unique<WAVWriter>();
TinyString new_suffix;
if (i == NUM_VOICES)
new_suffix.Assign("reverb.wav");
new_suffix.assign("reverb.wav");
else
new_suffix.Format("voice%u.wav", i);
new_suffix.fmt("voice{}.wav", i);
const std::string voice_filename = Path::ReplaceExtension(filename, new_suffix);
if (!s_voice_dump_writers[i]->Open(voice_filename.c_str(), SAMPLE_RATE, 2))

View file

@ -21,6 +21,8 @@
Log_SetChannel(Timers);
namespace Timers {
namespace {
static constexpr u32 NUM_TIMERS = 3;
enum class SyncMode : u8
@ -60,6 +62,8 @@ struct CounterState
bool irq_done;
};
} // namespace
static void UpdateCountingEnabled(CounterState& cs);
static void CheckForIRQ(u32 index, u32 old_counter);
static void UpdateIRQ(u32 index);

View file

@ -77,7 +77,6 @@ target_link_libraries(util PRIVATE stb libchdr zlib soundtouch Zstd::Zstd reshad
if(ENABLE_CUBEB)
target_sources(util PRIVATE
cubeb_audio_stream.cpp
cubeb_audio_stream.h
)
target_compile_definitions(util PUBLIC "ENABLE_CUBEB=1")
target_link_libraries(util PRIVATE cubeb)
@ -242,7 +241,6 @@ if(WIN32)
win32_raw_input_source.cpp
win32_raw_input_source.h
xaudio2_audio_stream.cpp
xaudio2_audio_stream.h
xinput_source.cpp
xinput_source.h
)

View file

@ -1,14 +1,19 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include <cerrno>
Log_SetChannel(CDImageBin);
namespace {
class CDImageBin : public CDImage
{
public:
@ -30,6 +35,8 @@ private:
CDSubChannelReplacement m_sbi;
};
} // namespace
CDImageBin::CDImageBin() = default;
CDImageBin::~CDImageBin()

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
@ -29,6 +29,8 @@
Log_SetChannel(CDImageCHD);
namespace {
static std::optional<CDImage::TrackMode> ParseTrackModeString(const char* str)
{
if (std::strncmp(str, "MODE2_FORM_MIX", 14) == 0)
@ -54,7 +56,6 @@ static std::optional<CDImage::TrackMode> ParseTrackModeString(const char* str)
static std::vector<std::pair<std::string, chd_header>> s_chd_hash_cache; // <filename, header>
static std::recursive_mutex s_chd_hash_cache_mutex;
namespace {
class CDImageCHD : public CDImage
{
public:

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
@ -20,6 +20,8 @@
Log_SetChannel(CDImageCueSheet);
namespace {
class CDImageCueSheet : public CDImage
{
public:
@ -46,6 +48,8 @@ private:
CDSubChannelReplacement m_sbi;
};
} // namespace
CDImageCueSheet::CDImageCueSheet() = default;
CDImageCueSheet::~CDImageCueSheet()

View file

@ -1,15 +1,18 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "assert.h"
#include "cd_image.h"
#include "common/error.h"
#include "common/log.h"
#include "common/string_util.h"
#include <algorithm>
#include <cerrno>
#include <cinttypes>
#include <cmath>
Log_SetChannel(CDImageDevice);
#if defined(_WIN32)
@ -36,6 +39,8 @@ static void U16ToBE(u8* beval, u16 leval)
beval[1] = static_cast<u8>(leval);
}
namespace {
class CDImageDeviceWin32 : public CDImage
{
public:
@ -74,6 +79,8 @@ private:
std::array<u8, SUBCHANNEL_BYTES_PER_FRAME> m_subq;
};
} // namespace
CDImageDeviceWin32::CDImageDeviceWin32() = default;
CDImageDeviceWin32::~CDImageDeviceWin32()

View file

@ -158,6 +158,8 @@ static void eccedc_generate(u8* sector, int type)
}
}
namespace {
class CDImageEcm : public CDImage
{
public:
@ -216,6 +218,8 @@ private:
CDSubChannelReplacement m_sbi;
};
} // namespace
CDImageEcm::CDImageEcm() = default;
CDImageEcm::~CDImageEcm()

View file

@ -1,14 +1,21 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image_hasher.h"
#include "cd_image.h"
#include "common/md5_digest.h"
#include "common/string_util.h"
namespace CDImageHasher {
static bool ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest, ProgressCallback* progress_callback)
static bool ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest, ProgressCallback* progress_callback);
static bool ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallback* progress_callback);
} // namespace CDImageHasher
bool CDImageHasher::ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest,
ProgressCallback* progress_callback)
{
const CDImage::LBA index_start = image->GetTrackIndexPosition(track, index);
const u32 index_length = image->GetTrackIndexLength(track, index);
@ -43,7 +50,7 @@ static bool ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest, Pro
return true;
}
static bool ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallback* progress_callback)
bool CDImageHasher::ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallback* progress_callback)
{
static constexpr u8 INDICES_TO_READ = 2;
@ -78,14 +85,14 @@ static bool ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallb
return true;
}
std::string HashToString(const Hash& hash)
std::string CDImageHasher::HashToString(const Hash& hash)
{
return fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
hash[11], hash[12], hash[13], hash[14], hash[15]);
}
std::optional<Hash> HashFromString(const std::string_view& str)
std::optional<CDImageHasher::Hash> CDImageHasher::HashFromString(const std::string_view& str)
{
auto decoded = StringUtil::DecodeHex(str);
if (decoded && decoded->size() == std::tuple_size_v<Hash>)
@ -97,8 +104,8 @@ std::optional<Hash> HashFromString(const std::string_view& str)
return std::nullopt;
}
bool GetImageHash(CDImage* image, Hash* out_hash,
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
bool CDImageHasher::GetImageHash(CDImage* image, Hash* out_hash,
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
{
MD5Digest digest;
@ -121,8 +128,8 @@ bool GetImageHash(CDImage* image, Hash* out_hash,
return true;
}
bool GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
bool CDImageHasher::GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
{
MD5Digest digest;
if (!ReadTrack(image, track, &digest, progress_callback))
@ -131,5 +138,3 @@ bool GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
digest.Final(out_hash->data());
return true;
}
} // namespace CDImageHasher

View file

@ -1,19 +1,24 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include <algorithm>
#include <cerrno>
#include <map>
#include <sstream>
Log_SetChannel(CDImageMemory);
namespace {
class CDImageM3u : public CDImage
{
public:
@ -48,6 +53,8 @@ private:
bool m_apply_patches = false;
};
} // namespace
CDImageM3u::CDImageM3u() = default;
CDImageM3u::~CDImageM3u() = default;

View file

@ -1,18 +1,23 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "assert.h"
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include <algorithm>
#include <cerrno>
#include <map>
Log_SetChannel(CDImageMds);
namespace {
#pragma pack(push, 1)
struct TrackEntry
{
@ -53,6 +58,8 @@ private:
CDSubChannelReplacement m_sbi;
};
} // namespace
CDImageMds::CDImageMds() = default;
CDImageMds::~CDImageMds()
@ -112,7 +119,8 @@ bool CDImageMds::OpenAndParse(const char* filename, Error* error)
if (track_count > 99 || track_offset >= mds.size())
{
Log_ErrorPrintf("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename);
Error::SetString(error, fmt::format("Invalid track count/block offset {}/{} in '{}'", track_count, track_offset, filename));
Error::SetString(
error, fmt::format("Invalid track count/block offset {}/{} in '{}'", track_count, track_offset, filename));
return false;
}
@ -142,7 +150,8 @@ bool CDImageMds::OpenAndParse(const char* filename, Error* error)
if (PackedBCDToBinary(track.track_number) != track_number)
{
Log_ErrorPrintf("Unexpected track number 0x%02X in track %u", track.track_number, track_number);
Error::SetString(error, fmt::format("Unexpected track number 0x{:02X} in track {}", track.track_number, track_number));
Error::SetString(error,
fmt::format("Unexpected track number 0x{:02X} in track {}", track.track_number, track_number));
return false;
}
@ -176,7 +185,8 @@ bool CDImageMds::OpenAndParse(const char* filename, Error* error)
if (track_pregap > track_start_lba)
{
Log_ErrorPrintf("Track pregap %u is too large for start lba %u", track_pregap, track_start_lba);
Error::SetString(error, fmt::format("Track pregap {} is too large for start lba {}", track_pregap, track_start_lba));
Error::SetString(error,
fmt::format("Track pregap {} is too large for start lba {}", track_pregap, track_start_lba));
return false;
}

View file

@ -1,16 +1,21 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/assert.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include <algorithm>
#include <cerrno>
Log_SetChannel(CDImageMemory);
namespace {
class CDImageMemory : public CDImage
{
public:
@ -33,6 +38,8 @@ private:
CDSubChannelReplacement m_sbi;
};
} // namespace
CDImageMemory::CDImageMemory() = default;
CDImageMemory::~CDImageMemory()

View file

@ -1,25 +1,129 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
#include "pbp_types.h"
#include "string.h"
#include "zlib.h"
#include <array>
#include <cstdio>
#include <cstring>
#include <map>
#include <string>
#include <variant>
#include <vector>
Log_SetChannel(CDImagePBP);
using namespace PBP;
using FileSystem::FSeek64;
using FileSystem::FTell64;
namespace {
enum : u32
{
PBP_HEADER_OFFSET_COUNT = 8u,
TOC_NUM_ENTRIES = 102u,
BLOCK_TABLE_NUM_ENTRIES = 32256u,
DISC_TABLE_NUM_ENTRIES = 5u,
DECOMPRESSED_BLOCK_SIZE = 37632u // 2352 bytes per sector * 16 sectors per block
};
#pragma pack(push, 1)
struct PBPHeader
{
u8 magic[4]; // "\0PBP"
u32 version;
union
{
u32 offsets[PBP_HEADER_OFFSET_COUNT];
struct
{
u32 param_sfo_offset; // 0x00000028
u32 icon0_png_offset;
u32 icon1_png_offset;
u32 pic0_png_offset;
u32 pic1_png_offset;
u32 snd0_at3_offset;
u32 data_psp_offset;
u32 data_psar_offset;
};
};
};
static_assert(sizeof(PBPHeader) == 0x28);
struct SFOHeader
{
u8 magic[4]; // "\0PSF"
u32 version;
u32 key_table_offset; // Relative to start of SFOHeader, 0x000000A4 expected
u32 data_table_offset; // Relative to start of SFOHeader, 0x00000100 expected
u32 num_table_entries; // 0x00000009
};
static_assert(sizeof(SFOHeader) == 0x14);
struct SFOIndexTableEntry
{
u16 key_offset; // Relative to key_table_offset
u16 data_type;
u32 data_size; // Size of actual data in bytes
u32 data_total_size; // Size of data field in bytes, data_total_size >= data_size
u32 data_offset; // Relative to data_table_offset
};
static_assert(sizeof(SFOIndexTableEntry) == 0x10);
using SFOIndexTable = std::vector<SFOIndexTableEntry>;
using SFOTableDataValue = std::variant<std::string, u32>;
using SFOTable = std::map<std::string, SFOTableDataValue>;
struct BlockTableEntry
{
u32 offset;
u16 size;
u16 marker;
u8 checksum[0x10];
u64 padding;
};
static_assert(sizeof(BlockTableEntry) == 0x20);
struct TOCEntry
{
struct Timecode
{
u8 m;
u8 s;
u8 f;
};
u8 type;
u8 unknown;
u8 point;
Timecode pregap_start;
u8 zero;
Timecode userdata_start;
};
static_assert(sizeof(TOCEntry) == 0x0A);
#if 0
struct AudioTrackTableEntry
{
u32 block_offset;
u32 block_size;
u32 block_padding;
u32 block_checksum;
};
static_assert(sizeof(CDDATrackTableEntry) == 0x10);
#endif
#pragma pack(pop)
class CDImagePBP final : public CDImage
{
@ -94,33 +198,7 @@ private:
CDSubChannelReplacement m_sbi;
};
namespace EndianHelper {
static constexpr bool HostIsLittleEndian()
{
constexpr union
{
u8 a[4];
u32 b;
} test_val = {{1}};
return test_val.a[0] == 1;
}
template<typename T>
static void SwapByteOrder(T& val)
{
union
{
T t;
std::array<u8, sizeof(T)> arr;
} swap_val;
swap_val.t = val;
std::reverse(std::begin(swap_val.arr), std::end(swap_val.arr));
val = swap_val.t;
}
} // namespace EndianHelper
} // namespace
CDImagePBP::~CDImagePBP()
{
@ -135,22 +213,22 @@ bool CDImagePBP::LoadPBPHeader()
if (!m_file)
return false;
if (FSeek64(m_file, 0, SEEK_END) != 0)
if (FileSystem::FSeek64(m_file, 0, SEEK_END) != 0)
return false;
if (FTell64(m_file) < 0)
if (FileSystem::FTell64(m_file) < 0)
return false;
if (FSeek64(m_file, 0, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, 0, SEEK_SET) != 0)
return false;
if (fread(&m_pbp_header, sizeof(PBPHeader), 1, m_file) != 1)
if (std::fread(&m_pbp_header, sizeof(PBPHeader), 1, m_file) != 1)
{
Log_ErrorPrint("Unable to read PBP header");
return false;
}
if (strncmp((char*)m_pbp_header.magic, "\0PBP", 4) != 0)
if (std::strncmp((char*)m_pbp_header.magic, "\0PBP", 4) != 0)
{
Log_ErrorPrint("PBP magic number mismatch");
return false;
@ -165,13 +243,13 @@ bool CDImagePBP::LoadPBPHeader()
bool CDImagePBP::LoadSFOHeader()
{
if (FSeek64(m_file, m_pbp_header.param_sfo_offset, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, m_pbp_header.param_sfo_offset, SEEK_SET) != 0)
return false;
if (fread(&m_sfo_header, sizeof(SFOHeader), 1, m_file) != 1)
if (std::fread(&m_sfo_header, sizeof(SFOHeader), 1, m_file) != 1)
return false;
if (strncmp((char*)m_sfo_header.magic, "\0PSF", 4) != 0)
if (std::strncmp((char*)m_sfo_header.magic, "\0PSF", 4) != 0)
{
Log_ErrorPrint("SFO magic number mismatch");
return false;
@ -189,12 +267,14 @@ bool CDImagePBP::LoadSFOIndexTable()
m_sfo_index_table.clear();
m_sfo_index_table.resize(m_sfo_header.num_table_entries);
if (FSeek64(m_file, m_pbp_header.param_sfo_offset + sizeof(m_sfo_header), SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, m_pbp_header.param_sfo_offset + sizeof(m_sfo_header), SEEK_SET) != 0)
return false;
if (fread(m_sfo_index_table.data(), sizeof(SFOIndexTableEntry), m_sfo_header.num_table_entries, m_file) !=
if (std::fread(m_sfo_index_table.data(), sizeof(SFOIndexTableEntry), m_sfo_header.num_table_entries, m_file) !=
m_sfo_header.num_table_entries)
{
return false;
}
#if _DEBUG
for (size_t i = 0; i < static_cast<size_t>(m_sfo_header.num_table_entries); ++i)
@ -215,7 +295,7 @@ bool CDImagePBP::LoadSFOTable()
u32 abs_data_offset =
m_pbp_header.param_sfo_offset + m_sfo_header.data_table_offset + m_sfo_index_table[i].data_offset;
if (FSeek64(m_file, abs_key_offset, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, abs_key_offset, SEEK_SET) != 0)
{
Log_ErrorPrintf("Failed seek to key for SFO table entry %zu", i);
return false;
@ -223,13 +303,13 @@ bool CDImagePBP::LoadSFOTable()
// Longest known key string is 20 characters total, including the null character
char key_cstr[20] = {};
if (fgets(key_cstr, sizeof(key_cstr), m_file) == nullptr)
if (std::fgets(key_cstr, sizeof(key_cstr), m_file) == nullptr)
{
Log_ErrorPrintf("Failed to read key string for SFO table entry %zu", i);
return false;
}
if (FSeek64(m_file, abs_data_offset, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, abs_data_offset, SEEK_SET) != 0)
{
Log_ErrorPrintf("Failed seek to data for SFO table entry %zu", i);
return false;
@ -322,12 +402,6 @@ bool CDImagePBP::IsValidEboot(Error* error)
bool CDImagePBP::Open(const char* filename, Error* error)
{
if (!EndianHelper::HostIsLittleEndian())
{
Log_ErrorPrint("Big endian hosts not currently supported");
return false;
}
m_file = FileSystem::OpenCFile(filename, "rb");
if (!m_file)
{
@ -379,25 +453,25 @@ bool CDImagePBP::Open(const char* filename, Error* error)
}
// Start parsing ISO stuff
if (FSeek64(m_file, m_pbp_header.data_psar_offset, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, m_pbp_header.data_psar_offset, SEEK_SET) != 0)
return false;
// Check "PSTITLEIMG000000" for multi-disc
char data_psar_magic[16] = {};
if (fread(data_psar_magic, sizeof(data_psar_magic), 1, m_file) != 1)
if (std::fread(data_psar_magic, sizeof(data_psar_magic), 1, m_file) != 1)
return false;
if (strncmp(data_psar_magic, "PSTITLEIMG000000", 16) == 0) // Multi-disc header found
if (std::strncmp(data_psar_magic, "PSTITLEIMG000000", 16) == 0) // Multi-disc header found
{
// For multi-disc, the five disc offsets are located at data_psar_offset + 0x200. Non-present discs have an offset
// of 0. There are also some disc hashes, a serial (from one of the discs, but used as an identifier for the entire
// "title image" header), and some other offsets, but we don't really need to check those
if (FSeek64(m_file, m_pbp_header.data_psar_offset + 0x200, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, m_pbp_header.data_psar_offset + 0x200, SEEK_SET) != 0)
return false;
u32 disc_table[DISC_TABLE_NUM_ENTRIES] = {};
if (fread(disc_table, sizeof(u32), DISC_TABLE_NUM_ENTRIES, m_file) != DISC_TABLE_NUM_ENTRIES)
if (std::fread(disc_table, sizeof(u32), DISC_TABLE_NUM_ENTRIES, m_file) != DISC_TABLE_NUM_ENTRIES)
return false;
// Ignore encrypted files
@ -449,14 +523,14 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
// Go to ISO header
const u32 iso_header_start = m_disc_offsets[index];
if (FSeek64(m_file, iso_header_start, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, iso_header_start, SEEK_SET) != 0)
return false;
char iso_header_magic[12] = {};
if (fread(iso_header_magic, sizeof(iso_header_magic), 1, m_file) != 1)
if (std::fread(iso_header_magic, sizeof(iso_header_magic), 1, m_file) != 1)
return false;
if (strncmp(iso_header_magic, "PSISOIMG0000", 12) != 0)
if (std::strncmp(iso_header_magic, "PSISOIMG0000", 12) != 0)
{
Log_ErrorPrint("ISO header magic number mismatch");
return false;
@ -464,10 +538,10 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
// Ignore encrypted files
u32 pgd_magic;
if (FSeek64(m_file, iso_header_start + 0x400, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, iso_header_start + 0x400, SEEK_SET) != 0)
return false;
if (fread(&pgd_magic, sizeof(pgd_magic), 1, m_file) != 1)
if (std::fread(&pgd_magic, sizeof(pgd_magic), 1, m_file) != 1)
return false;
if (pgd_magic == 0x44475000) // "\0PGD"
@ -478,12 +552,12 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
}
// Read in the TOC
if (FSeek64(m_file, iso_header_start + 0x800, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, iso_header_start + 0x800, SEEK_SET) != 0)
return false;
for (u32 i = 0; i < TOC_NUM_ENTRIES; i++)
{
if (fread(&m_toc[i], sizeof(m_toc[i]), 1, m_file) != 1)
if (std::fread(&m_toc[i], sizeof(m_toc[i]), 1, m_file) != 1)
return false;
}
@ -491,21 +565,21 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
// for both data and audio
// Get the offset of the compressed iso
if (FSeek64(m_file, iso_header_start + 0xBFC, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, iso_header_start + 0xBFC, SEEK_SET) != 0)
return false;
u32 iso_offset;
if (fread(&iso_offset, sizeof(iso_offset), 1, m_file) != 1)
if (std::fread(&iso_offset, sizeof(iso_offset), 1, m_file) != 1)
return false;
// Generate block info table
if (FSeek64(m_file, iso_header_start + 0x4000, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, iso_header_start + 0x4000, SEEK_SET) != 0)
return false;
for (u32 i = 0; i < BLOCK_TABLE_NUM_ENTRIES; i++)
{
BlockTableEntry bte;
if (fread(&bte, sizeof(bte), 1, m_file) != 1)
if (std::fread(&bte, sizeof(bte), 1, m_file) != 1)
return false;
// Only store absolute file offset into a BlockInfo if this is a valid block
@ -708,19 +782,19 @@ bool CDImagePBP::InitDecompressionStream()
bool CDImagePBP::DecompressBlock(const BlockInfo& block_info)
{
if (FSeek64(m_file, block_info.offset, SEEK_SET) != 0)
if (FileSystem::FSeek64(m_file, block_info.offset, SEEK_SET) != 0)
return false;
// Compression level 0 has compressed size == decompressed size.
if (block_info.size == m_decompressed_block.size())
{
return (fread(m_decompressed_block.data(), sizeof(u8), m_decompressed_block.size(), m_file) ==
return (std::fread(m_decompressed_block.data(), sizeof(u8), m_decompressed_block.size(), m_file) ==
m_decompressed_block.size());
}
m_compressed_block.resize(block_info.size);
if (fread(m_compressed_block.data(), sizeof(u8), m_compressed_block.size(), m_file) != m_compressed_block.size())
if (std::fread(m_compressed_block.data(), sizeof(u8), m_compressed_block.size(), m_file) != m_compressed_block.size())
return false;
m_inflate_stream.next_in = m_compressed_block.data();

View file

@ -1,17 +1,22 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_image.h"
#include "cd_subchannel_replacement.h"
#include "common/assert.h"
#include "common/file_system.h"
#include "common/log.h"
#include <algorithm>
#include <cerrno>
#include <map>
#include <unordered_map>
Log_SetChannel(CDImagePPF);
namespace {
enum : u32
{
DESC_SIZE = 50,
@ -51,6 +56,8 @@ private:
u32 m_replacement_offset = 0;
};
} // namespace
CDImagePPF::CDImagePPF() = default;
CDImagePPF::~CDImagePPF() = default;

View file

@ -1,8 +1,9 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cd_xa.h"
#include "cd_image.h"
#include <algorithm>
#include <array>
@ -11,7 +12,7 @@ static constexpr std::array<s32, 4> s_xa_adpcm_filter_table_pos = {{0, 60, 115,
static constexpr std::array<s32, 4> s_xa_adpcm_filter_table_neg = {{0, 0, -52, -55}};
template<bool IS_STEREO, bool IS_8BIT>
static void DecodeXA_ADPCMChunk(const u8* chunk_ptr, s16* samples, s32* last_samples)
ALWAYS_INLINE_RELEASE static void DecodeXA_ADPCMChunk(const u8* chunk_ptr, s16* samples, s32* last_samples)
{
// The data layout is annoying here. Each word of data is interleaved with the other blocks, requiring multiple
// passes to decode the whole chunk.
@ -58,7 +59,7 @@ static void DecodeXA_ADPCMChunk(const u8* chunk_ptr, s16* samples, s32* last_sam
}
template<bool IS_STEREO, bool IS_8BIT>
static void DecodeXA_ADPCMChunks(const u8* chunk_ptr, s16* samples, s32* last_samples)
ALWAYS_INLINE_RELEASE static void DecodeXA_ADPCMChunks(const u8* chunk_ptr, s16* samples, s32* last_samples)
{
constexpr u32 NUM_CHUNKS = 18;
constexpr u32 CHUNK_SIZE_IN_BYTES = 128;
@ -73,7 +74,9 @@ static void DecodeXA_ADPCMChunks(const u8* chunk_ptr, s16* samples, s32* last_sa
}
}
void DecodeADPCMSector(const void* data, s16* samples, s32* last_samples)
} // namespace CDXA
void CDXA::DecodeADPCMSector(const void* data, s16* samples, s32* last_samples)
{
const XASubHeader* subheader = reinterpret_cast<const XASubHeader*>(
reinterpret_cast<const u8*>(data) + CDImage::SECTOR_SYNC_SIZE + sizeof(CDImage::SectorHeader));
@ -97,5 +100,3 @@ void DecodeADPCMSector(const void* data, s16* samples, s32* last_samples)
DecodeXA_ADPCMChunks<true, true>(chunk_ptr, samples, last_samples);
}
}
} // namespace CDXA

View file

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cubeb_audio_stream.h"
#include "host.h"
#include "imgui_manager.h"
@ -22,7 +21,35 @@
Log_SetChannel(CubebAudioStream);
static void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state);
namespace {
class CubebAudioStream : public AudioStream
{
public:
CubebAudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch);
~CubebAudioStream();
void SetPaused(bool paused) override;
void SetOutputVolume(u32 volume) override;
bool Initialize(u32 latency_ms);
private:
static void LogCallback(const char* fmt, ...);
static long DataCallback(cubeb_stream* stm, void* user_ptr, const void* input_buffer, void* output_buffer,
long nframes);
static void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state);
void DestroyContextAndStream();
cubeb* m_context = nullptr;
cubeb_stream* stream = nullptr;
#ifdef _WIN32
bool m_com_initialized_by_us = false;
#endif
};
} // namespace
CubebAudioStream::CubebAudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch)
: AudioStream(sample_rate, channels, buffer_ms, stretch)
@ -194,7 +221,7 @@ bool CubebAudioStream::Initialize(u32 latency_ms)
return true;
}
void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state)
void CubebAudioStream::StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state)
{
// noop
}

View file

@ -1,37 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "audio_stream.h"
#include <cstdint>
struct cubeb;
struct cubeb_stream;
class CubebAudioStream : public AudioStream
{
public:
CubebAudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch);
~CubebAudioStream();
void SetPaused(bool paused) override;
void SetOutputVolume(u32 volume) override;
bool Initialize(u32 latency_ms);
private:
static void LogCallback(const char* fmt, ...);
static long DataCallback(cubeb_stream* stm, void* user_ptr, const void* input_buffer, void* output_buffer,
long nframes);
void DestroyContextAndStream();
cubeb* m_context = nullptr;
cubeb_stream* stream = nullptr;
#ifdef _WIN32
bool m_com_initialized_by_us = false;
#endif
};

View file

@ -1,16 +1,21 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cue_parser.h"
#include "common/error.h"
#include "common/log.h"
#include "common/string_util.h"
#include <cstdarg>
Log_SetChannel(CueParser);
namespace CueParser {
static bool TokenMatch(const std::string_view& s1, const char* token);
}
static bool TokenMatch(const std::string_view& s1, const char* token)
bool CueParser::TokenMatch(const std::string_view& s1, const char* token)
{
const size_t token_len = std::strlen(token);
if (s1.length() != token_len)
@ -19,11 +24,11 @@ static bool TokenMatch(const std::string_view& s1, const char* token)
return (StringUtil::Strncasecmp(s1.data(), token, token_len) == 0);
}
File::File() = default;
CueParser::File::File() = default;
File::~File() = default;
CueParser::File::~File() = default;
const Track* File::GetTrack(u32 n) const
const CueParser::Track* CueParser::File::GetTrack(u32 n) const
{
for (const auto& it : m_tracks)
{
@ -34,7 +39,7 @@ const Track* File::GetTrack(u32 n) const
return nullptr;
}
Track* File::GetMutableTrack(u32 n)
CueParser::Track* CueParser::File::GetMutableTrack(u32 n)
{
for (auto& it : m_tracks)
{
@ -45,7 +50,7 @@ Track* File::GetMutableTrack(u32 n)
return nullptr;
}
bool File::Parse(std::FILE* fp, Error* error)
bool CueParser::File::Parse(std::FILE* fp, Error* error)
{
char line[1024];
u32 line_number = 1;
@ -66,7 +71,7 @@ bool File::Parse(std::FILE* fp, Error* error)
return true;
}
void File::SetError(u32 line_number, Error* error, const char* format, ...)
void CueParser::File::SetError(u32 line_number, Error* error, const char* format, ...)
{
std::va_list ap;
SmallString str;
@ -78,7 +83,7 @@ void File::SetError(u32 line_number, Error* error, const char* format, ...)
Error::SetString(error, fmt::format("Cue parse error at line {}: {}", line_number, str));
}
std::string_view File::GetToken(const char*& line)
std::string_view CueParser::File::GetToken(const char*& line)
{
std::string_view ret;
@ -119,7 +124,7 @@ std::string_view File::GetToken(const char*& line)
return ret;
}
std::optional<MSF> File::GetMSF(const std::string_view& token)
std::optional<CueParser::MSF> CueParser::File::GetMSF(const std::string_view& token)
{
static const s32 max_values[] = {std::numeric_limits<s32>::max(), 60, 75};
@ -164,7 +169,7 @@ std::optional<MSF> File::GetMSF(const std::string_view& token)
return ret;
}
bool File::ParseLine(const char* line, u32 line_number, Error* error)
bool CueParser::File::ParseLine(const char* line, u32 line_number, Error* error)
{
const std::string_view command(GetToken(line));
if (command.empty())
@ -208,7 +213,7 @@ bool File::ParseLine(const char* line, u32 line_number, Error* error)
return false;
}
bool File::HandleFileCommand(const char* line, u32 line_number, Error* error)
bool CueParser::File::HandleFileCommand(const char* line, u32 line_number, Error* error)
{
const std::string_view filename(GetToken(line));
const std::string_view mode(GetToken(line));
@ -230,7 +235,7 @@ bool File::HandleFileCommand(const char* line, u32 line_number, Error* error)
return true;
}
bool File::HandleTrackCommand(const char* line, u32 line_number, Error* error)
bool CueParser::File::HandleTrackCommand(const char* line, u32 line_number, Error* error)
{
if (!CompleteLastTrack(line_number, error))
return false;
@ -286,7 +291,7 @@ bool File::HandleTrackCommand(const char* line, u32 line_number, Error* error)
return true;
}
bool File::HandleIndexCommand(const char* line, u32 line_number, Error* error)
bool CueParser::File::HandleIndexCommand(const char* line, u32 line_number, Error* error)
{
if (!m_current_track.has_value())
{
@ -332,7 +337,7 @@ bool File::HandleIndexCommand(const char* line, u32 line_number, Error* error)
return true;
}
bool File::HandlePregapCommand(const char* line, u32 line_number, Error* error)
bool CueParser::File::HandlePregapCommand(const char* line, u32 line_number, Error* error)
{
if (!m_current_track.has_value())
{
@ -364,7 +369,7 @@ bool File::HandlePregapCommand(const char* line, u32 line_number, Error* error)
return true;
}
bool File::HandleFlagCommand(const char* line, u32 line_number, Error* error)
bool CueParser::File::HandleFlagCommand(const char* line, u32 line_number, Error* error)
{
if (!m_current_track.has_value())
{
@ -393,7 +398,7 @@ bool File::HandleFlagCommand(const char* line, u32 line_number, Error* error)
return true;
}
bool File::CompleteLastTrack(u32 line_number, Error* error)
bool CueParser::File::CompleteLastTrack(u32 line_number, Error* error)
{
if (!m_current_track.has_value())
return true;
@ -434,7 +439,7 @@ bool File::CompleteLastTrack(u32 line_number, Error* error)
return true;
}
bool File::SetTrackLengths(u32 line_number, Error* error)
bool CueParser::File::SetTrackLengths(u32 line_number, Error* error)
{
for (const Track& track : m_tracks)
{
@ -464,7 +469,7 @@ bool File::SetTrackLengths(u32 line_number, Error* error)
return true;
}
const CueParser::MSF* Track::GetIndex(u32 n) const
const CueParser::MSF* CueParser::Track::GetIndex(u32 n) const
{
for (const auto& it : indices)
{
@ -474,5 +479,3 @@ const CueParser::MSF* Track::GetIndex(u32 n) const
return nullptr;
}
} // namespace CueParser

View file

@ -114,6 +114,7 @@ static std::string s_message_dialog_message;
static std::array<std::string, 3> s_message_dialog_buttons;
static MessageDialogCallbackVariant s_message_dialog_callback;
namespace {
struct FileSelectorItem
{
FileSelectorItem() = default;
@ -132,6 +133,7 @@ struct FileSelectorItem
std::string full_path;
bool is_file;
};
} // namespace
static bool s_file_selector_open = false;
static bool s_file_selector_directory = false;
@ -144,6 +146,7 @@ static std::vector<FileSelectorItem> s_file_selector_items;
static constexpr float NOTIFICATION_FADE_IN_TIME = 0.2f;
static constexpr float NOTIFICATION_FADE_OUT_TIME = 0.8f;
namespace {
struct Notification
{
std::string key;
@ -156,6 +159,7 @@ struct Notification
float target_y;
float last_y;
};
} // namespace
static std::vector<Notification> s_notifications;
@ -164,6 +168,7 @@ static std::string s_toast_message;
static Common::Timer::Value s_toast_start_time;
static float s_toast_duration;
namespace {
struct BackgroundProgressDialogData
{
std::string message;
@ -172,6 +177,7 @@ struct BackgroundProgressDialogData
s32 max;
s32 value;
};
} // namespace
static std::vector<BackgroundProgressDialogData> s_background_progress_dialogs;
static std::mutex s_background_progress_lock;

View file

@ -30,6 +30,8 @@
Log_SetChannel(ImGuiManager);
namespace ImGuiManager {
namespace {
struct SoftwareCursor
{
std::string image_path;
@ -41,6 +43,19 @@ struct SoftwareCursor
std::pair<float, float> pos;
};
struct OSDMessage
{
std::string key;
std::string text;
Common::Timer::Value start_time;
Common::Timer::Value move_time;
float duration;
float target_y;
float last_y;
};
} // namespace
static void SetStyle();
static void SetKeyMap();
static bool LoadFontData();
@ -54,7 +69,6 @@ static void CreateSoftwareCursorTextures();
static void UpdateSoftwareCursorTexture(u32 index);
static void DestroySoftwareCursorTextures();
static void DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float, float>& pos);
} // namespace ImGuiManager
static float s_global_prescale = 1.0f; // before window scale
static float s_global_scale = 1.0f;
@ -85,17 +99,6 @@ static std::unordered_map<u32, ImGuiKey> s_imgui_key_map;
static constexpr float OSD_FADE_IN_TIME = 0.1f;
static constexpr float OSD_FADE_OUT_TIME = 0.4f;
struct OSDMessage
{
std::string key;
std::string text;
Common::Timer::Value start_time;
Common::Timer::Value move_time;
float duration;
float target_y;
float last_y;
};
static std::deque<OSDMessage> s_osd_active_messages;
static std::deque<OSDMessage> s_osd_posted_messages;
static std::mutex s_osd_messages_lock;
@ -103,6 +106,7 @@ static bool s_show_osd_messages = true;
static bool s_global_prescale_changed = false;
static std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> s_software_cursors = {};
} // namespace ImGuiManager
void ImGuiManager::SetFontPath(std::string path)
{
@ -627,12 +631,12 @@ void Host::AddKeyedOSDMessage(std::string key, std::string message, float durati
else
Log_InfoPrintf("OSD: %s", message.c_str());
if (!s_show_osd_messages)
if (!ImGuiManager::s_show_osd_messages)
return;
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
OSDMessage msg;
ImGuiManager::OSDMessage msg;
msg.key = std::move(key);
msg.text = std::move(message);
msg.duration = duration;
@ -641,8 +645,8 @@ void Host::AddKeyedOSDMessage(std::string key, std::string message, float durati
msg.target_y = -1.0f;
msg.last_y = -1.0f;
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
s_osd_posted_messages.push_back(std::move(msg));
std::unique_lock<std::mutex> lock(ImGuiManager::s_osd_messages_lock);
ImGuiManager::s_osd_posted_messages.push_back(std::move(msg));
}
void Host::AddFormattedOSDMessage(float duration, const char* format, ...)
@ -670,25 +674,25 @@ void Host::AddKeyedFormattedOSDMessage(std::string key, float duration, const ch
void Host::RemoveKeyedOSDMessage(std::string key)
{
if (!s_show_osd_messages)
if (!ImGuiManager::s_show_osd_messages)
return;
OSDMessage msg = {};
ImGuiManager::OSDMessage msg = {};
msg.key = std::move(key);
msg.duration = 0.0f;
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
s_osd_posted_messages.push_back(std::move(msg));
std::unique_lock<std::mutex> lock(ImGuiManager::s_osd_messages_lock);
ImGuiManager::s_osd_posted_messages.push_back(std::move(msg));
}
void Host::ClearOSDMessages()
{
{
std::unique_lock<std::mutex> lock(s_osd_messages_lock);
s_osd_posted_messages.clear();
std::unique_lock<std::mutex> lock(ImGuiManager::s_osd_messages_lock);
ImGuiManager::s_osd_posted_messages.clear();
}
s_osd_active_messages.clear();
ImGuiManager::s_osd_active_messages.clear();
}
void ImGuiManager::AcquirePendingOSDMessages(Common::Timer::Value current_time)
@ -716,8 +720,7 @@ void ImGuiManager::AcquirePendingOSDMessages(Common::Timer::Value current_time)
// Don't fade it in again
const float time_passed =
static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - iter->start_time));
iter->start_time =
current_time - Common::Timer::ConvertSecondsToValue(std::min(time_passed, OSD_FADE_IN_TIME));
iter->start_time = current_time - Common::Timer::ConvertSecondsToValue(std::min(time_passed, OSD_FADE_IN_TIME));
}
else
{
@ -825,7 +828,7 @@ float ImGuiManager::GetGlobalScale()
float Host::GetOSDScale()
{
return s_global_scale;
return ImGuiManager::s_global_scale;
}
ImFont* ImGuiManager::GetStandardFont()

View file

@ -27,6 +27,8 @@
Log_SetChannel(InputManager);
namespace {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
@ -88,6 +90,8 @@ struct MacroButton
bool trigger_state; ///< Whether the macro button is active.
};
} // namespace
// ------------------------------------------------------------------------
// Forward Declarations (for static qualifier)
// ------------------------------------------------------------------------

View file

@ -1,113 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "common/types.h"
#include <map>
#include <string>
#include <variant>
#include <vector>
namespace PBP {
enum : u32
{
PBP_HEADER_OFFSET_COUNT = 8u,
TOC_NUM_ENTRIES = 102u,
BLOCK_TABLE_NUM_ENTRIES = 32256u,
DISC_TABLE_NUM_ENTRIES = 5u,
DECOMPRESSED_BLOCK_SIZE = 37632u // 2352 bytes per sector * 16 sectors per block
};
#pragma pack(push, 1)
struct PBPHeader
{
u8 magic[4]; // "\0PBP"
u32 version;
union
{
u32 offsets[PBP_HEADER_OFFSET_COUNT];
struct
{
u32 param_sfo_offset; // 0x00000028
u32 icon0_png_offset;
u32 icon1_png_offset;
u32 pic0_png_offset;
u32 pic1_png_offset;
u32 snd0_at3_offset;
u32 data_psp_offset;
u32 data_psar_offset;
};
};
};
static_assert(sizeof(PBPHeader) == 0x28);
struct SFOHeader
{
u8 magic[4]; // "\0PSF"
u32 version;
u32 key_table_offset; // Relative to start of SFOHeader, 0x000000A4 expected
u32 data_table_offset; // Relative to start of SFOHeader, 0x00000100 expected
u32 num_table_entries; // 0x00000009
};
static_assert(sizeof(SFOHeader) == 0x14);
struct SFOIndexTableEntry
{
u16 key_offset; // Relative to key_table_offset
u16 data_type;
u32 data_size; // Size of actual data in bytes
u32 data_total_size; // Size of data field in bytes, data_total_size >= data_size
u32 data_offset; // Relative to data_table_offset
};
static_assert(sizeof(SFOIndexTableEntry) == 0x10);
using SFOIndexTable = std::vector<SFOIndexTableEntry>;
using SFOTableDataValue = std::variant<std::string, u32>;
using SFOTable = std::map<std::string, SFOTableDataValue>;
struct BlockTableEntry
{
u32 offset;
u16 size;
u16 marker;
u8 checksum[0x10];
u64 padding;
};
static_assert(sizeof(BlockTableEntry) == 0x20);
struct TOCEntry
{
struct Timecode
{
u8 m;
u8 s;
u8 f;
};
u8 type;
u8 unknown;
u8 point;
Timecode pregap_start;
u8 zero;
Timecode userdata_start;
};
static_assert(sizeof(TOCEntry) == 0x0A);
#if 0
struct AudioTrackTableEntry
{
u32 block_offset;
u32 block_size;
u32 block_padding;
u32 block_checksum;
};
static_assert(sizeof(CDDATrackTableEntry) == 0x10);
#endif
#pragma pack(pop)
} // namespace PBP

View file

@ -5,7 +5,6 @@
<ClInclude Include="audio_stream.h" />
<ClInclude Include="cd_image.h" />
<ClInclude Include="cd_image_hasher.h" />
<ClInclude Include="cubeb_audio_stream.h" />
<ClInclude Include="cue_parser.h" />
<ClInclude Include="d3d11_device.h" />
<ClInclude Include="d3d11_pipeline.h" />
@ -62,7 +61,6 @@
<ClInclude Include="opengl_texture.h">
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="pbp_types.h" />
<ClInclude Include="page_fault_handler.h" />
<ClInclude Include="cd_subchannel_replacement.h" />
<ClInclude Include="pch.h" />
@ -106,7 +104,6 @@
<ClInclude Include="wav_writer.h" />
<ClInclude Include="win32_raw_input_source.h" />
<ClInclude Include="window_info.h" />
<ClInclude Include="xaudio2_audio_stream.h" />
<ClInclude Include="xinput_source.h" />
</ItemGroup>
<ItemGroup>

View file

@ -12,7 +12,6 @@
<ClInclude Include="cd_image_hasher.h" />
<ClInclude Include="shiftjis.h" />
<ClInclude Include="page_fault_handler.h" />
<ClInclude Include="pbp_types.h" />
<ClInclude Include="cue_parser.h" />
<ClInclude Include="ini_settings_interface.h" />
<ClInclude Include="shadergen.h" />
@ -24,11 +23,9 @@
<ClInclude Include="platform_misc.h" />
<ClInclude Include="sdl_input_source.h" />
<ClInclude Include="win32_raw_input_source.h" />
<ClInclude Include="xaudio2_audio_stream.h" />
<ClInclude Include="xinput_source.h" />
<ClInclude Include="dinput_source.h" />
<ClInclude Include="input_manager.h" />
<ClInclude Include="cubeb_audio_stream.h" />
<ClInclude Include="metal_stream_buffer.h" />
<ClInclude Include="opengl_device.h" />
<ClInclude Include="opengl_loader.h" />

View file

@ -6,6 +6,7 @@
#include "common/log.h"
Log_SetChannel(WAVWriter);
namespace {
#pragma pack(push, 1)
struct WAV_HEADER
{
@ -32,8 +33,7 @@ struct WAV_HEADER
} data_chunk_header;
};
#pragma pack(pop)
namespace Common {
} // namespace
WAVWriter::WAVWriter() = default;
@ -114,5 +114,3 @@ bool WAVWriter::WriteHeader()
return (std::fwrite(&header, sizeof(header), 1, m_file) == 1);
}
} // namespace Common

View file

@ -1,12 +1,10 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "common/types.h"
#include <cstdio>
namespace Common {
class WAVWriter
{
public:
@ -33,5 +31,3 @@ private:
u32 m_num_channels = 0;
u32 m_num_frames = 0;
};
} // namespace Common

View file

@ -1,13 +1,68 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "xaudio2_audio_stream.h"
#include "util/audio_stream.h"
#include "common/assert.h"
#include "common/log.h"
#include <VersionHelpers.h>
#include "common/windows_headers.h"
#include <array>
#include <cstdint>
#include <memory>
#include <wrl/client.h>
#include <xaudio2.h>
Log_SetChannel(XAudio2AudioStream);
namespace {
class XAudio2AudioStream final : public AudioStream, private IXAudio2VoiceCallback
{
public:
XAudio2AudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch);
~XAudio2AudioStream();
void SetPaused(bool paused) override;
void SetOutputVolume(u32 volume) override;
bool OpenDevice(u32 latency_ms);
void CloseDevice();
void EnqueueBuffer();
private:
enum : u32
{
NUM_BUFFERS = 2,
INTERNAL_BUFFER_SIZE = 512,
};
ALWAYS_INLINE bool IsOpen() const { return static_cast<bool>(m_xaudio); }
// Inherited via IXAudio2VoiceCallback
void __stdcall OnVoiceProcessingPassStart(UINT32 BytesRequired) override;
void __stdcall OnVoiceProcessingPassEnd(void) override;
void __stdcall OnStreamEnd(void) override;
void __stdcall OnBufferStart(void* pBufferContext) override;
void __stdcall OnBufferEnd(void* pBufferContext) override;
void __stdcall OnLoopEnd(void* pBufferContext) override;
void __stdcall OnVoiceError(void* pBufferContext, HRESULT Error) override;
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio;
IXAudio2MasteringVoice* m_mastering_voice = nullptr;
IXAudio2SourceVoice* m_source_voice = nullptr;
std::array<std::unique_ptr<SampleType[]>, NUM_BUFFERS> m_enqueue_buffers;
u32 m_enqueue_buffer_size = 0;
u32 m_current_buffer = 0;
bool m_buffer_enqueued = false;
HMODULE m_xaudio2_library = {};
bool m_com_initialized_by_us = false;
};
} // namespace
XAudio2AudioStream::XAudio2AudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch)
: AudioStream(sample_rate, channels, buffer_ms, stretch)
{

View file

@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "common/windows_headers.h"
#include "util/audio_stream.h"
#include <array>
#include <cstdint>
#include <memory>
#include <wrl/client.h>
// We need to use the Windows 10 headers otherwise this won't compile.
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_WIN10
#include <xaudio2.h>
class XAudio2AudioStream final : public AudioStream, private IXAudio2VoiceCallback
{
public:
XAudio2AudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch);
~XAudio2AudioStream();
void SetPaused(bool paused) override;
void SetOutputVolume(u32 volume) override;
bool OpenDevice(u32 latency_ms);
void CloseDevice();
void EnqueueBuffer();
private:
enum : u32
{
NUM_BUFFERS = 2,
INTERNAL_BUFFER_SIZE = 512,
};
ALWAYS_INLINE bool IsOpen() const { return static_cast<bool>(m_xaudio); }
// Inherited via IXAudio2VoiceCallback
void __stdcall OnVoiceProcessingPassStart(UINT32 BytesRequired) override;
void __stdcall OnVoiceProcessingPassEnd(void) override;
void __stdcall OnStreamEnd(void) override;
void __stdcall OnBufferStart(void* pBufferContext) override;
void __stdcall OnBufferEnd(void* pBufferContext) override;
void __stdcall OnLoopEnd(void* pBufferContext) override;
void __stdcall OnVoiceError(void* pBufferContext, HRESULT Error) override;
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio;
IXAudio2MasteringVoice* m_mastering_voice = nullptr;
IXAudio2SourceVoice* m_source_voice = nullptr;
std::array<std::unique_ptr<SampleType[]>, NUM_BUFFERS> m_enqueue_buffers;
u32 m_enqueue_buffer_size = 0;
u32 m_current_buffer = 0;
bool m_buffer_enqueued = false;
HMODULE m_xaudio2_library = {};
bool m_com_initialized_by_us = false;
};