From c67988d2ce13946170fb91ae31550cbd01b4b781 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Jun 2019 08:17:00 -0700 Subject: [PATCH 1/2] Audio: Correct errors on Output2/SRC release. --- Core/HLE/sceAudio.cpp | 105 ++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index cdbc811e4768..dd6072d1e9d9 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -335,14 +335,19 @@ static u32 sceAudioOutput2Reserve(u32 sampleCount) { static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) { // Note: 0xFFFFF, not 0xFFFF! if (vol > 0xFFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput2OutputBlocking(%08x, %08x) - invalid volume", vol, dataPtr); - return SCE_ERROR_AUDIO_INVALID_VOLUME; + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); } - DEBUG_LOG(SCEAUDIO, "sceAudioOutput2OutputBlocking(%08x, %08x)", vol, dataPtr); - chans[PSP_AUDIO_CHANNEL_OUTPUT2].leftVolume = vol; - chans[PSP_AUDIO_CHANNEL_OUTPUT2].rightVolume = vol; - chans[PSP_AUDIO_CHANNEL_OUTPUT2].sampleAddress = dataPtr; - return __AudioEnqueue(chans[PSP_AUDIO_CHANNEL_OUTPUT2], PSP_AUDIO_CHANNEL_OUTPUT2, true); + + auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; + chan.leftVolume = vol; + chan.rightVolume = vol; + chan.sampleAddress = dataPtr; + hleEatCycles(10000); + + int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_OUTPUT2, true); + if (result < 0) + return hleLogError(SCEAUDIO, result); + return hleLogSuccessI(SCEAUDIO, result); } static u32 sceAudioOutput2ChangeLength(u32 sampleCount) { @@ -365,10 +370,15 @@ static u32 sceAudioOutput2GetRestSample() { } static u32 sceAudioOutput2Release() { - DEBUG_LOG(SCEAUDIO, "sceAudioOutput2Release()"); - chans[PSP_AUDIO_CHANNEL_OUTPUT2].reset(); - chans[PSP_AUDIO_CHANNEL_OUTPUT2].reserved = false; - return 0; + auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; + if (!chan.reserved) + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + if (!chan.sampleQueue.empty()) + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); + + chan.reset(); + chan.reserved = false; + return hleLogSuccessI(SCEAUDIO, 0); } static u32 sceAudioSetFrequency(u32 freq) { @@ -389,7 +399,7 @@ static u32 sceAudioSetVolumeOffset() { static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) { if (format == 4) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - unexpected format", sampleCount, freq, format); + ERROR_LOG_REPORT(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - unexpected format", sampleCount, freq, format); return PSP_AUDIO_ERROR_SRC_FORMAT_4; } else if (format != 2) { ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - unexpected format", sampleCount, freq, format); @@ -401,36 +411,41 @@ static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) { ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - channel already reserved ", sampleCount, freq, format); return SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED; } else { - DEBUG_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x)", sampleCount, freq, format); chans[PSP_AUDIO_CHANNEL_SRC].reserved = true; chans[PSP_AUDIO_CHANNEL_SRC].sampleCount = sampleCount; chans[PSP_AUDIO_CHANNEL_SRC].format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO; __AudioSetOutputFrequency(freq); } - return 0; + return hleLogSuccessI(SCEAUDIO, 0); } static u32 sceAudioSRCChRelease() { - if (!chans[PSP_AUDIO_CHANNEL_SRC].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCChRelease() - channel not reserved "); - return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; - } - DEBUG_LOG(SCEAUDIO, "sceAudioSRCChRelease()"); - chans[PSP_AUDIO_CHANNEL_SRC].reset(); - chans[PSP_AUDIO_CHANNEL_SRC].reserved = false; - return 0; + auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; + if (!chan.reserved) + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved"); + if (!chan.sampleQueue.empty()) + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "output busy"); + + chan.reset(); + chan.reserved = false; + return hleLogSuccessI(SCEAUDIO, 0); } static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) { if (vol > 0xFFFFF) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCOutputBlocking(%08x, %08x) - invalid volume", vol, buf); - return SCE_ERROR_AUDIO_INVALID_VOLUME; + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_VOLUME, "invalid volume"); } - DEBUG_LOG(SCEAUDIO, "sceAudioSRCOutputBlocking(%08x, %08x)", vol, buf); - chans[PSP_AUDIO_CHANNEL_SRC].leftVolume = vol; - chans[PSP_AUDIO_CHANNEL_SRC].rightVolume = vol; - chans[PSP_AUDIO_CHANNEL_SRC].sampleAddress = buf; - return __AudioEnqueue(chans[PSP_AUDIO_CHANNEL_SRC], PSP_AUDIO_CHANNEL_SRC, true); + + auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; + chan.leftVolume = vol; + chan.rightVolume = vol; + chan.sampleAddress = buf; + + hleEatCycles(10000); + int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_SRC, true); + if (result < 0) + return hleLogError(SCEAUDIO, result); + return hleLogSuccessI(SCEAUDIO, result); } static u32 sceAudioRoutingSetMode(u32 mode) { @@ -461,31 +476,31 @@ const HLEFunction sceAudio[] = { // Newer simplified single channel audio output. Presumably for games that use Atrac3 // directly from Sas instead of playing it on a separate audio channel. - {0X01562BA3, &WrapU_U, "sceAudioOutput2Reserve", 'x', "x" }, + {0X01562BA3, &WrapU_U, "sceAudioOutput2Reserve", 'x', "i" }, {0X2D53F36E, &WrapU_UU, "sceAudioOutput2OutputBlocking", 'x', "xx" }, - {0X63F2889C, &WrapU_U, "sceAudioOutput2ChangeLength", 'x', "x" }, - {0X647CEF33, &WrapU_V, "sceAudioOutput2GetRestSample", 'x', "" }, + {0X63F2889C, &WrapU_U, "sceAudioOutput2ChangeLength", 'x', "i" }, + {0X647CEF33, &WrapU_V, "sceAudioOutput2GetRestSample", 'i', "" }, {0X43196845, &WrapU_V, "sceAudioOutput2Release", 'x', "" }, // "Traditional" audio channel interface {0X80F1F7E0, &WrapU_V, "sceAudioInit", 'x', "" }, {0X210567F7, &WrapU_V, "sceAudioEnd", 'x', "" }, - {0XA2BEAA6C, &WrapU_U, "sceAudioSetFrequency", 'x', "x" }, + {0XA2BEAA6C, &WrapU_U, "sceAudioSetFrequency", 'x', "i" }, {0X927AC32B, &WrapU_V, "sceAudioSetVolumeOffset", 'x', "" }, - {0X8C1009B2, &WrapU_UIU, "sceAudioOutput", 'x', "xix" }, - {0X136CAF51, &WrapU_UIU, "sceAudioOutputBlocking", 'x', "xix" }, - {0XE2D56B2D, &WrapU_UIIU, "sceAudioOutputPanned", 'x', "xiix"}, - {0X13F592BC, &WrapU_UIIU, "sceAudioOutputPannedBlocking", 'x', "xiix"}, - {0X5EC81C55, &WrapU_IUU, "sceAudioChReserve", 'x', "ixx" }, - {0X6FC46853, &WrapU_U, "sceAudioChRelease", 'x', "x" }, - {0XE9D97901, &WrapI_U, "sceAudioGetChannelRestLen", 'i', "x" }, - {0XB011922F, &WrapI_U, "sceAudioGetChannelRestLength", 'i', "x" }, - {0XCB2E439E, &WrapU_UU, "sceAudioSetChannelDataLen", 'x', "xx" }, - {0X95FD0C2D, &WrapU_UU, "sceAudioChangeChannelConfig", 'x', "xx" }, - {0XB7E1D8E7, &WrapU_UUU, "sceAudioChangeChannelVolume", 'x', "xxx" }, + {0X8C1009B2, &WrapU_UIU, "sceAudioOutput", 'x', "ixx" }, + {0X136CAF51, &WrapU_UIU, "sceAudioOutputBlocking", 'x', "ixx" }, + {0XE2D56B2D, &WrapU_UIIU, "sceAudioOutputPanned", 'x', "ixxx"}, + {0X13F592BC, &WrapU_UIIU, "sceAudioOutputPannedBlocking", 'x', "ixxx"}, + {0X5EC81C55, &WrapU_IUU, "sceAudioChReserve", 'x', "iii" }, + {0X6FC46853, &WrapU_U, "sceAudioChRelease", 'x', "i" }, + {0XE9D97901, &WrapI_U, "sceAudioGetChannelRestLen", 'i', "i" }, + {0XB011922F, &WrapI_U, "sceAudioGetChannelRestLength", 'i', "i" }, + {0XCB2E439E, &WrapU_UU, "sceAudioSetChannelDataLen", 'x', "ii" }, + {0X95FD0C2D, &WrapU_UU, "sceAudioChangeChannelConfig", 'x', "ii" }, + {0XB7E1D8E7, &WrapU_UUU, "sceAudioChangeChannelVolume", 'x', "ixx" }, // Not sure about the point of these, maybe like traditional but with ability to do sample rate conversion? - {0X38553111, &WrapU_UUU, "sceAudioSRCChReserve", 'x', "xxx" }, + {0X38553111, &WrapU_UUU, "sceAudioSRCChReserve", 'x', "iii" }, {0X5C37C0AE, &WrapU_V, "sceAudioSRCChRelease", 'x', "" }, {0XE0727056, &WrapU_UU, "sceAudioSRCOutputBlocking", 'x', "xx" }, From 2c205676240729c927cea17a83e3b711a13a9f86 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Jun 2019 08:38:22 -0700 Subject: [PATCH 2/2] Audio: Better errors on Output2/SRC reserve. The frequency handling probably doesn't work, though. --- Core/HLE/sceAudio.cpp | 60 ++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index dd6072d1e9d9..6fd437bad69e 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -317,19 +317,19 @@ static u32 sceAudioEnd() { } static u32 sceAudioOutput2Reserve(u32 sampleCount) { + auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2]; + // This seems to ignore the MSB, for some reason. + sampleCount &= 0x7FFFFFFF; if (sampleCount < 17 || sampleCount > 4111) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput2Reserve(%08x) - invalid sample count", sampleCount); - return SCE_KERNEL_ERROR_INVALID_SIZE; - } else if (chans[PSP_AUDIO_CHANNEL_OUTPUT2].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioOutput2Reserve(%08x) - channel already reserved", sampleCount); - return SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED; - } else { - DEBUG_LOG(SCEAUDIO, "sceAudioOutput2Reserve(%08x)", sampleCount); - chans[PSP_AUDIO_CHANNEL_OUTPUT2].sampleCount = sampleCount; - chans[PSP_AUDIO_CHANNEL_OUTPUT2].format = PSP_AUDIO_FORMAT_STEREO; - chans[PSP_AUDIO_CHANNEL_OUTPUT2].reserved = true; + return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); + } else if (chan.reserved) { + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); } - return 0; + + chan.sampleCount = sampleCount; + chan.format = PSP_AUDIO_FORMAT_STEREO; + chan.reserved = true; + return hleLogSuccessI(SCEAUDIO, 0); } static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) { @@ -397,23 +397,35 @@ static u32 sceAudioSetVolumeOffset() { return 0; } +static bool SRCFrequencyAllowed(int freq) { + if (freq == 44100 || freq == 22050 || freq == 11025) + return true; + if (freq == 48000 || freq == 32000 || freq == 24000 || freq == 16000 || freq == 12000 || freq == 8000) + return true; + return false; +} + static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) { + auto &chan = chans[PSP_AUDIO_CHANNEL_SRC]; + // This seems to ignore the MSB, for some reason. + sampleCount &= 0x7FFFFFFF; if (format == 4) { - ERROR_LOG_REPORT(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - unexpected format", sampleCount, freq, format); - return PSP_AUDIO_ERROR_SRC_FORMAT_4; + return hleReportError(SCEAUDIO, PSP_AUDIO_ERROR_SRC_FORMAT_4, "unexpected format"); } else if (format != 2) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - unexpected format", sampleCount, freq, format); - return SCE_KERNEL_ERROR_INVALID_SIZE; + return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "unexpected format"); } else if (sampleCount < 17 || sampleCount > 4111) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - invalid sample count", sampleCount, freq, format); - return SCE_KERNEL_ERROR_INVALID_SIZE; - } else if (chans[PSP_AUDIO_CHANNEL_SRC].reserved) { - ERROR_LOG(SCEAUDIO, "sceAudioSRCChReserve(%08x, %08x, %08x) - channel already reserved ", sampleCount, freq, format); - return SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED; - } else { - chans[PSP_AUDIO_CHANNEL_SRC].reserved = true; - chans[PSP_AUDIO_CHANNEL_SRC].sampleCount = sampleCount; - chans[PSP_AUDIO_CHANNEL_SRC].format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO; + return hleLogError(SCEAUDIO, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid sample count"); + } else if (freq != 0 && !SRCFrequencyAllowed(freq)) { + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_INVALID_FREQUENCY, "invalid frequency"); + } else if (chan.reserved) { + return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED, "channel already reserved"); + } + + chan.reserved = true; + chan.sampleCount = sampleCount; + chan.format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO; + // TODO: Zero probably means don't change? Or it means default? + if (freq != 0) { __AudioSetOutputFrequency(freq); } return hleLogSuccessI(SCEAUDIO, 0);