diff --git a/CMakeLists.txt b/CMakeLists.txt
index c766a7d657..4a0112137f 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.")
@@ -758,6 +761,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceAtrac.cpp
Core/HLE/sceAtrac.h
Core/HLE/sceAudio.cpp
+ Core/HLE/sceAudioCodec.cpp
+ Core/HLE/sceAudioCodec.h
Core/HLE/sceAudio.h
Core/HLE/sceChnnlsv.cpp
Core/HLE/sceChnnlsv.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/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp
index f70800df9b..caabe6d04b 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
@@ -113,6 +115,7 @@ struct Atrac {
pFrame = 0;
#endif // USE_FFMPEG
decoder_context = 0;
+ atracContext = 0;
sampleQueue.clear();
}
@@ -131,6 +134,9 @@ struct Atrac {
Atrac3plus_Decoder::CloseContext(&decoder_context);
sampleQueue.clear();
+
+ if (atracContext.Valid())
+ kernelMemory.Free(atracContext.ptr);
}
void DoState(PointerWrap &p) {
@@ -172,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");
}
@@ -230,6 +241,8 @@ struct Atrac {
Atrac3plus_Decoder::BufferQueue sampleQueue;
void* decoder_context;
+ PSPPointer atracContext;
+
#ifdef USE_FFMPEG
AVFormatContext *pFormatCtx;
AVIOContext *pAVIOCtx;
@@ -483,18 +496,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 +532,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 +559,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;
@@ -569,7 +580,7 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF
} 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) {
@@ -579,10 +590,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 +608,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()");
@@ -756,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))
@@ -896,6 +917,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 +992,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 +1263,67 @@ 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;
+ ERROR_LOG(HLE, "_sceAtracGetContextAddress(%i): bad atrac id", atracID);
+ return 0;
}
- return 0;
+ if (!atrac->atracContext.Valid()) {
+ // allocate a new atracContext
+ u32 contextsize = 256;
+ atrac->atracContext = kernelMemory.Alloc(contextsize, false, "Atrac Context");
+ if (atrac->atracContext.Valid())
+ Memory::Memset(atrac->atracContext.ptr, 0, 256);
+
+ WARN_LOG(HLE, "%08x=_sceAtracGetContextAddress(%i): allocated new context", atrac->atracContext.ptr, atracID);
+ }
+ 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};
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
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
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;
}
}
}
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..88f6181acf 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,42 @@ void VagDecoder::DoState(PointerWrap &p)
p.Do(end_);
}
+int SasAtrac3::setContext(u32 context) {
+ contextAddr = context;
+ atracID = _AtracGetIDByContext(context);
+ if (!sampleQueue)
+ sampleQueue = new Atrac3plus_Decoder::BufferQueue;
+ 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);
+ 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
int simpleRate(int n) {
@@ -340,6 +377,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 +576,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..0026053d87 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,19 @@ private:
bool end_;
};
+class SasAtrac3 {
+public:
+ 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;
+};
+
// Max height: 0x40000000 I think
class ADSREnvelope
{
@@ -218,6 +233,7 @@ struct SasVoice
ADSREnvelope envelope;
VagDecoder vag;
+ SasAtrac3 atrac3;
};
class SasInstance
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.
diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp
index 51194c2067..2d7741c839 100644
--- a/UI/GameInfoCache.cpp
+++ b/UI/GameInfoCache.cpp
@@ -288,6 +288,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 e428d4f5e7..bb054e3d76 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), paramSFOLoaded(false) {}
+ GameInfo() : fileType(FILETYPE_UNKNOWN), iconTexture(NULL), pic0Texture(NULL), pic1Texture(NULL), wantBG(false), paramSFOLoaded(false) {}
bool DeleteGame(); // Better be sure what you're doing when calling this.
bool DeleteAllSaveData();
@@ -110,4 +110,4 @@ private:
};
// This one can be global, no good reason not to.
-extern GameInfoCache g_gameInfoCache;
\ No newline at end of file
+extern GameInfoCache g_gameInfoCache;
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 014c895b71..818c0fc140 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -216,6 +216,7 @@ LOCAL_SRC_FILES := \
$(SRC)/Core/HLE/sceAtrac.cpp \
$(SRC)/Core/HLE/__sceAudio.cpp \
$(SRC)/Core/HLE/sceAudio.cpp \
+ $(SRC)/Core/HLE/sceAudioCodec.cpp \
$(SRC)/Core/HLE/sceChnnlsv.cpp \
$(SRC)/Core/HLE/sceCtrl.cpp \
$(SRC)/Core/HLE/sceDeflt.cpp \