Merge pull request #20242 from hrydgard/audio-investigation

ImDebugger: Add some audio investigation tools
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2025-04-12 16:07:57 +02:00
commit 686d104903
16 files changed
+235 -131

No files matched your search

+1
View File
@@ -263,6 +263,7 @@ public:
int iDefaultTab;
int iScreenshotMode;
bool bVulkanDisableImplicitLayers;
bool bForceFfmpegForAudioDec;
std::vector<std::string> vPostShaderNames; // Off for chain end (only Off for no shader)
std::map<std::string, float> mPostShaderSetting;
+8 -8
View File
@@ -207,7 +207,7 @@ void Atrac::WriteContextToPSPMem() {
if (track_.firstSampleOffset != 0) {
context->info.firstValidSample = track_.FirstSampleOffsetFull();
} else {
context->info.firstValidSample = (track_.codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
context->info.firstValidSample = (track_.codecType == PSP_CODEC_AT3PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
}
context->info.sampleSize = track_.bytesPerFrame;
context->info.numChan = track_.channels;
@@ -226,7 +226,7 @@ void Atrac::WriteContextToPSPMem() {
void Track::DebugLog() const {
DEBUG_LOG(Log::ME, "ATRAC analyzed: %s channels: %d filesize: %d bitrate: %d kbps jointStereo: %d",
codecType == PSP_MODE_AT_3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo);
codecType == PSP_CODEC_AT3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo);
DEBUG_LOG(Log::ME, "dataoff: %d firstSampleOffset: %d endSample: %d", dataByteOffset, firstSampleOffset, endSample);
DEBUG_LOG(Log::ME, "loopStartSample: %d loopEndSample: %d", loopStartSample, loopEndSample);
DEBUG_LOG(Log::ME, "sampleSize: %d (%03x", bytesPerFrame, bytesPerFrame);
@@ -308,7 +308,7 @@ void AtracBase::CreateDecoder(int codecType, int bytesPerFrame, int channels) {
}
// First, init the standalone decoder.
if (codecType == PSP_MODE_AT_3) {
if (codecType == PSP_CODEC_AT3) {
// TODO: This is maybe not entirely reliable? Mui Mui house in LocoRoco 2 fails. Although also fails
// when I override this, so maybe the issue is something different...
bool jointStereo = IsAtrac3StreamJointStereo(codecType, bytesPerFrame, channels);
@@ -435,7 +435,7 @@ int Atrac::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize,
ResetData();
UpdateBufferState();
if (track_.codecType != PSP_MODE_AT_3 && track_.codecType != PSP_MODE_AT_3_PLUS) {
if (track_.codecType != PSP_CODEC_AT3 && track_.codecType != PSP_CODEC_AT3PLUS) {
// Shouldn't have gotten here, Analyze() checks this.
bufferState_ = ATRAC_STATUS_NO_DATA;
ERROR_LOG(Log::ME, "unexpected codec type %d in set data", track_.codecType);
@@ -454,7 +454,7 @@ int Atrac::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize,
bufferValidBytes_ = first_.size - bufferPos_;
}
const char *codecName = track_.codecType == PSP_MODE_AT_3 ? "atrac3" : "atrac3+";
const char *codecName = track_.codecType == PSP_CODEC_AT3 ? "atrac3" : "atrac3+";
const char *channelName = track_.channels == 1 ? "mono" : "stereo";
// Over-allocate databuf to prevent going off the end if the bitstream is bad or if there are
@@ -897,7 +897,7 @@ int Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrit
bufferValidBytes_ = bytesWrittenFirstBuf - bufferPos_;
}
if (track_.codecType == PSP_MODE_AT_3 || track_.codecType == PSP_MODE_AT_3_PLUS) {
if (track_.codecType == PSP_CODEC_AT3 || track_.codecType == PSP_CODEC_AT3PLUS) {
SeekToSample(sample);
}
@@ -916,11 +916,11 @@ void Atrac::InitLowLevel(const Atrac3LowLevelParams &params, int codecType) {
first_.writableBytes = track_.bytesPerFrame;
ResetData();
if (codecType == PSP_MODE_AT_3) {
if (codecType == PSP_CODEC_AT3) {
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
track_.bitrate = (track_.bitrate + 511) >> 10;
track_.jointStereo = IsAtrac3StreamJointStereo(codecType, params.bytesPerFrame, params.encodedChannels);
} else if (codecType == PSP_MODE_AT_3_PLUS) {
} else if (codecType == PSP_CODEC_AT3PLUS) {
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0;
track_.jointStereo = false;
+3 -3
View File
@@ -819,7 +819,7 @@ int Atrac2::SetData(const Track &track, u32 bufferAddr, u32 readSize, u32 buffer
SceAtracIdInfo &info = context_->info;
if (track.codecType != PSP_MODE_AT_3 && track.codecType != PSP_MODE_AT_3_PLUS) {
if (track.codecType != PSP_CODEC_AT3 && track.codecType != PSP_CODEC_AT3PLUS) {
// Shouldn't have gotten here, Analyze() checks this.
ERROR_LOG(Log::ME, "unexpected codec type %d in set data", track.codecType);
return SCE_ERROR_ATRAC_UNKNOWN_FORMAT;
@@ -832,7 +832,7 @@ int Atrac2::SetData(const Track &track, u32 bufferAddr, u32 readSize, u32 buffer
if (readSize >= track.fileSize) {
INFO_LOG(Log::ME, "The full file was set directly - we can dump it.");
char filename[512];
snprintf(filename, sizeof(filename), "%s_%d%s", track.codecType == PSP_MODE_AT_3 ? "at3" : "at3plus", track.endSample, track.channels == 1 ? "_mono" : "");
snprintf(filename, sizeof(filename), "%s_%d%s", track.codecType == PSP_CODEC_AT3 ? "at3" : "at3plus", track.endSample, track.channels == 1 ? "_mono" : "");
DumpFileIfEnabled(Memory::GetPointer(bufferAddr), readSize, filename, DumpFileType::Atrac3);
}
@@ -1004,7 +1004,7 @@ int Atrac2::Bitrate() const {
const SceAtracIdInfo &info = context_->info;
int bitrate = (info.sampleSize * 352800) / 1000;
if (info.codec == PSP_MODE_AT_3_PLUS)
if (info.codec == PSP_CODEC_AT3PLUS)
bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0;
else
bitrate = (bitrate + 511) >> 10;
+46 -28
View File
@@ -91,6 +91,15 @@ static u32 atracLibCrc = 0;
static int g_atracMaxContexts = 6;
static int g_atracBSS = 0;
static bool g_muteFlag[PSP_MAX_ATRAC_IDS]{}; // Not saved, just for debugging.
bool *__AtracMuteFlag(int atracID) {
if (atracID < 0 || atracID >= PSP_MAX_ATRAC_IDS) {
return nullptr;
}
return &g_muteFlag[atracID];
}
// For debugger only.
const AtracBase *__AtracGetCtx(int i, u32 *type) {
if (type) {
@@ -110,12 +119,13 @@ void __AtracInit() {
atracInited = true; // TODO: This should probably only happen in __AtracNotifyLoadModule.
memset(atracContexts, 0, sizeof(atracContexts));
memset(g_muteFlag, 0, sizeof(g_muteFlag));
// Start with 2 of each in this order.
atracContextTypes[0] = PSP_MODE_AT_3_PLUS;
atracContextTypes[1] = PSP_MODE_AT_3_PLUS;
atracContextTypes[2] = PSP_MODE_AT_3;
atracContextTypes[3] = PSP_MODE_AT_3;
atracContextTypes[0] = PSP_CODEC_AT3PLUS;
atracContextTypes[1] = PSP_CODEC_AT3PLUS;
atracContextTypes[2] = PSP_CODEC_AT3;
atracContextTypes[3] = PSP_CODEC_AT3;
atracContextTypes[4] = 0;
atracContextTypes[5] = 0;
}
@@ -127,6 +137,10 @@ void __AtracShutdown() {
}
}
int __AtracMaxContexts() {
return g_atracMaxContexts;
}
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize) {
atracLibVersion = version;
atracLibCrc = crc;
@@ -241,7 +255,7 @@ static int UnregisterAndDeleteAtrac(int atracID) {
// Really, allocate an Atrac context of a specific codec type.
// Useful to initialize a context for low level decode.
static u32 sceAtracGetAtracID(int codecType) {
if (codecType != PSP_MODE_AT_3 && codecType != PSP_MODE_AT_3_PLUS) {
if (codecType != PSP_CODEC_AT3 && codecType != PSP_CODEC_AT3PLUS) {
return hleReportError(Log::ME, SCE_ERROR_ATRAC_INVALID_CODECTYPE, "invalid codecType");
}
@@ -311,13 +325,15 @@ static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32
return hleLogError(Log::ME, SCE_ERROR_ATRAC_BAD_ALIGNMENT);
}
int numSamples = 0;
int numSamplesWritten = 0;
int finish = 0;
int remains = 0;
int ret = atrac->DecodeData(outAddr ? Memory::GetPointerWrite(outAddr) : nullptr, outAddr, &numSamples, &finish, &remains);
u8 *outPtr = outAddr ? Memory::GetPointerWrite(outAddr) : nullptr;
int ret = atrac->DecodeData(outPtr, outAddr, &numSamplesWritten, &finish, &remains);
if (ret != (int)SCE_ERROR_ATRAC_BAD_ATRACID && ret != (int)SCE_ERROR_ATRAC_NO_DATA) {
if (Memory::IsValidAddress(numSamplesAddr))
Memory::WriteUnchecked_U32(numSamples, numSamplesAddr);
Memory::WriteUnchecked_U32(numSamplesWritten, numSamplesAddr);
if (Memory::IsValidAddress(finishFlagAddr))
Memory::WriteUnchecked_U32(finish, finishFlagAddr);
// On error, no remaining frame value is written.
@@ -325,20 +341,25 @@ static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32
Memory::WriteUnchecked_U32(remains, remainAddr);
}
DEBUG_LOG(Log::ME, "%08x=sceAtracDecodeData(%i, %08x, %08x[%08x], %08x[%08x], %08x[%d])", ret, atracID, outAddr,
numSamplesAddr, numSamples,
finishFlagAddr, finish,
remainAddr, remains);
numSamplesAddr, numSamplesWritten,
finishFlagAddr, finish,
remainAddr, remains);
if (outPtr && g_muteFlag[atracID]) {
memset(outPtr, 0, atrac->GetOutputChannels() * 2 * numSamplesWritten);
}
if (ret == 0 || ret == SCE_ERROR_ATRAC_API_FAIL) {
// decode data successfully, delay thread
// Decoded or at least attempted to decode data, delay thread
return hleDelayResult(hleNoLog(ret), "atrac decode data", atracDecodeDelay);
}
return hleNoLog(ret);
}
// Likely a bogus brute-forced name?
static u32 sceAtracEndEntry() {
ERROR_LOG_REPORT(Log::ME, "UNIMPL sceAtracEndEntry()");
return hleNoLog(0);
static u32 sceAtracReleaseResources() {
// In the real implementation, this just calls sceAudioCodecReleaseEDRAM if any has been allocated.
return hleLogDebug(Log::ME, 0);
}
// Obtains information about what needs to be in the buffer to seek (or "reset")
@@ -356,13 +377,6 @@ static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 buffer
return hleLogError(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid buffer, should crash");
}
/*
DEBUG_LOG(Log::ME, "GetBufferInfoForResetting: First: %08x %08x %08x %08x", bufferInfo->first.writePosPtr, bufferInfo->first.writableBytes, bufferInfo->first.minWriteBytes, bufferInfo->first.filePos);
if (bufferInfo->second.filePos) {
DEBUG_LOG(Log::ME, "GetBufferInfoForResetting: Second: %08x %08x %08x %08x", bufferInfo->second.writePosPtr, bufferInfo->second.writableBytes, bufferInfo->second.minWriteBytes, bufferInfo->second.filePos);
}
*/
// Note: If we error here, it's because of the internal SkipFrames.
// We delayresult if we skip frames, which indeed can happen.
bool delay = false;
@@ -794,13 +808,13 @@ static int sceAtracReinit(int at3Count, int at3plusCount) {
for (int i = 0; i < at3plusCount; ++i) {
space -= 2;
if (space >= 0) {
atracContextTypes[next++] = PSP_MODE_AT_3_PLUS;
atracContextTypes[next++] = PSP_CODEC_AT3PLUS;
}
}
for (int i = 0; i < at3Count; ++i) {
space -= 1;
if (space >= 0) {
atracContextTypes[next++] = PSP_MODE_AT_3;
atracContextTypes[next++] = PSP_CODEC_AT3;
}
}
@@ -1030,7 +1044,7 @@ static const At3HeaderMap at3HeaderMap[] = {
};
bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels) {
if (codecType != PSP_MODE_AT_3) {
if (codecType != PSP_CODEC_AT3) {
// Well, might actually be, but it's not used in codec setup.
return false;
}
@@ -1061,7 +1075,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) {
atrac->InitLowLevel(*params, codecType);
const char *codecName = codecType == PSP_MODE_AT_3 ? "atrac3" : "atrac3+";
const char *codecName = codecType == PSP_CODEC_AT3 ? "atrac3" : "atrac3+";
const char *encodedChannelName = params->encodedChannels == 1 ? "mono" : "stereo";
const char *outputChannelName = params->outputChannels == 1 ? "mono" : "stereo";
return hleLogInfo(Log::ME, 0, "%s %s->%s audio", codecName, encodedChannelName, outputChannelName);
@@ -1090,6 +1104,10 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo
*srcConsumed = bytesConsumed;
*outWritten = bytesWritten;
if (g_muteFlag[atracID]) {
memset(outp, 0, bytesWritten);
}
NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, bytesWritten, "AtracLowLevelDecode");
return hleDelayResult(hleLogDebug(Log::ME, retval), "low level atrac decode data", atracDecodeDelay);
}
@@ -1164,7 +1182,7 @@ const char *AtracStatusToString(AtracStatus status) {
const HLEFunction sceAtrac3plus[] = {
{0X7DB31251, &WrapU_IU<sceAtracAddStreamData>, "sceAtracAddStreamData", 'x', "ix" },
{0X6A8C3CD5, &WrapU_IUUUU<sceAtracDecodeData>, "sceAtracDecodeData", 'x', "ixppp"},
{0XD5C28CC0, &WrapU_V<sceAtracEndEntry>, "sceAtracEndEntry", 'x', "" },
{0XD5C28CC0, &WrapU_V<sceAtracReleaseResources>, "sceAtracReleaseResources", 'x', "" }, // previously had the wrong name sceAtracEndEntry. The new name is a guess, but accurate in meaning.
{0X780F88D1, &WrapU_I<sceAtracGetAtracID>, "sceAtracGetAtracID", 'i', "x" },
{0XCA3CA3D2, &WrapU_IIU<sceAtracGetBufferInfoForResetting>, "sceAtracGetBufferInfoForReseting", 'x', "iix" },
{0XA554A158, &WrapU_IU<sceAtracGetBitrate>, "sceAtracGetBitrate", 'x', "ip" },
+5
View File
@@ -26,6 +26,7 @@ void Register_sceAtrac3plus();
void __AtracInit();
void __AtracDoState(PointerWrap &p);
void __AtracShutdown();
int __AtracMaxContexts();
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize);
void __AtracNotifyUnloadModule();
@@ -141,3 +142,7 @@ bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels);
u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd);
void AtracSasDecodeData(int atracID, u8* outbuf, int *SamplesNum, int *finish);
int AtracSasBindContextAndGetID(u32 contextAddr);
// To provide checkboxes in the debugger UI.
// This setting is not saved.
bool *__AtracMuteFlag(int atracID);
+1
View File
@@ -171,6 +171,7 @@ const HLEFunction SysMemForKernel[] = {
{ 0X536AD5E1, &WrapU_V<sceKernelGetUidmanCB>, "sceKernelGetUidmanCB", 'i', "i" , HLE_KERNEL_SYSCALL },
{ 0X7B749390, &WrapI_IU<sceKernelFreeHeapMemory>, "sceKernelFreeHeapMemory", 'i', "ix" , HLE_KERNEL_SYSCALL },
{ 0XEB7A74DB, &WrapI_IUU<sceKernelAllocHeapMemoryWithOption>, "sceKernelAllocHeapMemoryWithOption", 'i', "ixp" , HLE_KERNEL_SYSCALL },
{ 0x6373995d, nullptr, "sceKernelGetModel", 'i', "", HLE_KERNEL_SYSCALL },
};
void Register_SysMemForKernel() {
+12 -3
View File
@@ -79,6 +79,12 @@ static volatile int sasThreadState = SasThreadState::DISABLED;
static SasThreadParams sasThreadParams;
static int sasMixEvent = -1;
static bool g_sasMuteFlag = false;
bool *__SasGetGlobalMuteFlag() {
return &g_sasMuteFlag;
}
int __SasThread() {
SetCurrentThreadName("SAS");
@@ -86,8 +92,8 @@ int __SasThread() {
while (sasThreadState != SasThreadState::DISABLED) {
sasWake.wait(guard);
if (sasThreadState == SasThreadState::QUEUED) {
sas->Mix(sasThreadParams.outAddr, sasThreadParams.inAddr, sasThreadParams.leftVol, sasThreadParams.rightVol);
const bool mute = g_sasMuteFlag;
sas->Mix(sasThreadParams.outAddr, sasThreadParams.inAddr, sasThreadParams.leftVol, sasThreadParams.rightVol, mute);
std::lock_guard<std::mutex> doneGuard(sasDoneMutex);
sasThreadState = SasThreadState::READY;
sasDone.notify_one();
@@ -105,7 +111,8 @@ static void __SasDrain() {
static void __SasEnqueueMix(u32 outAddr, u32 inAddr = 0, int leftVol = 0, int rightVol = 0) {
if (sasThreadState == SasThreadState::DISABLED) {
// No thread, call it immediately.
sas->Mix(outAddr, inAddr, leftVol, rightVol);
const bool mute = g_sasMuteFlag;
sas->Mix(outAddr, inAddr, leftVol, rightVol, mute);
return;
}
@@ -162,6 +169,8 @@ static void sasMixFinish(u64 userdata, int cycleslate) {
void __SasInit() {
sas = new SasInstance();
g_sasMuteFlag = false;
sasMixEvent = CoreTiming::RegisterEvent("SasMix", sasMixFinish);
if (g_Config.bSeparateSASThread) {
+1
View File
@@ -22,6 +22,7 @@ void __SasDoState(PointerWrap &p);
void __SasShutdown();
void __SasGetDebugStats(char *stats, size_t bufsize);
bool *__SasGetGlobalMuteFlag();
void Register_sceSasCore();
+8 -1
View File
@@ -623,7 +623,7 @@ void SasInstance::MixVoice(SasVoice &voice) {
}
}
void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol, bool mute) {
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
SasVoice &voice = voices[v];
if (!voice.playing || voice.paused)
@@ -631,6 +631,12 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
MixVoice(voice);
}
// Apply mute if needed (note: we try to keep everything else identical to the non-muted case).
if (mute) {
memset(mixBuffer, 0, grainSize * sizeof(int) * 2);
memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
}
// Then mix the send buffer in with the rest.
// Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
@@ -664,6 +670,7 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
}
// Note: leftVol/rightVol here are how much to scale the inp content by, not the mixBuffer.
void SasInstance::WriteMixedOutput(s16 *outp, const s16 *inp, int leftVol, int rightVol) {
const bool dry = waveformEffect.isDryOn != 0;
const bool wet = waveformEffect.isWetOn != 0;
+1 -1
View File
@@ -315,7 +315,7 @@ public:
FILE *audioDump = nullptr;
void Mix(u32 outAddr, u32 inAddr = 0, int leftVol = 0, int rightVol = 0);
void Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol, bool mute);
void MixVoice(SasVoice &voice);
// Applies reverb to send buffer, according to waveformEffect.
+11 -2
View File
@@ -39,6 +39,7 @@ extern "C" {
#include "Core/FFMPEGCompat.h"
}
#include "Core/Config.h"
#else
@@ -136,15 +137,23 @@ private:
};
AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) {
bool forceFfmpeg = false;
#ifdef USE_FFMPEG
forceFfmpeg = g_Config.bForceFfmpegForAudioDec;
#endif
if (forceFfmpeg) {
return new FFmpegAudioDecoder(audioType, sampleRateHz, channels);
}
switch (audioType) {
case PSP_CODEC_MP3:
return new MiniMp3Audio();
case PSP_CODEC_AT3:
return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize);
return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize);
case PSP_CODEC_AT3PLUS:
return CreateAtrac3PlusAudio(channels, blockAlign);
default:
// Only AAC falls back to FFMPEG now.
// Only AAC normally falls back to FFMPEG now.
return new FFmpegAudioDecoder(audioType, sampleRateHz, channels);
}
}
+8 -4
View File
@@ -4,6 +4,10 @@
#include "Core/HLE/ErrorCodes.h"
#include "Core/MemMap.h"
// Atrac file parsing constants
#define AT3_MAGIC 0x0270
#define AT3_PLUS_MAGIC 0xFFFE // This is normally a marker for WAVE_FORMAT_EXTENSIBLE
const int RIFF_CHUNK_MAGIC = 0x46464952;
const int RIFF_WAVE_MAGIC = 0x45564157;
const int FMT_CHUNK_MAGIC = 0x20746D66;
@@ -110,9 +114,9 @@ int AnalyzeAtracTrack(const u8 *buffer, u32 size, Track *track, std::string *err
}
if (at3fmt->fmtTag == AT3_MAGIC)
track->codecType = PSP_MODE_AT_3;
track->codecType = PSP_CODEC_AT3;
else if (at3fmt->fmtTag == AT3_PLUS_MAGIC)
track->codecType = PSP_MODE_AT_3_PLUS;
track->codecType = PSP_CODEC_AT3PLUS;
else {
*error = "AnalyzeTrack: invalid fmt magic: %04x";
return SCE_ERROR_ATRAC_UNKNOWN_FORMAT;
@@ -288,14 +292,14 @@ int AnalyzeAA3Track(const u8 *buffer, u32 size, u32 fileSize, Track *track, std:
switch (buffer[32]) {
case 0:
track->codecType = PSP_MODE_AT_3;
track->codecType = PSP_CODEC_AT3;
track->bytesPerFrame = (codecParams & 0x03FF) * 8;
track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 1024;
track->channels = 2;
track->jointStereo = (codecParams >> 17) & 1;
break;
case 1:
track->codecType = PSP_MODE_AT_3_PLUS;
track->codecType = PSP_CODEC_AT3PLUS;
track->bytesPerFrame = ((codecParams & 0x03FF) * 8) + 8;
track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 2048;
track->channels = (codecParams >> 10) & 7;
+4 -8
View File
@@ -5,11 +5,7 @@
#include <vector>
#include <string>
// Atrac file parsing.
#define AT3_MAGIC 0x0270
#define AT3_PLUS_MAGIC 0xFFFE
#define PSP_MODE_AT_3_PLUS 0x00001000
#define PSP_MODE_AT_3 0x00001001
#include "Core/HLE/sceAudiocodec.h"
constexpr u32 ATRAC3_MAX_SAMPLES = 0x400; // 1024
constexpr u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; // 2048
@@ -72,7 +68,7 @@ struct Track {
inline int FirstOffsetExtra() const {
// These first samples are skipped, after first possibly skipping 0-2 full frames, it seems.
return codecType == PSP_MODE_AT_3_PLUS ? 0x170 : 0x45;
return codecType == PSP_CODEC_AT3PLUS ? 0x170 : 0x45;
}
// Includes the extra offset. See firstSampleOffset comment above.
@@ -82,12 +78,12 @@ struct Track {
// Output frame size, different between the two supported codecs.
int SamplesPerFrame() const {
return codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES;
return codecType == PSP_CODEC_AT3PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES;
}
int Bitrate() const {
int bitrate = (bytesPerFrame * 352800) / 1000;
if (codecType == PSP_MODE_AT_3_PLUS)
if (codecType == PSP_CODEC_AT3PLUS)
bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0;
else
bitrate = (bitrate + 511) >> 10;
+73 -55
View File
@@ -100,11 +100,10 @@ void DeveloperToolsScreen::CreateTextureReplacementTab(UI::LinearLayout *list) {
void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) {
using namespace UI;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
auto si = GetI18NCategory(I18NCat::SYSINFO);
auto sy = GetI18NCategory(I18NCat::SYSTEM);
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
list->Add(new ItemHeader(sy->T("General")));
list->Add(new ItemHeader(sy->T("CPU Core")));
bool canUseJit = System_GetPropertyBool(SYSPROP_CAN_JIT);
// iOS can now use JIT on all modes, apparently.
@@ -130,14 +129,10 @@ void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) {
list->Add(new Choice(dev->T("JIT debug tools")))->OnClick.Handle(this, &DeveloperToolsScreen::OnJitDebugTools);
list->Add(new CheckBox(&g_Config.bShowDeveloperMenu, dev->T("Show Developer Menu")));
#if !PPSSPP_PLATFORM(UWP)
Choice *cpuTests = new Choice(dev->T("Run CPU Tests"));
list->Add(cpuTests)->OnClick.Handle(this, &DeveloperToolsScreen::OnRunCPUTests);
cpuTests->SetEnabled(TestsAvailable() && !PSP_IsInited());
#endif
AddOverlayList(list, screenManager());
list->Add(new ItemHeader(sy->T("General")));
list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged);
list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig);
list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics")));
@@ -145,37 +140,7 @@ void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) {
list->Add(new CheckBox(&g_Config.bGpuLogProfiler, dev->T("GPU log profiler")));
}
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
list->Add(new CheckBox(&g_Config.bRenderMultiThreading, dev->T("Multi-threaded rendering"), ""))->OnClick.Add([](UI::EventParams &e) {
// TODO: Not translating yet. Will combine with other translations of settings that need restart.
g_OSD.Show(OSDType::MESSAGE_WARNING, "Restart required");
return UI::EVENT_DONE;
});
}
if (GetGPUBackend() == GPUBackend::VULKAN && SupportsCustomDriver()) {
auto driverChoice = list->Add(new Choice(gr->T("AdrenoTools driver manager")));
driverChoice->OnClick.Add([=](UI::EventParams &e) {
screenManager()->push(new DriverManagerScreen(gamePath_));
return UI::EVENT_DONE;
});
}
// For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply
// because the D3D drivers are generally solid enough to not need this type of investigation.
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest);
}
list->Add(new CheckBox(&g_Config.bVendorBugChecksEnabled, dev->T("Enable driver bug workarounds")));
Choice *frameDumpTests = list->Add(new Choice(dev->T("Framedump tests")));
frameDumpTests->OnClick.Add([this](UI::EventParams &e) {
screenManager()->push(new FrameDumpTestScreen());
return UI::EVENT_DONE;
});
frameDumpTests->SetEnabled(!PSP_IsInited());
list->Add(new Choice(dev->T("Touchscreen Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnTouchscreenTest);
// list->Add(new Choice(dev->T("Memstick Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnMemstickTest);
list->Add(new CheckBox(&g_Config.bShowOnScreenMessages, dev->T("Show on-screen messages")));
allowDebugger_ = !WebServerStopped(WebServerFlags::DEBUGGER);
canAllowDebugger_ = !WebServerStopping(WebServerFlags::DEBUGGER);
@@ -183,8 +148,6 @@ void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) {
list->Add(allowDebugger)->OnClick.Handle(this, &DeveloperToolsScreen::OnRemoteDebugger);
allowDebugger->SetEnabledPtr(&canAllowDebugger_);
list->Add(new CheckBox(&g_Config.bShowOnScreenMessages, dev->T("Show on-screen messages")));
list->Add(new Choice(dev->T("GPI/GPO switches/LEDs")))->OnClick.Add([=](UI::EventParams &e) {
screenManager()->push(new GPIGPOScreen(dev->T("GPI/GPO switches/LEDs")));
return UI::EVENT_DONE;
@@ -209,20 +172,35 @@ void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) {
});
#endif
static const char *ffModes[] = { "Render all frames", "", "Frame Skipping" };
PopupMultiChoice *ffMode = list->Add(new PopupMultiChoice(&g_Config.iFastForwardMode, dev->T("Fast-forward mode"), ffModes, 0, ARRAY_SIZE(ffModes), I18NCat::GRAPHICS, screenManager()));
ffMode->SetEnabledFunc([]() { return !g_Config.bVSync; });
ffMode->HideChoice(1); // not used
auto displayRefreshRate = list->Add(new PopupSliderChoice(&g_Config.iDisplayRefreshRate, 60, 1000, 60, dev->T("Display refresh rate"), 1, screenManager()));
displayRefreshRate->SetFormat(si->T("%d Hz"));
// Makes it easy to get savestates out of an iOS device. The file listing shown in MacOS doesn't allow
// you to descend into directories.
#if PPSSPP_PLATFORM(IOS)
list->Add(new Choice(dev->T("Copy savestates to memstick root")))->OnClick.Handle(this, &DeveloperToolsScreen::OnCopyStatesToRoot);
#endif
}
void DeveloperToolsScreen::CreateTestsTab(UI::LinearLayout *list) {
using namespace UI;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
list->Add(new Choice(dev->T("Touchscreen Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnTouchscreenTest);
// list->Add(new Choice(dev->T("Memstick Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnMemstickTest);
Choice *frameDumpTests = list->Add(new Choice(dev->T("Framedump tests")));
frameDumpTests->OnClick.Add([this](UI::EventParams &e) {
screenManager()->push(new FrameDumpTestScreen());
return UI::EVENT_DONE;
});
frameDumpTests->SetEnabled(!PSP_IsInited());
#if !PPSSPP_PLATFORM(UWP)
Choice *cpuTests = new Choice(dev->T("Run CPU Tests"));
list->Add(cpuTests)->OnClick.Handle(this, &DeveloperToolsScreen::OnRunCPUTests);
cpuTests->SetEnabled(TestsAvailable() && !PSP_IsInited());
#endif
// For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply
// because the D3D drivers are generally solid enough to not need this type of investigation.
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest);
}
}
void DeveloperToolsScreen::CreateDumpFileTab(UI::LinearLayout *list) {
@@ -313,17 +291,52 @@ void DeveloperToolsScreen::CreateMIPSTracerTab(UI::LinearLayout *list) {
ClearMIPSTracer->OnClick.Handle(this, &DeveloperToolsScreen::OnMIPSTracerClearTracer);
}
void DeveloperToolsScreen::CreateAudioTab(UI::LinearLayout *list) {
using namespace UI;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
list->Add(new CheckBox(&g_Config.bForceFfmpegForAudioDec, dev->T("Use FFMPEG for all compressed audio")));
}
void DeveloperToolsScreen::CreateGraphicsTab(UI::LinearLayout *list) {
using namespace UI;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
auto ps = GetI18NCategory(I18NCat::POSTSHADERS);
auto sy = GetI18NCategory(I18NCat::SYSTEM);
auto si = GetI18NCategory(I18NCat::SYSINFO);
Draw::DrawContext *draw = screenManager()->getDrawContext();
list->Add(new ItemHeader(sy->T("General")));
list->Add(new CheckBox(&g_Config.bVendorBugChecksEnabled, dev->T("Enable driver bug workarounds")));
static const char *ffModes[] = { "Render all frames", "", "Frame Skipping" };
PopupMultiChoice *ffMode = list->Add(new PopupMultiChoice(&g_Config.iFastForwardMode, dev->T("Fast-forward mode"), ffModes, 0, ARRAY_SIZE(ffModes), I18NCat::GRAPHICS, screenManager()));
ffMode->SetEnabledFunc([]() { return !g_Config.bVSync; });
ffMode->HideChoice(1); // not used
auto displayRefreshRate = list->Add(new PopupSliderChoice(&g_Config.iDisplayRefreshRate, 60, 1000, 60, dev->T("Display refresh rate"), 1, screenManager()));
displayRefreshRate->SetFormat(si->T("%d Hz"));
list->Add(new ItemHeader(dev->T("Vulkan")));
list->Add(new CheckBox(&g_Config.bVulkanDisableImplicitLayers, dev->T("Prevent loading overlays")));
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
list->Add(new CheckBox(&g_Config.bRenderMultiThreading, dev->T("Multi-threaded rendering"), ""))->OnClick.Add([](UI::EventParams &e) {
// TODO: Not translating yet. Will combine with other translations of settings that need restart.
g_OSD.Show(OSDType::MESSAGE_WARNING, "Restart required");
return UI::EVENT_DONE;
});
}
if (GetGPUBackend() == GPUBackend::VULKAN && SupportsCustomDriver()) {
auto driverChoice = list->Add(new Choice(gr->T("AdrenoTools driver manager")));
driverChoice->OnClick.Add([=](UI::EventParams &e) {
screenManager()->push(new DriverManagerScreen(gamePath_));
return UI::EVENT_DONE;
});
}
list->Add(new ItemHeader(dev->T("Ubershaders")));
if (draw->GetShaderLanguageDesc().bitwiseOps && !draw->GetBugs().Has(Draw::Bugs::UNIFORM_INDEXING_BROKEN)) {
// If the above if fails, the checkbox is redundant since it'll be force disabled anyway.
@@ -392,11 +405,20 @@ void DeveloperToolsScreen::CreateTabs() {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
AddTab("General", sy->T("General"), [this](UI::LinearLayout *parent) {
CreateGeneralTab(parent);
});
AddTab("TextureReplacement", dev->T("Texture Replacement"), [this](UI::LinearLayout *parent) {
CreateTextureReplacementTab(parent);
});
AddTab("General", sy->T("General"), [this](UI::LinearLayout *parent) {
CreateGeneralTab(parent);
AddTab("Graphics", ms->T("Graphics"), [this](UI::LinearLayout *parent) {
CreateGraphicsTab(parent);
});
AddTab("Audio", ms->T("Audio"), [this](UI::LinearLayout *parent) {
CreateAudioTab(parent);
});
AddTab("Tests", dev->T("Tests"), [this](UI::LinearLayout *parent) {
CreateTestsTab(parent);
});
AddTab("DumpFiles", sy->T("Dump files"), [this](UI::LinearLayout *parent) {
CreateDumpFileTab(parent);
@@ -410,10 +432,6 @@ void DeveloperToolsScreen::CreateTabs() {
CreateMIPSTracerTab(parent);
});
#endif
AddTab("Graphics", ms->T("Graphics"), [this](UI::LinearLayout *parent) {
CreateGraphicsTab(parent);
});
// Reconsider whenever recreating views.
hasTexturesIni_ = HasIni::MAYBE;
}
+2
View File
@@ -20,6 +20,8 @@ private:
void CreateDumpFileTab(UI::LinearLayout *parent);
void CreateHLETab(UI::LinearLayout *parent);
void CreateMIPSTracerTab(UI::LinearLayout *list);
void CreateTestsTab(UI::LinearLayout *list);
void CreateAudioTab(UI::LinearLayout *list);
void CreateGraphicsTab(UI::LinearLayout *list);
UI::EventReturn OnRunCPUTests(UI::EventParams &e);
+51 -18
View File
@@ -957,43 +957,58 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) {
}
if (ImGui::CollapsingHeader("sceAtrac", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::BeginTable("atracs", 7, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::Checkbox("Force FFMPEG", &g_Config.bForceFfmpegForAudioDec);
if (ImGui::BeginTable("atracs", 8, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Index", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Mute", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Channels", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("CurrentSample", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("RemainingFrames", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("CurSample", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("RemFrames", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Impl", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
for (int i = 0; i < PSP_MAX_ATRAC_IDS; i++) {
u32 type = 0;
const AtracBase *ctx = __AtracGetCtx(i, &type);
if (!ctx) {
continue;
}
const int maxContexts = __AtracMaxContexts();
for (int i = 0; i < maxContexts; i++) {
u32 codecType = 0;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(i);
ImGui::SetNextItemAllowOverlap();
char temp[16];
snprintf(temp, sizeof(temp), "%d", i);
if (ImGui::Selectable(temp, i == cfg.selectedAtracCtx, ImGuiSelectableFlags_SpanAllColumns)) {
cfg.selectedAtracCtx = i;
}
ImGui::TableNextColumn();
switch (type) {
case PSP_MODE_AT_3_PLUS:
bool *mutePtr = __AtracMuteFlag(i);
if (mutePtr) {
ImGui::Checkbox("", mutePtr);
}
ImGui::TableNextColumn();
switch (codecType) {
case 0:
ImGui::TextUnformatted("-"); // Uninitialized
break;
case PSP_CODEC_AT3PLUS:
ImGui::TextUnformatted("Atrac3+");
break;
case PSP_MODE_AT_3:
case PSP_CODEC_AT3:
ImGui::TextUnformatted("Atrac3");
break;
default:
ImGui::Text("%04x", type);
ImGui::Text("%04x", codecType);
break;
}
const AtracBase *ctx = __AtracGetCtx(i, &codecType);
if (!ctx) {
// Nothing more we can display about uninitialized contexts.
ImGui::PopID();
continue;
}
ImGui::TableNextColumn();
ImGui::TextUnformatted(AtracStatusToString(ctx->BufferState()));
ImGui::TableNextColumn();
@@ -1014,6 +1029,7 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) {
}
ImGui::TableNextColumn();
ImGui::TextUnformatted(ctx->GetContextVersion() >= 2 ? "NewImpl" : "Legacy");
ImGui::PopID();
}
ImGui::EndTable();
@@ -1291,6 +1307,8 @@ void DrawSasAudio(ImConfig &cfg) {
return;
}
ImGui::Checkbox("Mute", __SasGetGlobalMuteFlag());
ImGui::SameLine();
ImGui::Checkbox("Show all voices", &cfg.sasShowAllVoices);
if (ImGui::BeginTable("saschannels", 9, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
@@ -1834,6 +1852,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
System_CopyStringToClipboard(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base));
}
}
ImGui::Separator();
if (ImGui::MenuItem("Close")) {
g_Config.bShowImDebugger = false;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Core")) {
@@ -1952,11 +1974,22 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("Dear ImGui Style editor", nullptr, &cfg_.styleEditorOpen);
ImGui::EndMenu();
}
// Let's have this at the top level, to help anyone confused.
if (ImGui::BeginMenu("Close Debugger")) {
if (ImGui::MenuItem("Close")) {
g_Config.bShowImDebugger = false;
ImGui::EndMenu();
}
switch (coreState) {
case CoreState::CORE_STEPPING_CPU:
if (ImGui::MenuItem(">> Run")) {
Core_Resume();
}
break;
case CoreState::CORE_RUNNING_CPU:
if (ImGui::MenuItem("|| Break")) {
Core_Break(BreakReason::DebugBreak);
}
break;
default:
break;
}
ImGui::EndMainMenuBar();
}