From b0a3f803e0fd87941bf9a19d6008db619080f783 Mon Sep 17 00:00:00 2001 From: oioitff Date: Thu, 30 May 2013 17:33:47 +0800 Subject: [PATCH] Add support for new atrac3plus decoder --- Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 +++ Core/HLE/sceAtrac.cpp | 104 ++++++++++++++++++++++++++++++++++---- Core/HW/atrac3plus.cpp | 80 +++++++++++++++++++++++++++++ Core/HW/atrac3plus.h | 83 ++++++++++++++++++++++++++++++ 5 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 Core/HW/atrac3plus.cpp create mode 100644 Core/HW/atrac3plus.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index ec889d444..79d047500 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -228,6 +228,7 @@ + @@ -406,6 +407,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index d9be5a458..80e38247a 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -427,6 +427,9 @@ MIPS\JitCommon + + HW + @@ -792,6 +795,9 @@ MIPS\JitCommon + + HW + diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d454ce5ba..0eb32262c 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -78,6 +78,8 @@ extern "C" { #include "../HW/audioPlayer.h" #endif // _USE_DSHOW_ +#include "Core/HW/atrac3plus.h" + struct InputBuffer { u32 addr; u32 size; @@ -114,6 +116,8 @@ struct Atrac { pSwrCtx = 0; pFrame = 0; #endif // USE_FFMPEG + decoder_context = 0; + sampleQueue.empty(); } ~Atrac() { @@ -132,6 +136,9 @@ struct Atrac { if (data_buf) delete [] data_buf; data_buf = 0; + + Atrac3plus_Decoder::closeContext(&decoder_context); + sampleQueue.empty(); } void DoState(PointerWrap &p) { @@ -178,7 +185,8 @@ struct Atrac { void Analyze(); u32 getDecodePosBySample(int sample) { - return (u32)(firstSampleoffset + sample / ATRAC_MAX_SAMPLES * atracBytesPerFrame ); + int atracSamplesPerFrame = (codeType == PSP_MODE_AT_3_PLUS ? 0x800 : 0x400); + return (u32)(firstSampleoffset + sample / atracSamplesPerFrame * atracBytesPerFrame ); } int getRemainFrames() { @@ -227,6 +235,9 @@ struct Atrac { InputBuffer first; InputBuffer second; + Atrac3plus_Decoder::BufferQueue sampleQueue; + void* decoder_context; + #ifdef USE_FFMPEG AVFormatContext *pFormatCtx; AVIOContext *pAVIOCtx; @@ -276,6 +287,7 @@ void __AtracInit() { initaudioEngine(); #endif //_USE_DSHOW_ + Atrac3plus_Decoder::initdecoder(); } void __AtracDoState(PointerWrap &p) { @@ -293,6 +305,8 @@ void __AtracShutdown() { #ifdef _USE_DSHOW_ shutdownEngine(); #endif // _USE_DSHOW_ + + Atrac3plus_Decoder::shutdowndecoder(); } Atrac *getAtrac(int atracID) { @@ -548,6 +562,35 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF } else #endif // USE_FFMPEG + if (atrac->decoder_context) { + static u8 buf[0x8000]; + if (atrac->sampleQueue.getQueueSize() < ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels) { + int decodebytes = 0; + atrac->decodePos = atrac->getDecodePosBySample(atrac->currentSample); + int inbytes = std::max((int)atrac->first.filesize - (int)atrac->decodePos, 0); + inbytes = std::min(inbytes, (int)atrac->atracBytesPerFrame); + if (inbytes > 0) { + Atrac3plus_Decoder::atrac3plus_decode(atrac->decoder_context, atrac->data_buf + atrac->decodePos, inbytes, &decodebytes, buf); + INFO_LOG(HLE, "decodebytes: %i outbuf: %08x", decodebytes, buf); + atrac->sampleQueue.push(buf, decodebytes); + } + } + s16* out = (s16*)Memory::GetPointer(outAddr); + memset(out, 0, ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels); + int gotsize = atrac->sampleQueue.pop_front(buf, ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels); + numSamples = gotsize / sizeof(s16) / atrac->atracChannels; + s16* in = (s16*)buf; + for (int i = 0; i < numSamples; i++) { + s16 sampleL = *in++; + s16 sampleR = sampleL; + if (atrac->atracChannels == 2) + sampleR = *in++; + *out++ = sampleL; + if (atrac->atracOutputChannels == 2) + *out++ = sampleR; + } + numSamples = ATRAC_MAX_SAMPLES; + } else #ifdef _USE_DSHOW_ if (engine) { static s16 buf[ATRAC_MAX_SAMPLES * 2]; @@ -899,6 +942,11 @@ int64_t _AtracSeekbuffer(void *opaque, int64_t offset, int whence) int __AtracSetContext(Atrac *atrac) { + if (atrac->codeType == PSP_MODE_AT_3_PLUS) { + atrac->decoder_context = Atrac3plus_Decoder::openContext(); + return 0; + } + #ifdef _USE_DSHOW_ if (atrac->codeType == PSP_MODE_AT_3_PLUS && atrac->atracChannels != 1) { addAtrac3Audio(atrac->data_buf, atrac->first.size, atrac->atracID); @@ -1007,17 +1055,15 @@ int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) } else if (atrac->codeType == PSP_MODE_AT_3_PLUS) { if (atrac->atracChannels == 1) { - WARN_LOG(HLE, "This is an atrac3+ mono audio (Unsupported)"); + WARN_LOG(HLE, "This is an atrac3+ mono audio"); } else { WARN_LOG(HLE, "This is an atrac3+ stereo audio"); - -#ifdef _USE_DSHOW_ - atrac->data_buf = new u8[atrac->first.filesize]; - Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); - return __AtracSetContext(atrac); -#endif // _USE_DSHOW - } + + atrac->data_buf = new u8[atrac->first.filesize]; + Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); + return __AtracSetContext(atrac); + } @@ -1366,6 +1412,12 @@ int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) return 0; } #endif // USE_FFMPEG + + if (atrac->codeType == PSP_MODE_AT_3_PLUS){ + atrac->data_buf = new u8[atrac->atracBytesPerFrame]; + __AtracSetContext(atrac); + return 0; + } } return 0; } @@ -1432,6 +1484,40 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA } #endif // USE_FFMPEG + if (Memory::IsValidAddress(sourceAddr) && Memory::IsValidAddress(sourceBytesConsumedAddr) && + Memory::IsValidAddress(samplesAddr) && Memory::IsValidAddress(sampleBytesAddr) && atrac && atrac->decoder_context) { + u32 sourcebytes = atrac->first.writableBytes; + static u8 buf[0x8000]; + if (sourcebytes > 0) { + int decodebytes = 0; + Atrac3plus_Decoder::atrac3plus_decode(atrac->decoder_context, Memory::GetPointer(sourceAddr), sourcebytes, &decodebytes, buf); + atrac->sampleQueue.push(buf, decodebytes); + } + s16* out = (s16*)Memory::GetPointer(samplesAddr); + memset(out, 0, ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels); + int gotsize = atrac->sampleQueue.pop_front(buf, ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels); + int numSamples = gotsize / sizeof(s16) / atrac->atracChannels; + s16* in = (s16*)buf; + for (int i = 0; i < numSamples; i++) { + s16 sampleL = *in++; + s16 sampleR = sampleL; + if (atrac->atracChannels == 2) + sampleR = *in++; + *out++ = sampleL; + if (atrac->atracOutputChannels == 2) + *out++ = sampleR; + } + numSamples = ATRAC_MAX_SAMPLES; + Memory::Write_U32(numSamples * sizeof(s16) * atrac->atracOutputChannels, sampleBytesAddr); + int space = atrac->sampleQueue.getQueueSize(); + if (space < ATRAC_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels) + atrac->first.writableBytes = atrac->atracBytesPerFrame; + else + atrac->first.writableBytes = 0; + Memory::Write_U32(atrac->first.writableBytes, sourceBytesConsumedAddr); + return 0; + } + #ifdef _USE_DSHOW_ if (Memory::IsValidAddress(sourceAddr) && Memory::IsValidAddress(sourceBytesConsumedAddr) && atrac) { u32 sourcebytes = Memory::Read_U32(sourceBytesConsumedAddr); diff --git a/Core/HW/atrac3plus.cpp b/Core/HW/atrac3plus.cpp new file mode 100644 index 000000000..1bb366577 --- /dev/null +++ b/Core/HW/atrac3plus.cpp @@ -0,0 +1,80 @@ + +#ifdef _WIN32 +#include +#endif // _WIN32 + +#include + +namespace Atrac3plus_Decoder { + +#ifdef _WIN32 + HMODULE hlib = 0; +#endif // _WIN32 + + typedef int (* ATRAC3PLUS_DECODEFRAME)(void* context, void* inbuf, int inbytes, int* channels, void** outbuf); + typedef void* (* ATRAC3PLUS_OPENCONTEXT)(); + typedef int (* ATRAC3PLUS_CLOSECONTEXT)(void* context); + ATRAC3PLUS_DECODEFRAME frame_decoder = 0; + ATRAC3PLUS_OPENCONTEXT open_context = 0; + ATRAC3PLUS_CLOSECONTEXT close_context = 0; + + int initdecoder() { + +#ifdef _WIN32 + hlib = LoadLibraryA("MaiAT3PlusDecoder.dll"); + if (hlib) { + frame_decoder = (ATRAC3PLUS_DECODEFRAME)GetProcAddress(hlib, "Atrac3plusDecoder_decodeFrame"); + open_context = (ATRAC3PLUS_OPENCONTEXT)GetProcAddress(hlib, "Atrac3plusDecoder_openContext"); + close_context = (ATRAC3PLUS_CLOSECONTEXT)GetProcAddress(hlib, "Atrac3plusDecoder_closeContext"); + } else { + return -1; + } +#endif // _WIN32 + + return 0; + } + + int shutdowndecoder() { + +#ifdef _WIN32 + if (hlib) { + FreeLibrary(hlib); + hlib = 0; + } +#endif // _WIN32 + + return 0; + } + + void* openContext() { + if (!open_context) + return 0; + return open_context(); + } + + int closeContext(void** context) { + if (!close_context || !context) + return 0; + close_context(*context); + *context = 0; + return 0; + } + + bool atrac3plus_decode(void* context, void* inbuf, int inbytes, int *outbytes, void* outbuf) { + if (!frame_decoder) { + *outbytes = 0; + return false; + } + int channels = 0; + void* buf; + int ret = frame_decoder(context, inbuf, inbytes, &channels, &buf); + if (ret != 0) { + *outbytes = 0; + return false; + } + *outbytes = channels * 2 * 0x800; + memcpy(outbuf, buf, *outbytes); + return true; + } + +} // Atrac3plus_Decoder \ No newline at end of file diff --git a/Core/HW/atrac3plus.h b/Core/HW/atrac3plus.h new file mode 100644 index 000000000..018233507 --- /dev/null +++ b/Core/HW/atrac3plus.h @@ -0,0 +1,83 @@ +#ifndef _ATRAC3PLUS_DECODER_ +#define _ATRAC3PLUS_DECODER_ + +namespace Atrac3plus_Decoder { + int initdecoder(); + int shutdowndecoder(); + + void* openContext(); + int closeContext(void** context); + bool atrac3plus_decode(void* context, void* inbuf, int inbytes, int *outbytes, void* outbuf); + + struct BufferQueue { + BufferQueue(int size = 0x20000) { + bufQueue = 0; + alloc(size); + } + + ~BufferQueue() { + if (bufQueue) + delete [] bufQueue; + } + + bool alloc(int size) { + if (size < 0) + return false; + if (bufQueue) + delete [] bufQueue; + bufQueue = new unsigned char[size]; + start = 0; + end = 0; + bufQueueSize = size; + return true; + } + + void empty() { + start = 0; + end = 0; + } + + inline int getQueueSize() { + return (end + bufQueueSize - start) % bufQueueSize; + } + + bool push(unsigned char *buf, int addsize) { + int queuesz = getQueueSize(); + int space = bufQueueSize - queuesz; + if (space < addsize || addsize < 0) + return false; + if (end + addsize <= bufQueueSize) { + memcpy(bufQueue + end, buf, addsize); + } else { + int size = bufQueueSize - end; + memcpy(bufQueue + end, buf, size); + memcpy(bufQueue, buf + size, addsize - size); + } + end = (end + addsize) % bufQueueSize; + return true; + } + + int pop_front(unsigned char *buf, int wantedsize) { + if (wantedsize <= 0) + return 0; + int bytesgot = getQueueSize(); + if (wantedsize < bytesgot) + bytesgot = wantedsize; + if (start + bytesgot <= bufQueueSize) { + memcpy(buf, bufQueue + start, bytesgot); + } else { + int size = bufQueueSize - start; + memcpy(buf, bufQueue + start, size); + memcpy(buf + size, bufQueue, bytesgot - size); + } + start = (start + bytesgot) % bufQueueSize; + return bytesgot; + } + + unsigned char* bufQueue; + int start, end; + int bufQueueSize; + }; +} + +#endif // _ATRAC3PLUS_DECODER_ \ No newline at end of file