diff --git a/Core/Config.h b/Core/Config.h index 525d5703d4..27a88251e0 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -263,6 +263,7 @@ public: int iDefaultTab; int iScreenshotMode; bool bVulkanDisableImplicitLayers; + bool bForceFfmpegForAudioDec; std::vector vPostShaderNames; // Off for chain end (only Off for no shader) std::map mPostShaderSetting; diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 14ee036062..9777085d3d 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -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 ¶ms, 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; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 466140c8f6..2a7cd6e2c2 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -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; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 2048f13345..d3f5f523cc 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -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", 'x', "ix" }, {0X6A8C3CD5, &WrapU_IUUUU, "sceAtracDecodeData", 'x', "ixppp"}, - {0XD5C28CC0, &WrapU_V, "sceAtracEndEntry", 'x', "" }, + {0XD5C28CC0, &WrapU_V, "sceAtracReleaseResources", 'x', "" }, // previously had the wrong name sceAtracEndEntry. The new name is a guess, but accurate in meaning. {0X780F88D1, &WrapU_I, "sceAtracGetAtracID", 'i', "x" }, {0XCA3CA3D2, &WrapU_IIU, "sceAtracGetBufferInfoForReseting", 'x', "iix" }, {0XA554A158, &WrapU_IU, "sceAtracGetBitrate", 'x', "ip" }, diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index 1f4fb046dc..e04e045538 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -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); diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 0bfb214c50..0855229137 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -171,6 +171,7 @@ const HLEFunction SysMemForKernel[] = { { 0X536AD5E1, &WrapU_V, "sceKernelGetUidmanCB", 'i', "i" , HLE_KERNEL_SYSCALL }, { 0X7B749390, &WrapI_IU, "sceKernelFreeHeapMemory", 'i', "ix" , HLE_KERNEL_SYSCALL }, { 0XEB7A74DB, &WrapI_IUU, "sceKernelAllocHeapMemoryWithOption", 'i', "ixp" , HLE_KERNEL_SYSCALL }, + { 0x6373995d, nullptr, "sceKernelGetModel", 'i', "", HLE_KERNEL_SYSCALL }, }; void Register_SysMemForKernel() { diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 238321a13f..ef1449ed67 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -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 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) { diff --git a/Core/HLE/sceSas.h b/Core/HLE/sceSas.h index 66dc65db6d..d6c1dccc1e 100644 --- a/Core/HLE/sceSas.h +++ b/Core/HLE/sceSas.h @@ -22,6 +22,7 @@ void __SasDoState(PointerWrap &p); void __SasShutdown(); void __SasGetDebugStats(char *stats, size_t bufsize); +bool *__SasGetGlobalMuteFlag(); void Register_sceSasCore(); diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 126f3d68ff..7cf1f1f8b3 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -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; diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index fb480a0ceb..8635f71b71 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -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. diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 0f0229d57c..330c1e7116 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -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); } } diff --git a/Core/Util/AtracTrack.cpp b/Core/Util/AtracTrack.cpp index 16748519ef..9755112278 100644 --- a/Core/Util/AtracTrack.cpp +++ b/Core/Util/AtracTrack.cpp @@ -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; diff --git a/Core/Util/AtracTrack.h b/Core/Util/AtracTrack.h index 9c83ec58e2..1d670865b4 100644 --- a/Core/Util/AtracTrack.h +++ b/Core/Util/AtracTrack.h @@ -5,11 +5,7 @@ #include #include -// 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; diff --git a/UI/DeveloperToolsScreen.cpp b/UI/DeveloperToolsScreen.cpp index ef3a9daf12..d9bba48354 100644 --- a/UI/DeveloperToolsScreen.cpp +++ b/UI/DeveloperToolsScreen.cpp @@ -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; } diff --git a/UI/DeveloperToolsScreen.h b/UI/DeveloperToolsScreen.h index 05d89923e5..b74d04935f 100644 --- a/UI/DeveloperToolsScreen.h +++ b/UI/DeveloperToolsScreen.h @@ -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); diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 7236b8c109..b9d09bf2f2 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -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(); }