From 2a6b35f3ad33beee0feabf19017ecba8e01a2cdc Mon Sep 17 00:00:00 2001 From: aquanull Date: Wed, 5 Jun 2013 00:37:39 +0800 Subject: [PATCH 1/8] Fix missing Pause Screen BG if the game is exited once and then replayed. --- UI/GameInfoCache.cpp | 1 + UI/GameInfoCache.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 56a7a90e83..9114c40f19 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -286,6 +286,7 @@ void GameInfoCache::FlushBGs() { delete iter->second->pic1Texture; iter->second->pic1Texture = 0; } + iter->second->wantBG = false; } } diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index cf2745350a..6415a64238 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -33,7 +33,7 @@ class GameInfo { public: - GameInfo() : fileType(FILETYPE_UNKNOWN), iconTexture(NULL), pic0Texture(NULL), pic1Texture(NULL) {} + GameInfo() : fileType(FILETYPE_UNKNOWN), iconTexture(NULL), pic0Texture(NULL), pic1Texture(NULL), wantBG(false) {} bool DeleteGame(); // Better be sure what you're doing when calling this. bool DeleteAllSaveData(); From 6fb2abd0fbf6a141b5fc7d772d3066fcbec10257 Mon Sep 17 00:00:00 2001 From: oioitff Date: Sun, 9 Jun 2013 01:28:58 +0800 Subject: [PATCH 2/8] Add sceAudiocodec stuff --- Core/CMakeLists.txt | 1 + Core/Core.vcxproj | 2 ++ Core/Core.vcxproj.filters | 6 ++++ Core/HLE/HLETables.cpp | 2 ++ Core/HLE/sceAudiocodec.cpp | 45 +++++++++++++++++++++++++++++ Core/HLE/sceAudiocodec.h | 59 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 Core/HLE/sceAudiocodec.cpp create mode 100644 Core/HLE/sceAudiocodec.h diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 95e838aa7d..38643ffa0e 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -72,6 +72,7 @@ set(SRCS HLE/sceParseUri.cpp HLE/sceParseHttp.cpp HLE/sceVaudio.cpp + HLE/sceAudiocodec.cpp HW/MemoryStick.cpp HW/MediaEngine.cpp HW/SasAudio.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index cc7f5e9260..15613de74b 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -188,6 +188,7 @@ + @@ -368,6 +369,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 7172448df5..4cf70aa22e 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -433,6 +433,9 @@ HW + + HLE\Libraries + @@ -801,6 +804,9 @@ HW + + HLE\Libraries + diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 4d69d4e47f..4b2713828b 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -64,6 +64,7 @@ #include "sceNp.h" #include "sceMd5.h" #include "sceJpeg.h" +#include "sceAudiocodec.h" #define N(s) s @@ -269,6 +270,7 @@ void RegisterAllModules() { Register_sceNpAuth(); Register_sceMd5(); Register_sceJpeg(); + Register_sceAudiocodec(); for (int i = 0; i < numModules; i++) { diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp new file mode 100644 index 0000000000..b89b3e6e1d --- /dev/null +++ b/Core/HLE/sceAudiocodec.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Core/HLE/HLE.h" + +#include "sceAudiocodec.h" +#include "Core/Reporting.h" + +int sceAudiocodecInit(u32 audioCodec, int codeType) { + ERROR_LOG_REPORT(HLE, "UNIMPL sceAudiocodecInit(%08x, %x)", audioCodec, codeType); + return 0; +} +int sceAudiocodecDecode(u32 audioCodec, int codeType) { + ERROR_LOG_REPORT(HLE, "UNIMPL sceAudiocodecDecode(%08x, %x)", audioCodec, codeType); + return 0; +} + +const HLEFunction sceAudiocodec[] = +{ + {0x70A703F8, WrapI_UI, "sceAudiocodecDecode"}, + {0x5B37EB1D, WrapI_UI, "sceAudiocodecInit"}, + {0x8ACA11D5, 0, "sceAudiocodecGetInfo"}, + {0x3A20A200, 0, "sceAudiocodecGetEDRAM"}, + {0x29681260, 0, "sceAudiocodecReleaseEDRAM"}, + {0x9D3F790C, 0, "sceAudiocodeCheckNeedMem"}, +}; + +void Register_sceAudiocodec() +{ + RegisterModule("sceAudiocodec", ARRAY_SIZE(sceAudiocodec), sceAudiocodec); +} \ No newline at end of file diff --git a/Core/HLE/sceAudiocodec.h b/Core/HLE/sceAudiocodec.h new file mode 100644 index 0000000000..f909bef490 --- /dev/null +++ b/Core/HLE/sceAudiocodec.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +typedef struct +{ + s32 unk0; + s32 unk4; + s32 err; // 8 + s32 edramAddr; // 12 + s32 neededMem; // 16 + s32 unk20; + u32 inBuf; // 24 + s32 unk28; + u32 outBuf; // 32 + s32 unk36; + s8 unk40; + s8 unk41; + s8 unk42; + s8 unk43; + s8 unk44; + s8 unk45; + s8 unk46; + s8 unk47; + s32 unk48; + s32 unk52; + s32 unk56; + s32 unk60; + s32 unk64; + s32 unk68; + s32 unk72; + s32 unk76; + s32 unk80; + s32 unk84; + s32 unk88; + s32 unk92; + s32 unk96; + s32 unk100; + u32 allocMem; // 104 + // make sure the size is 128 + u8 unk[20]; +} SceAudiocodecCodec; + +void Register_sceAudiocodec(); \ No newline at end of file From cac9b89823e65230fe4b7066bb2d6731e4fc96ee Mon Sep 17 00:00:00 2001 From: oioitff Date: Sun, 9 Jun 2013 01:31:45 +0800 Subject: [PATCH 3/8] Basically implement _sceAtracGetContextAddress. --- Core/HLE/sceAtrac.cpp | 170 ++++++++++++++++++++++++++++++------------ Core/HLE/sceAtrac.h | 47 +++++++++++- 2 files changed, 169 insertions(+), 48 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index f70800df9b..57bf7fb38b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -26,6 +26,8 @@ #include "sceKernel.h" #include "sceUtility.h" +#include "sceKernelMemory.h" +#include "sceAtrac.h" #define ATRAC_ERROR_API_FAIL 0x80630002 @@ -102,7 +104,7 @@ struct AtracLoopInfo { struct Atrac { Atrac() : atracID(-1), data_buf(0), decodePos(0), decodeEnd(0), atracChannels(2), atracOutputChannels(2), atracBitrate(64), atracBytesPerFrame(0), atracBufSize(0), - currentSample(0), endSample(-1), firstSampleoffset(0), loopinfoNum(0), loopNum(0) { + currentSample(0), endSample(-1), firstSampleoffset(0), loopinfoNum(0), loopNum(0), atracContext(0) { memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(second)); #ifdef USE_FFMPEG @@ -131,6 +133,9 @@ struct Atrac { Atrac3plus_Decoder::CloseContext(&decoder_context); sampleQueue.clear(); + + if (atracContext) + kernelMemory.Free(atracContext); } void DoState(PointerWrap &p) { @@ -230,6 +235,8 @@ struct Atrac { Atrac3plus_Decoder::BufferQueue sampleQueue; void* decoder_context; + u32 atracContext; + #ifdef USE_FFMPEG AVFormatContext *pFormatCtx; AVIOContext *pAVIOCtx; @@ -483,18 +490,17 @@ u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) return 0; } -u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) +u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int *remains) { - DEBUG_LOG(HLE, "sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr); Atrac *atrac = getAtrac(atracID); u32 ret = 0; if (atrac != NULL) { // We already passed the end - return an error (many games check for this.) if (atrac->currentSample >= atrac->endSample && atrac->loopNum == 0) { - Memory::Write_U32(0, numSamplesAddr); - Memory::Write_U32(1, finishFlagAddr); - Memory::Write_U32(0, remainAddr); + *SamplesNum = 0; + *finish = 1; + *remains = 0; ret = ATRAC_ERROR_ALL_DATA_DECODED; } else { // TODO: This isn't at all right, but at least it makes the music "last" some time. @@ -520,7 +526,7 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF // got a frame int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, atrac->pFrame->nb_samples, (AVSampleFormat)atrac->pFrame->format, 1); - u8* out = Memory::GetPointer(outAddr); + u8* out = outbuf; numSamples = atrac->pFrame->nb_samples; avret = swr_convert(atrac->pSwrCtx, &out, atrac->pFrame->nb_samples, (const u8**)atrac->pFrame->extended_data, atrac->pFrame->nb_samples); @@ -547,11 +553,10 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF inbytes = std::min(inbytes, (int)atrac->atracBytesPerFrame); if (inbytes > 0 && inbytes == atrac->atracBytesPerFrame) { Atrac3plus_Decoder::Decode(atrac->decoder_context, atrac->data_buf + atrac->decodePos, inbytes, &decodebytes, buf); - DEBUG_LOG(HLE, "atracID: %i decodebytes: %i outAddr: %08x", atracID, decodebytes, outAddr); atrac->sampleQueue.push(buf, decodebytes); } } - s16* out = (s16*)Memory::GetPointer(outAddr); + s16* out = (s16*)outbuf; memset(out, 0, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels); int gotsize = atrac->sampleQueue.pop_front(buf, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels); numSamples = gotsize / sizeof(s16) / atrac->atracChannels; @@ -579,10 +584,10 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF if (numSamples == 0 && (atrac->loopNum != 0)) { numSamples = atracSamplesPerFrame; } - Memory::Memset(outAddr, 0, numSamples * sizeof(s16) * atrac->atracOutputChannels); + memset(outbuf, 0, numSamples * sizeof(s16) * atrac->atracOutputChannels); } - Memory::Write_U32(numSamples, numSamplesAddr); + *SamplesNum = numSamples; // update current sample and decodePos atrac->currentSample += numSamples; atrac->decodePos = atrac->getDecodePosBySample(atrac->currentSample); @@ -597,23 +602,33 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF (numSamples == 0 && atrac->first.size >= atrac->first.filesize)) finishFlag = 1; - Memory::Write_U32(finishFlag, finishFlagAddr); - int remains = atrac->getRemainFrames(); - Memory::Write_U32(remains, remainAddr); + *finish = finishFlag; + *remains = atrac->getRemainFrames(); } // TODO: Can probably remove this after we validate no wrong ids? } else { - Memory::Write_U16(0, outAddr); // Write a single 16-bit stereo - Memory::Write_U16(0, outAddr + 2); - - Memory::Write_U32(1, numSamplesAddr); - Memory::Write_U32(1, finishFlagAddr); // Lie that decoding is finished - Memory::Write_U32(-1, remainAddr); // Lie that decoding is finished + memset(outbuf, 0, ATRAC3_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels); + *SamplesNum = ATRAC3_MAX_SAMPLES; + *finish = 1; + *remains = -1; } return ret; } +u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) +{ + DEBUG_LOG(HLE, "sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr); + u32 numSamples = 0; + u32 finish = 0; + int remains = 0; + int ret = _AtracDecodeData(atracID, Memory::GetPointer(outAddr), &numSamples, &finish, &remains); + Memory::Write_U32(numSamples, numSamplesAddr); + Memory::Write_U32(finish, finishFlagAddr); + Memory::Write_U32(remains, remainAddr); + return ret; +} + u32 sceAtracEndEntry() { ERROR_LOG(HLE, "UNIMPL sceAtracEndEntry()"); @@ -896,6 +911,39 @@ int64_t _AtracSeekbuffer(void *opaque, int64_t offset, int whence) #endif // USE_FFMPEG +#ifdef USE_FFMPEG +int __AtracUpdateOutputMode(Atrac *atrac, int wanted_channels) { + if (atrac->pSwrCtx && atrac->atracOutputChannels == wanted_channels) + return 0; + atrac->atracOutputChannels = wanted_channels; + int64_t wanted_channel_layout = av_get_default_channel_layout(wanted_channels); + int64_t dec_channel_layout = av_get_default_channel_layout(atrac->atracChannels); + + atrac->pSwrCtx = + swr_alloc_set_opts + ( + atrac->pSwrCtx, + wanted_channel_layout, + AV_SAMPLE_FMT_S16, + atrac->pCodecCtx->sample_rate, + dec_channel_layout, + atrac->pCodecCtx->sample_fmt, + atrac->pCodecCtx->sample_rate, + 0, + NULL + ); + if (!atrac->pSwrCtx) { + ERROR_LOG(HLE, "swr_alloc_set_opts: Could not allocate resampler context"); + return -1; + } + if (swr_init(atrac->pSwrCtx) < 0) { + ERROR_LOG(HLE, "swr_init: Failed to initialize the resampling context"); + return -1; + } + return 0; +} +#endif // USE_FFMPEG + int __AtracSetContext(Atrac *atrac) { if (atrac->codeType == PSP_MODE_AT_3_PLUS) { @@ -938,31 +986,8 @@ int __AtracSetContext(Atrac *atrac) return -1; } - int wanted_channels = atrac->atracOutputChannels; - int64_t wanted_channel_layout = av_get_default_channel_layout(wanted_channels); - int64_t dec_channel_layout = av_get_default_channel_layout(atrac->atracChannels); - - atrac->pSwrCtx = - swr_alloc_set_opts - ( - NULL, - wanted_channel_layout, - AV_SAMPLE_FMT_S16, - atrac->pCodecCtx->sample_rate, - dec_channel_layout, - atrac->pCodecCtx->sample_fmt, - atrac->pCodecCtx->sample_rate, - 0, - NULL - ); - if (!atrac->pSwrCtx) { - ERROR_LOG(HLE, "swr_alloc_set_opts: Could not allocate resampler context %d", ret); - return -1; - } - if ((ret = swr_init(atrac->pSwrCtx)) < 0) { - ERROR_LOG(HLE, "swr_init: Failed to initialize the resampling context %d", ret); - return -1; - } + if ((ret = __AtracUpdateOutputMode(atrac, atrac->atracOutputChannels)) < 0) + return ret; // alloc audio frame atrac->pFrame = avcodec_alloc_frame(); @@ -1232,15 +1257,66 @@ int sceAtracSetAA3DataAndGetID(u32 buffer, int bufferSize, int fileSize, u32 met return createAtrac(atrac); } +int _AtracGetIDByContext(u32 contextAddr) { + int atracID = (int)Memory::Read_U32(contextAddr + 0xfc); +#ifdef USE_FFMPEG + Atrac *atrac = getAtrac(atracID); + if (atrac) + __AtracUpdateOutputMode(atrac, 1); +#endif // USE_FFMPEG + return atracID; +} + +void _AtracGenarateContext(Atrac *atrac, SceAtracId *context) { + context->info.buffer = atrac->first.addr; + context->info.bufferByte = atrac->atracBufSize; + context->info.codec = atrac->codeType; + context->info.loopNum = atrac->loopNum; + context->info.loopStart = atrac->loopStartSample > 0 ? atrac->loopStartSample : 0; + context->info.loopEnd = atrac->loopEndSample > 0 ? atrac->loopEndSample : 0; + if (atrac->first.size >= atrac->first.fileoffset) { + // state 2, all data loaded + context->info.state = 2; + } else if (atrac->loopinfoNum == 0) { + // state 3, lack some data, no loop info + context->info.state = 3; + } else { + // state 6, lack some data, has loop info + context->info.state = 6; + } + context->info.samplesPerChan = (atrac->codeType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + context->info.sampleSize = atrac->atracBytesPerFrame; + context->info.numChan = atrac->atracChannels; + context->info.dataOff = atrac->firstSampleoffset; + context->info.endSample = atrac->endSample; + context->info.dataEnd = atrac->first.filesize; + context->info.curOff = atrac->first.size; + context->info.streamDataByte = atrac->first.size - atrac->firstSampleoffset; + + u8* buf = (u8*)context; + *(u32*)(buf + 0xfc) = atrac->atracID; +} + int _sceAtracGetContextAddress(int atracID) { ERROR_LOG(HLE, "UNIMPL _sceAtracGetContextAddress(%i)", atracID); Atrac *atrac = getAtrac(atracID); if (!atrac) { // Sol Trigger requires return -1 otherwise hangup . - return -1; + return 0; } - return 0; + if (!atrac->atracContext) { + // allocate a new atracContext + u32 contextsize = 256; + atrac->atracContext = kernelMemory.Alloc(contextsize, false, "Atrac Context"); + if (atrac->atracContext) + Memory::Memset(atrac->atracContext, 0, 256); + } + SceAtracId *context = (SceAtracId*)Memory::GetPointer(atrac->atracContext); + if (context) + _AtracGenarateContext(atrac, context); + INFO_LOG(HLE, "atracContext: %08x", atrac->atracContext); + return atrac->atracContext; } static u8 at3Header[] ={0x52,0x49,0x46,0x46,0x3b,0xbe,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x20,0x00,0x00,0x00,0x70,0x02,0x02,0x00,0x44,0xac,0x00,0x00,0x4d,0x20,0x00,0x00,0xc0,0x00,0x00,0x00,0x0e,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x64,0x61,0x74,0x61,0xc0,0xbd,0x00,0x00}; diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index f967991188..71e2b801d9 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -17,9 +17,54 @@ #pragma once +#include "sceAudiocodec.h" + class PointerWrap; void Register_sceAtrac3plus(); void __AtracInit(); void __AtracDoState(PointerWrap &p); -void __AtracShutdown(); \ No newline at end of file +void __AtracShutdown(); + +typedef struct +{ + u32 decodePos; // 0 + u32 endSample; // 4 + u32 loopStart; // 8 + u32 loopEnd; // 12 + int samplesPerChan; // 16 + char numFrame; // 20 + // 2: all the stream data on the buffer + // 6: looping -> second buffer needed + char state; // 21 + char unk22; + char numChan; // 23 + u16 sampleSize; // 24 + u16 codec; // 26 + u32 dataOff; // 28 + u32 curOff; // 32 + u32 dataEnd; // 36 + int loopNum; // 40 + u32 streamDataByte; // 44 + u32 unk48; + u32 unk52; + u32 buffer; // 56 + u32 secondBuffer; // 60 + u32 bufferByte; // 64 + u32 secondBufferByte; // 68 + // make sure the size is 128 + u8 unk[56]; +} SceAtracIdInfo; + +typedef struct +{ + // size 128 + SceAudiocodecCodec codec; + // size 128 + SceAtracIdInfo info; +} SceAtracId; + +// provide some decoder interface + +u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int *remains); +int _AtracGetIDByContext(u32 contextAddr); \ No newline at end of file From 3c13b574e3aace07f0e3e0d370a2de8808a58ca7 Mon Sep 17 00:00:00 2001 From: oioitff Date: Sun, 9 Jun 2013 01:34:38 +0800 Subject: [PATCH 4/8] Partly implement __sceSasSetVoiceATRAC3. Fix Sol Trigger hang up issue. --- Core/HLE/sceSas.cpp | 12 +++++++++--- Core/HW/SasAudio.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ Core/HW/SasAudio.h | 15 +++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 9c2f9ba0e8..798801ea93 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -432,8 +432,14 @@ u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) { return 0; } -u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context) { - ERROR_LOG_REPORT(HLE, "UNIMPL __sceSasSetVoiceATRAC3(%08x, %i, %i)", core, voice, atrac3Context); +u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { + INFO_LOG_REPORT(HLE, "__sceSasSetVoiceATRAC3(%08x, %i, %08x)", core, voiceNum, atrac3Context); + SasVoice &v = sas->voices[voiceNum]; + u32 prevPcmAddr = v.pcmAddr; + v.type = VOICETYPE_ATRAC3; + v.loop = false; + v.playing = true; + v.atrac3.setContext(atrac3Context); return 0; } @@ -478,7 +484,7 @@ const HLEFunction sceSasCore[] = {0xe855bf76, WrapU_UU, "__sceSasSetOutputmode"}, {0x07f58c24, WrapU_UU, "__sceSasGetAllEnvelopeHeights"}, {0xE1CD9561, WrapU_UIUII, "__sceSasSetVoicePCM"}, - {0x4AA9EAD6, WrapU_UII<__sceSasSetVoiceATRAC3>,"__sceSasSetVoiceATRAC3"}, + {0x4AA9EAD6, WrapU_UIU<__sceSasSetVoiceATRAC3>,"__sceSasSetVoiceATRAC3"}, {0x7497EA85, WrapU_UIUI<__sceSasConcatenateATRAC3>,"__sceSasConcatenateATRAC3"}, {0xF6107F00, WrapU_UI<__sceSasUnsetATRAC3>,"__sceSasUnsetATRAC3"}, }; diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 86ae5b87bf..c4ad931237 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -18,6 +18,7 @@ #include "base/basictypes.h" #include "../Globals.h" #include "../MemMap.h" +#include "Core/HLE/sceAtrac.h" #include "SasAudio.h" // #define AUDIO_TO_FILE @@ -152,6 +153,37 @@ void VagDecoder::DoState(PointerWrap &p) p.Do(end_); } +int SasAtrac3::setContext(u32 context) { + contextAddr = context; + atracID = _AtracGetIDByContext(context); + sampleQueue.clear(); + return 0; +} + +int SasAtrac3::getNextSamples(s16* outbuf, int wantedSamples) { + if (atracID < 0) + return -1; + u32 finish = 0; + int wantedbytes = wantedSamples * sizeof(s16); + while (!finish && sampleQueue.getQueueSize() < wantedbytes) { + u32 numSamples = 0; + int remains = 0; + static s16 buf[0x800]; + _AtracDecodeData(atracID, (u8*)buf, &numSamples, &finish, &remains); + if (numSamples > 0) + sampleQueue.push((u8*)buf, numSamples * sizeof(s16)); + else + finish = 1; + } + sampleQueue.pop_front((u8*)outbuf, wantedbytes); + return finish; +} + +void SasAtrac3::DoState(PointerWrap &p) { + p.Do(contextAddr); + p.Do(atracID); +} + // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java int simpleRate(int n) { @@ -340,6 +372,16 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) { } } break; + case VOICETYPE_ATRAC3: + { + int ret = voice.atrac3.getNextSamples(resampleBuffer + 2, numSamples); + if (ret) { + // Hit atrac3 voice end + voice.playing = false; + voice.on = false; // ?? + } + } + break; default: { memset(resampleBuffer + 2, 0, numSamples * sizeof(s16)); @@ -529,6 +571,7 @@ void SasVoice::DoState(PointerWrap &p) envelope.DoState(p); vag.DoState(p); + atrac3.DoState(p); } // This is horribly stolen from JPCSP. diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 7ee4c18ba0..5e6916e263 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -25,6 +25,8 @@ #include "../Globals.h" #include "ChunkFile.h" +#include "Core/HW/atrac3plus.h" + enum { PSP_SAS_VOICES_MAX = 32, @@ -106,6 +108,18 @@ private: bool end_; }; +class SasAtrac3 { +public: + SasAtrac3() : contextAddr(0), atracID(-1){} + int setContext(u32 context); + int getNextSamples(s16* outbuf, int wantedSamples); + void DoState(PointerWrap &p); +private: + u32 contextAddr; + int atracID; + Atrac3plus_Decoder::BufferQueue sampleQueue; +}; + // Max height: 0x40000000 I think class ADSREnvelope { @@ -218,6 +232,7 @@ struct SasVoice ADSREnvelope envelope; VagDecoder vag; + SasAtrac3 atrac3; }; class SasInstance From f03ae843d2fb931687fadda576473ec4156380f3 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Sat, 8 Jun 2013 19:48:10 +0200 Subject: [PATCH 5/8] Add ffmpeg in SDL build --- CMakeLists.txt | 3 +++ README.md | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04d732c097..ee4c4f8a1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -477,6 +477,9 @@ elseif(SDL_FOUND) elseif(PANDORA OR MAEMO) set(nativeExtraLibs ${nativeExtraLibs} pthread EGL X11) endif() + # FFMPEG + add_definitions(-DUSE_FFMPEG) + set(nativeExtraLibs ${nativeExtraLibs} avformat avcodec swresample swscale) set(TargetBin PPSSPPSDL) else() message(FATAL_ERROR "Could not find SDL. Failing.") diff --git a/README.md b/README.md index 527dc0b390..6351b74f86 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ Building for Linux/BSD/Meego Harmattan/Pandora/etc -------------------------- Qt (recommended) + A Qt-based frontend is available in the Qt/ dir. Open PPSSPPQt.pro with [Qt Creator 2.6+][qt-creator]. Install libsdl1.2 if you want to use USB Gamepad. @@ -92,9 +93,12 @@ If the build has an error about finding mobility or multimedia: - Install the package "qtmobility-dev" SDL + Alternatively, install the libsdl1.2 (SDL 1.2) development headers. This is called `libsdl1.2-dev` on Debian/Ubuntu, `SDL-devel` on Fedora/RHEL, `sdl12` on BSD ports. +You will need a recent version of ffmpeg (1.1 or greater, which means libav 9.1 or greater probably) or development packets (for distributions with separate packets) for libavformat, libavcodec, libswresample and libswscale (still version 9.1 or greater). + Currently the user interface is identical to Android's, operated with the mouse. From 883d60fad3d4349fb3a2bd6e7e158ff3cec6a23e Mon Sep 17 00:00:00 2001 From: oioitff Date: Sun, 9 Jun 2013 01:58:06 +0800 Subject: [PATCH 6/8] Use a pointer for sampleQueue in SasAtrac3. --- Core/HW/SasAudio.cpp | 13 +++++++++---- Core/HW/SasAudio.h | 5 +++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index c4ad931237..88f6181acf 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -156,7 +156,9 @@ void VagDecoder::DoState(PointerWrap &p) int SasAtrac3::setContext(u32 context) { contextAddr = context; atracID = _AtracGetIDByContext(context); - sampleQueue.clear(); + if (!sampleQueue) + sampleQueue = new Atrac3plus_Decoder::BufferQueue; + sampleQueue->clear(); return 0; } @@ -165,23 +167,26 @@ int SasAtrac3::getNextSamples(s16* outbuf, int wantedSamples) { return -1; u32 finish = 0; int wantedbytes = wantedSamples * sizeof(s16); - while (!finish && sampleQueue.getQueueSize() < wantedbytes) { + while (!finish && sampleQueue->getQueueSize() < wantedbytes) { u32 numSamples = 0; int remains = 0; static s16 buf[0x800]; _AtracDecodeData(atracID, (u8*)buf, &numSamples, &finish, &remains); if (numSamples > 0) - sampleQueue.push((u8*)buf, numSamples * sizeof(s16)); + sampleQueue->push((u8*)buf, numSamples * sizeof(s16)); else finish = 1; } - sampleQueue.pop_front((u8*)outbuf, wantedbytes); + sampleQueue->pop_front((u8*)outbuf, wantedbytes); return finish; } void SasAtrac3::DoState(PointerWrap &p) { p.Do(contextAddr); p.Do(atracID); + if (p.mode == p.MODE_READ && atracID >= 0 && !sampleQueue) { + sampleQueue = new Atrac3plus_Decoder::BufferQueue; + } } // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 5e6916e263..0026053d87 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -110,14 +110,15 @@ private: class SasAtrac3 { public: - SasAtrac3() : contextAddr(0), atracID(-1){} + SasAtrac3() : contextAddr(0), atracID(-1), sampleQueue(0){} + ~SasAtrac3() { if (sampleQueue) delete sampleQueue; } int setContext(u32 context); int getNextSamples(s16* outbuf, int wantedSamples); void DoState(PointerWrap &p); private: u32 contextAddr; int atracID; - Atrac3plus_Decoder::BufferQueue sampleQueue; + Atrac3plus_Decoder::BufferQueue *sampleQueue; }; // Max height: 0x40000000 I think From bfb66cc2ab718d7f0545537a120a7933d190f30c Mon Sep 17 00:00:00 2001 From: oioitff Date: Sun, 9 Jun 2013 02:27:30 +0800 Subject: [PATCH 7/8] Scale volume in sceP3daBridgeCore and avoid overflow. --- Core/HLE/sceP3da.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceP3da.cpp b/Core/HLE/sceP3da.cpp index dd189784a4..7ad09d69e2 100644 --- a/Core/HLE/sceP3da.cpp +++ b/Core/HLE/sceP3da.cpp @@ -31,10 +31,20 @@ u32 sceP3daBridgeExit() return 0; } +static inline int getScaleValue(u32 channelsNum) { + int val = 0; + while (channelsNum > 1) { + channelsNum >>= 1; + val++; + } + return val; +} + u32 sceP3daBridgeCore(u32 p3daCoreAddr, u32 channelsNum, u32 samplesNum, u32 inputAddr, u32 outputAddr) { INFO_LOG(HLE, "sceP3daBridgeCore(%08x, %08x, %08x, %08x, %08x)", p3daCoreAddr, channelsNum, samplesNum, inputAddr, outputAddr); if (Memory::IsValidAddress(inputAddr) && Memory::IsValidAddress(outputAddr)) { + int scaleval = getScaleValue(channelsNum); s16* outbuf = (s16*)Memory::GetPointer(outputAddr); memset(outbuf, 0, samplesNum * sizeof(s16) * 2); for (u32 k = 0; k < channelsNum; k++) { @@ -43,8 +53,9 @@ u32 sceP3daBridgeCore(u32 p3daCoreAddr, u32 channelsNum, u32 samplesNum, u32 inp if (!inbuf) continue; for (u32 i = 0; i < samplesNum; i++) { - outbuf[i*2] += inbuf[i]; - outbuf[i*2 + 1] += inbuf[i]; + s16 sample = inbuf[i] >> scaleval; + outbuf[i*2] += sample; + outbuf[i*2 + 1] += sample; } } } From f0cdc230d0a7eae9cb21db672e7823314c269cc2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 8 Jun 2013 12:30:40 -0700 Subject: [PATCH 8/8] Savestate the context thing properly. Just to make sure we don't leak kernel memory on load state. --- Core/HLE/sceAtrac.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 57bf7fb38b..caabe6d04b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -104,7 +104,7 @@ struct AtracLoopInfo { struct Atrac { Atrac() : atracID(-1), data_buf(0), decodePos(0), decodeEnd(0), atracChannels(2), atracOutputChannels(2), atracBitrate(64), atracBytesPerFrame(0), atracBufSize(0), - currentSample(0), endSample(-1), firstSampleoffset(0), loopinfoNum(0), loopNum(0), atracContext(0) { + currentSample(0), endSample(-1), firstSampleoffset(0), loopinfoNum(0), loopNum(0) { memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(second)); #ifdef USE_FFMPEG @@ -115,6 +115,7 @@ struct Atrac { pFrame = 0; #endif // USE_FFMPEG decoder_context = 0; + atracContext = 0; sampleQueue.clear(); } @@ -134,8 +135,8 @@ struct Atrac { Atrac3plus_Decoder::CloseContext(&decoder_context); sampleQueue.clear(); - if (atracContext) - kernelMemory.Free(atracContext); + if (atracContext.Valid()) + kernelMemory.Free(atracContext.ptr); } void DoState(PointerWrap &p) { @@ -177,6 +178,11 @@ struct Atrac { p.Do(loopEndSample); p.Do(loopNum); + // Is NULL okay for this? + if (p.mode == p.MODE_READ) + decoder_context = 0; + p.Do(atracContext); + p.DoMarker("Atrac"); } @@ -235,7 +241,7 @@ struct Atrac { Atrac3plus_Decoder::BufferQueue sampleQueue; void* decoder_context; - u32 atracContext; + PSPPointer atracContext; #ifdef USE_FFMPEG AVFormatContext *pFormatCtx; @@ -574,7 +580,7 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int } else { numSamples = atrac->endSample - atrac->currentSample; - int atracSamplesPerFrame = (atrac->codeType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + u32 atracSamplesPerFrame = (atrac->codeType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); if (atrac->currentSample >= atrac->endSample) { numSamples = 0; } else if (numSamples > atracSamplesPerFrame) { @@ -771,7 +777,7 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr) Memory::Write_U32(0, outNAddr); } else { u32 numSamples = atrac->endSample - atrac->currentSample; - int atracSamplesPerFrame = (atrac->codeType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + u32 atracSamplesPerFrame = (atrac->codeType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); if (numSamples > atracSamplesPerFrame) numSamples = atracSamplesPerFrame; if (Memory::IsValidAddress(outNAddr)) @@ -1299,24 +1305,25 @@ void _AtracGenarateContext(Atrac *atrac, SceAtracId *context) { int _sceAtracGetContextAddress(int atracID) { - ERROR_LOG(HLE, "UNIMPL _sceAtracGetContextAddress(%i)", atracID); Atrac *atrac = getAtrac(atracID); if (!atrac) { - // Sol Trigger requires return -1 otherwise hangup . + ERROR_LOG(HLE, "_sceAtracGetContextAddress(%i): bad atrac id", atracID); return 0; } - if (!atrac->atracContext) { + if (!atrac->atracContext.Valid()) { // allocate a new atracContext u32 contextsize = 256; atrac->atracContext = kernelMemory.Alloc(contextsize, false, "Atrac Context"); - if (atrac->atracContext) - Memory::Memset(atrac->atracContext, 0, 256); + if (atrac->atracContext.Valid()) + Memory::Memset(atrac->atracContext.ptr, 0, 256); + + WARN_LOG(HLE, "%08x=_sceAtracGetContextAddress(%i): allocated new context", atrac->atracContext.ptr, atracID); } - SceAtracId *context = (SceAtracId*)Memory::GetPointer(atrac->atracContext); - if (context) - _AtracGenarateContext(atrac, context); - INFO_LOG(HLE, "atracContext: %08x", atrac->atracContext); - return atrac->atracContext; + else + WARN_LOG(HLE, "%08x=_sceAtracGetContextAddress(%i)", atrac->atracContext.ptr, atracID); + if (atrac->atracContext.Valid()) + _AtracGenarateContext(atrac, atrac->atracContext); + return atrac->atracContext.ptr; } static u8 at3Header[] ={0x52,0x49,0x46,0x46,0x3b,0xbe,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x20,0x00,0x00,0x00,0x70,0x02,0x02,0x00,0x44,0xac,0x00,0x00,0x4d,0x20,0x00,0x00,0xc0,0x00,0x00,0x00,0x0e,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x64,0x61,0x74,0x61,0xc0,0xbd,0x00,0x00};