#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/Log.h"
#include "Core/Reporting.h"
#include "Core/MemMapHelpers.h"
#include "Core/System.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/ErrorCodes.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceAtrac.h"
#include "Core/HLE/AtracCtx.h"
#include "Core/HW/Atrac3Standalone.h"
#include "Core/HLE/sceKernelMemory.h"
const size_t overAllocBytes = 16384;
Atrac::~Atrac() {
ResetData();
}
void Atrac::DoState(PointerWrap &p) {
auto s = p.Section("Atrac", 1, 9);
if (!s)
return;
Do(p, track_.channels);
Do(p, outputChannels_);
if (s >= 5) {
Do(p, track_.jointStereo);
}
Do(p, atracID_);
if (p.mode != p.MODE_READ) {
first_._filesize_dontuse = track_.fileSize;
}
Do(p, first_);
if (p.mode == p.MODE_READ) {
track_.fileSize = first_._filesize_dontuse;
}
Do(p, bufferMaxSize_);
Do(p, track_.codecType);
Do(p, currentSample_);
Do(p, track_.endSample);
Do(p, track_.firstSampleOffset);
if (s >= 3) {
Do(p, track_.dataByteOffset);
} else {
track_.dataByteOffset = track_.firstSampleOffset;
}
u32 hasDataBuf = dataBuf_ != nullptr;
Do(p, hasDataBuf);
if (hasDataBuf) {
if (p.mode == p.MODE_READ) {
if (dataBuf_)
delete[] dataBuf_;
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
}
DoArray(p, dataBuf_, track_.fileSize);
}
Do(p, second_);
Do(p, decodePos_);
if (s < 9) {
u32 oldDecodeEnd = 0;
Do(p, oldDecodeEnd);
}
if (s >= 4) {
Do(p, bufferPos_);
} else {
bufferPos_ = decodePos_;
}
Do(p, track_.bitrate);
Do(p, track_.bytesPerFrame);
Do(p, track_.loopinfo);
if (s < 9) {
int oldLoopInfoNum = 42;
Do(p, oldLoopInfoNum);
}
Do(p, track_.loopStartSample);
Do(p, track_.loopEndSample);
Do(p, loopNum_);
Do(p, context_);
if (s >= 6) {
Do(p, bufferState_);
} else {
if (dataBuf_ == nullptr) {
bufferState_ = ATRAC_STATUS_NO_DATA;
} else {
UpdateBufferState();
}
}
if (s >= 7) {
Do(p, ignoreDataBuf_);
} else {
ignoreDataBuf_ = false;
}
if (s >= 9) {
Do(p, bufferValidBytes_);
Do(p, bufferHeaderSize_);
} else {
bufferHeaderSize_ = track_.dataByteOffset;
bufferValidBytes_ = std::min(first_.size - track_.dataByteOffset, StreamBufferEnd() - track_.dataByteOffset);
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
bufferPos_ = track_.dataByteOffset;
}
}
if (s < 8 && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
}
if (p.mode == p.MODE_READ && bufferState_ != ATRAC_STATUS_NO_DATA) {
CreateDecoder(track_.codecType, track_.bytesPerFrame, track_.channels);
}
if (s >= 2 && s < 9) {
bool oldResetBuffer = false;
Do(p, oldResetBuffer);
}
}
void Atrac::ResetData() {
delete decoder_;
decoder_ = nullptr;
if (dataBuf_)
delete[] dataBuf_;
dataBuf_ = 0;
ignoreDataBuf_ = false;
bufferState_ = ATRAC_STATUS_NO_DATA;
if (context_.IsValid())
kernelMemory.Free(context_.ptr);
}
u8 *Atrac::BufferStart() {
return ignoreDataBuf_ ? Memory::GetPointerWrite(first_.addr) : dataBuf_;
}
AtracBase::~AtracBase() {
delete decoder_;
}
void Atrac::UpdateContextFromPSPMem() {
if (!context_.IsValid()) {
return;
}
bufferState_ = context_->info.state;
loopNum_ = context_->info.loopNum;
}
void Atrac::WriteContextToPSPMem() {
if (!context_.IsValid()) {
return;
}
SceAtracContext *context = context_;
context->info.buffer = first_.addr;
context->info.bufferByte = bufferMaxSize_;
context->info.secondBuffer = second_.addr;
context->info.secondBufferByte = second_.size;
context->info.codec = track_.codecType;
context->info.loopNum = loopNum_;
context->info.loopStart = track_.loopStartSample > 0 ? track_.loopStartSample : 0;
context->info.loopEnd = track_.loopEndSample > 0 ? track_.loopEndSample : 0;
context->info.state = bufferState_;
if (track_.firstSampleOffset != 0) {
context->info.firstValidSample = track_.FirstSampleOffsetFull();
} else {
context->info.firstValidSample = (track_.codecType == PSP_CODEC_AT3PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
}
context->info.sampleSize = track_.bytesPerFrame;
context->info.numChan = track_.channels;
context->info.dataOff = track_.dataByteOffset;
context->info.endSample = track_.endSample + track_.FirstSampleOffsetFull();
context->info.fileDataEnd = track_.fileSize;
context->info.curFileOff = first_.fileoffset;
context->info.decodePos = track_.DecodePosBySample(currentSample_);
context->info.streamDataByte = first_.size - track_.dataByteOffset;
u8 *buf = (u8 *)context;
*(u32_le *)(buf + 0xfc) = atracID_;
NotifyMemInfo(MemBlockFlags::WRITE, context_.ptr, sizeof(SceAtracContext), "AtracContext");
}
void Track::DebugLog() const {
DEBUG_LOG(Log::Atrac, "ATRAC analyzed: %s channels: %d filesize: %d bitrate: %d kbps jointStereo: %d",
codecType == PSP_CODEC_AT3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo);
DEBUG_LOG(Log::Atrac, "dataoff: %d firstSampleOffset: %d endSample: %d", dataByteOffset, firstSampleOffset, endSample);
DEBUG_LOG(Log::Atrac, "loopStartSample: %d loopEndSample: %d", loopStartSample, loopEndSample);
DEBUG_LOG(Log::Atrac, "sampleSize: %d (%03x)", bytesPerFrame, bytesPerFrame);
}
int Atrac::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const {
*endSample = track_.endSample;
*loopStartSample = track_.loopStartSample == -1 ? -1 : track_.loopStartSample - track_.FirstSampleOffsetFull();
*loopEndSample = track_.loopEndSample == -1 ? -1 : track_.loopEndSample - track_.FirstSampleOffsetFull();
return 0;
}
int Atrac::GetNextDecodePosition(int *pos) const {
if (currentSample_ >= track_.endSample) {
*pos = 0;
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
} else {
*pos = currentSample_;
return 0;
}
}
void Atrac::CalculateStreamInfo(u32 *outReadOffset) {
u32 readOffset = first_.fileoffset;
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
readOffset = 0;
first_.offset = 0;
first_.writableBytes = 0;
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
first_.offset = readOffset;
first_.writableBytes = track_.fileSize - readOffset;
} else {
u32 bufferEnd = StreamBufferEnd();
u32 bufferValidExtended = bufferPos_ + bufferValidBytes_;
if (bufferValidExtended < bufferEnd) {
first_.offset = bufferValidExtended;
first_.writableBytes = bufferEnd - bufferValidExtended;
} else {
u32 bufferStartUsed = bufferValidExtended - bufferEnd;
first_.offset = bufferStartUsed;
first_.writableBytes = bufferPos_ - bufferStartUsed;
}
if (readOffset >= track_.fileSize) {
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
readOffset = 0;
first_.offset = 0;
first_.writableBytes = 0;
} else {
readOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
}
}
if (readOffset + first_.writableBytes > track_.fileSize) {
first_.writableBytes = track_.fileSize - readOffset;
}
if (first_.offset + first_.writableBytes > bufferMaxSize_) {
ERROR_LOG_REPORT(Log::Atrac, "Somehow calculated too many writable bytes: %d + %d > %d", first_.offset, first_.writableBytes, bufferMaxSize_);
first_.offset = 0;
first_.writableBytes = bufferMaxSize_;
}
}
if (outReadOffset) {
*outReadOffset = readOffset;
}
}
void AtracBase::CreateDecoder(int codecType, int bytesPerFrame, int channels) {
if (decoder_) {
delete decoder_;
}
if (codecType == PSP_CODEC_AT3) {
bool jointStereo = IsAtrac3StreamJointStereo(codecType, bytesPerFrame, channels);
uint8_t extraData[14]{};
extraData[0] = 1;
extraData[3] = channels << 3;
extraData[6] = jointStereo;
extraData[8] = jointStereo;
extraData[10] = 1;
decoder_ = CreateAtrac3Audio(channels, bytesPerFrame, extraData, sizeof(extraData));
} else {
decoder_ = CreateAtrac3PlusAudio(channels, bytesPerFrame);
}
}
int Atrac::GetBufferInfoForResetting(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) {
*delay = false;
if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && !HasSecondBuffer()) {
return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED;
} else if ((u32)sample + track_.firstSampleOffset > (u32)track_.endSample + track_.firstSampleOffset) {
return SCE_ERROR_ATRAC_BAD_SAMPLE;
}
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
bufferInfo->first.writePosPtr = first_.addr;
bufferInfo->first.writableBytes = 0;
bufferInfo->first.minWriteBytes = 0;
bufferInfo->first.filePos = 0;
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
bufferInfo->first.writePosPtr = first_.addr + first_.size;
bufferInfo->first.writableBytes = track_.fileSize - first_.size;
int minWriteBytes = track_.FileOffsetBySample(sample) - first_.size;
if (minWriteBytes > 0) {
bufferInfo->first.minWriteBytes = minWriteBytes;
} else {
bufferInfo->first.minWriteBytes = 0;
}
bufferInfo->first.filePos = first_.size;
} else {
int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame());
const u32 bufSizeAligned = (bufferMaxSize_ / track_.bytesPerFrame) * track_.bytesPerFrame;
const int needsMoreFrames = track_.FirstOffsetExtra();
bufferInfo->first.writePosPtr = first_.addr;
bufferInfo->first.writableBytes = std::min(track_.fileSize - sampleFileOffset, bufSizeAligned);
if (((sample + track_.firstSampleOffset) % (int)track_.SamplesPerFrame()) >= (int)track_.SamplesPerFrame() - needsMoreFrames) {
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 3;
} else {
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 2;
}
if ((u32)sample < (u32)track_.firstSampleOffset && sampleFileOffset != track_.dataByteOffset) {
sampleFileOffset -= track_.bytesPerFrame;
}
bufferInfo->first.filePos = sampleFileOffset;
if (second_.size != 0) {
}
}
bufferInfo->second.writePosPtr = first_.addr;
bufferInfo->second.writableBytes = 0;
bufferInfo->second.minWriteBytes = 0;
bufferInfo->second.filePos = 0;
return 0;
}
int Atrac::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, u32 fileSize, int outputChannels, bool isAA3) {
if (readSize < 72) {
return SCE_ERROR_ATRAC_SIZE_TOO_SMALL;
}
if (!Memory::IsValidAddress(buffer)) {
return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
}
first_ = {};
first_.addr = buffer;
first_.size = readSize;
currentSample_ = 0;
loopNum_ = 0;
decodePos_ = 0;
bufferPos_ = 0;
outputChannels_ = outputChannels;
track.DebugLog();
track_ = track;
first_._filesize_dontuse = track_.fileSize;
if (outputChannels != track_.channels) {
WARN_LOG(Log::Atrac, "Atrac::SetData: outputChannels %d doesn't match track_.channels %d", outputChannels, track_.channels);
}
first_.addr = buffer;
first_.size = readSize;
if (first_.size > track_.fileSize)
first_.size = track_.fileSize;
first_.fileoffset = first_.size;
bufferMaxSize_ = bufferSize;
first_.offset = first_.size;
ResetData();
UpdateBufferState();
if (track_.codecType != PSP_CODEC_AT3 && track_.codecType != PSP_CODEC_AT3PLUS) {
bufferState_ = ATRAC_STATUS_NO_DATA;
ERROR_LOG(Log::Atrac, "unexpected codec type %d in set data", track_.codecType);
return SCE_ERROR_ATRAC_UNKNOWN_FORMAT;
}
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED || bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
ignoreDataBuf_ = true;
}
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
bufferHeaderSize_ = track_.dataByteOffset;
bufferPos_ = track_.dataByteOffset + track_.bytesPerFrame;
bufferValidBytes_ = first_.size - bufferPos_;
}
const char *codecName = track_.codecType == PSP_CODEC_AT3 ? "atrac3" : "atrac3+";
const char *channelName = track_.channels == 1 ? "mono" : "stereo";
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
if (!ignoreDataBuf_) {
u32 copybytes = std::min(bufferSize, track_.fileSize);
Memory::Memcpy(dataBuf_, buffer, copybytes, "AtracSetData");
}
CreateDecoder(track.codecType, track.bytesPerFrame, track.channels);
INFO_LOG(Log::Atrac, "Atrac::SetData (buffer=%08x, readSize=%d, bufferSize=%d): %s %s (%d channels) audio", buffer, readSize, bufferSize, codecName, channelName, track_.channels);
INFO_LOG(Log::Atrac, "BufferState: %s", AtracStatusToString(bufferState_));
INFO_LOG(Log::Atrac,
"buffer: %08x bufferSize: %d readSize: %d bufferPos: %d\n",
buffer, bufferSize, readSize, bufferPos_
);
if (track_.channels == 2 && outputChannels == 1) {
WARN_LOG(Log::Atrac, "Tried to load a stereo track into a mono context, returning NOT_MONO");
return SCE_ERROR_ATRAC_NOT_MONO;
}
return 0;
}
int Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
u32 secondFileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
u32 desiredSize = track_.fileSize - secondFileOffset;
if (secondBufferSize < desiredSize && secondBufferSize < (u32)track_.BytesPerFrame() * 3) {
return SCE_ERROR_ATRAC_SIZE_TOO_SMALL;
}
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
return SCE_ERROR_ATRAC_SECOND_BUFFER_NOT_NEEDED;
}
second_.addr = secondBuffer;
second_.size = secondBufferSize;
second_.fileoffset = secondFileOffset;
return 0;
}
int Atrac::GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) const {
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
*fileOffset = 0;
*desiredSize = 0;
return SCE_ERROR_ATRAC_SECOND_BUFFER_NOT_NEEDED;
}
*fileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
*desiredSize = track_.fileSize - *fileOffset;
return 0;
}
void Atrac::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) {
u32 calculatedReadOffset;
CalculateStreamInfo(&calculatedReadOffset);
*writePtr = first_.addr + first_.offset;
*writableBytes = first_.writableBytes;
*readOffset = calculatedReadOffset;
}
void Atrac::UpdateBufferState() {
if (bufferMaxSize_ >= track_.fileSize) {
if (first_.size < track_.fileSize) {
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
} else {
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
if (track_.loopEndSample <= 0) {
bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
} else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
} else {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
}
}
}
int Atrac::AddStreamData(u32 bytesToAdd) {
u32 readOffset;
CalculateStreamInfo(&readOffset);
if (bytesToAdd > first_.writableBytes)
return SCE_ERROR_ATRAC_ADD_DATA_IS_TOO_BIG;
if (bytesToAdd > 0) {
first_.fileoffset = readOffset;
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset);
if (!ignoreDataBuf_) {
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr + first_.offset, addbytes, "AtracAddStreamData");
}
first_.fileoffset += addbytes;
}
first_.size += bytesToAdd;
if (first_.size >= track_.fileSize) {
first_.size = track_.fileSize;
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
WriteContextToPSPMem();
}
first_.offset += bytesToAdd;
bufferValidBytes_ += bytesToAdd;
if (PSP_CoreParameter().compat.flags().AtracLoopHack && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && RemainingFrames() > 2) {
loopNum_++;
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
}
return 0;
}
u32 Atrac::GetNextSamples() {
if (currentSample_ >= track_.endSample) {
return 0;
}
int skipSamples = track_.FirstSampleOffsetFull();
int firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame();
int numSamples = track_.endSample + 1 - currentSample_;
if (currentSample_ == 0 && firstSamples != 0) {
numSamples = firstSamples;
}
int unalignedSamples = (skipSamples + currentSample_) % track_.SamplesPerFrame();
if (unalignedSamples != 0) {
numSamples = track_.SamplesPerFrame() - unalignedSamples;
}
if (numSamples > track_.SamplesPerFrame())
numSamples = track_.SamplesPerFrame();
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && (int)numSamples + currentSample_ > track_.endSample) {
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
return numSamples;
}
void Atrac::ForceSeekToSample(int sample) {
if (decoder_) {
decoder_->FlushBuffers();
}
currentSample_ = sample;
}
void Atrac::SeekToSample(int sample) {
const u32 offsetSamples = track_.FirstSampleOffsetFull();
const u32 unalignedSamples = (offsetSamples + sample) % track_.SamplesPerFrame();
int seekFrame = sample + offsetSamples - unalignedSamples;
if ((sample != currentSample_ || sample == 0) && decoder_ != nullptr) {
decoder_->FlushBuffers();
int adjust = 0;
if (sample == 0) {
int offsetSamples = track_.FirstSampleOffsetFull();
adjust = -(int)(offsetSamples % track_.SamplesPerFrame());
}
const u32 off = track_.FileOffsetBySample(sample + adjust);
const u32 backfill = track_.bytesPerFrame * 2;
const u32 start = off - track_.dataByteOffset < backfill ? track_.dataByteOffset : off - backfill;
for (u32 pos = start; pos < off; pos += track_.bytesPerFrame) {
decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, 2, nullptr, nullptr);
}
}
currentSample_ = sample;
}
int Atrac::RemainingFrames() const {
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
return PSP_ATRAC_ALLDATA_IS_ON_MEMORY;
}
u32 currentFileOffset = track_.FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + track_.FirstOffsetExtra());
if (first_.fileoffset >= track_.fileSize) {
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
}
int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset;
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && currentSample_ > loopEndAdjusted) {
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
}
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK && loopNum_ == 0) {
return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY;
}
}
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
return bufferValidBytes_ / track_.bytesPerFrame;
}
const int remainingBytes = first_.fileoffset - currentFileOffset;
if (remainingBytes < 0) {
return 0;
}
return remainingBytes / track_.bytesPerFrame;
}
void Atrac::ConsumeFrame() {
bufferPos_ += track_.bytesPerFrame;
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
if (bufferValidBytes_ > track_.bytesPerFrame) {
bufferValidBytes_ -= track_.bytesPerFrame;
} else {
bufferValidBytes_ = 0;
}
}
if (bufferPos_ >= StreamBufferEnd()) {
bufferPos_ -= StreamBufferEnd();
bufferHeaderSize_ = 0;
}
}
u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) {
int loopNum = loopNum_;
if (bufferState_ == ATRAC_STATUS_FOR_SCESAS) {
loopNum = 0;
}
if (currentSample_ >= track_.endSample && loopNum == 0) {
*SamplesNum = 0;
*finish = 1;
WriteContextToPSPMem();
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
}
int numSamples = 0;
int offsetSamples = track_.FirstSampleOffsetFull();
int skipSamples = 0;
int maxSamples = track_.endSample + 1 - currentSample_;
u32 unalignedSamples = (offsetSamples + currentSample_) % track_.SamplesPerFrame();
if (unalignedSamples != 0) {
maxSamples = track_.SamplesPerFrame() - unalignedSamples;
skipSamples = unalignedSamples;
}
if (skipSamples != 0 && bufferHeaderSize_ == 0) {
DEBUG_LOG(Log::Atrac, "Calling ConsumeFrame to skip the initial frame");
ConsumeFrame();
}
SeekToSample(currentSample_);
bool gotFrame = false;
u32 off = track_.FileOffsetBySample(currentSample_ - skipSamples);
DEBUG_LOG(Log::Atrac, "Decode(%08x): nextFileOff: %d", outbufPtr, off);
if (off < first_.size) {
uint8_t *indata = BufferStart() + off;
int bytesConsumed = 0;
int outSamples = track_.SamplesPerFrame();
int outBytes = outSamples * outputChannels_ * sizeof(int16_t);
gotFrame = true;
numSamples = outSamples;
uint32_t packetAddr = CurBufferAddress(-skipSamples);
int skipped = std::min(skipSamples, numSamples);
skipSamples -= skipped;
numSamples = numSamples - skipped;
numSamples = std::min(maxSamples, numSamples);
outSamples = numSamples;
if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, (int16_t *)outbuf, &outSamples)) {
*SamplesNum = 0;
*finish = 1;
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
}
if (packetAddr != 0 && MemBlockInfoDetailed()) {
char tagData[128];
size_t tagSize = FormatMemWriteTagAt(tagData, sizeof(tagData), "AtracDecode/", packetAddr, track_.bytesPerFrame);
NotifyMemInfo(MemBlockFlags::READ, packetAddr, track_.bytesPerFrame, tagData, tagSize);
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tagData, tagSize);
} else {
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
}
}
if (!gotFrame && currentSample_ < track_.endSample) {
if (track_.FileOffsetBySample(currentSample_) < (int)track_.fileSize) {
numSamples = std::min(maxSamples, track_.SamplesPerFrame());
u32 outBytes = numSamples * outputChannels_ * sizeof(s16);
if (outbuf != nullptr) {
memset(outbuf, 0, outBytes);
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
}
}
}
*SamplesNum = numSamples;
currentSample_ += numSamples;
decodePos_ = track_.DecodePosBySample(currentSample_);
ConsumeFrame();
int finishFlag = 0;
bool hitEnd = currentSample_ >= track_.endSample || (numSamples == 0 && first_.size >= track_.fileSize);
int loopEndAdjusted = track_.loopEndSample - track_.FirstSampleOffsetFull();
if ((hitEnd || currentSample_ > loopEndAdjusted) && loopNum != 0) {
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
if (bufferState_ != ATRAC_STATUS_FOR_SCESAS) {
if (loopNum_ > 0)
loopNum_--;
}
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
u32 loopOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
if (loopOffset > first_.fileoffset || loopOffset + bufferValidBytes_ < first_.fileoffset) {
first_.fileoffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
}
}
} else if (hitEnd) {
finishFlag = 1;
currentSample_ += track_.SamplesPerFrame() - numSamples;
}
*finish = finishFlag;
if (remains) {
*remains = RemainingFrames();
}
WriteContextToPSPMem();
return 0;
}
int Atrac::SetLoopNum(int loopNum) {
if (track_.loopinfo.size() == 0) {
return SCE_ERROR_ATRAC_NO_LOOP_INFORMATION;
}
loopNum_ = loopNum;
if (loopNum != 0 && track_.loopinfo.size() == 0) {
track_.loopStartSample = track_.FirstSampleOffsetFull();
track_.loopEndSample = track_.endSample + track_.FirstSampleOffsetFull();
}
WriteContextToPSPMem();
return 0;
}
int Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) {
*delay = false;
if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && !HasSecondBuffer()) {
return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED;
} else if ((u32)sample + track_.firstSampleOffset > (u32)track_.endSample + track_.firstSampleOffset) {
return SCE_ERROR_ATRAC_BAD_SAMPLE;
}
AtracResetBufferInfo bufferInfo;
bool ignored;
GetBufferInfoForResetting(&bufferInfo, sample, &ignored);
if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) {
return SCE_ERROR_ATRAC_BAD_FIRST_RESET_SIZE;
}
if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) {
return SCE_ERROR_ATRAC_BAD_SECOND_RESET_SIZE;
}
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
if (bytesWrittenFirstBuf != 0) {
if (!ignoreDataBuf_) {
Memory::Memcpy(dataBuf_ + first_.size, first_.addr + first_.size, bytesWrittenFirstBuf, "AtracResetPlayPosition");
}
first_.fileoffset += bytesWrittenFirstBuf;
first_.size += bytesWrittenFirstBuf;
first_.offset += bytesWrittenFirstBuf;
}
if (first_.size >= track_.fileSize) {
first_.size = track_.fileSize;
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
if (bufferInfo.first.filePos > track_.fileSize) {
*delay = true;
return SCE_ERROR_ATRAC_API_FAIL;
}
first_.fileoffset = bufferInfo.first.filePos;
if (bytesWrittenFirstBuf != 0) {
if (!ignoreDataBuf_) {
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr, bytesWrittenFirstBuf, "AtracResetPlayPosition");
}
first_.fileoffset += bytesWrittenFirstBuf;
}
first_.size = first_.fileoffset;
first_.offset = bytesWrittenFirstBuf;
bufferHeaderSize_ = 0;
bufferPos_ = track_.bytesPerFrame;
bufferValidBytes_ = bytesWrittenFirstBuf - bufferPos_;
}
if (track_.codecType == PSP_CODEC_AT3 || track_.codecType == PSP_CODEC_AT3PLUS) {
SeekToSample(sample);
}
WriteContextToPSPMem();
return 0;
}
void Atrac::InitLowLevel(const Atrac3LowLevelParams ¶ms, int codecType) {
track_ = Track();
track_.codecType = codecType;
track_.endSample = 0;
track_.channels = params.encodedChannels;
outputChannels_ = params.outputChannels;
bufferMaxSize_ = params.bytesPerFrame;
track_.bytesPerFrame = bufferMaxSize_;
first_.writableBytes = track_.bytesPerFrame;
ResetData();
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_CODEC_AT3PLUS) {
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0;
track_.jointStereo = false;
} else {
_dbg_assert_msg_(false, "bad codec type %08x", codecType);
}
track_.dataByteOffset = 0;
first_.size = 0;
track_.fileSize = track_.bytesPerFrame;
bufferState_ = ATRAC_STATUS_LOW_LEVEL;
currentSample_ = 0;
CreateDecoder(codecType, track_.bytesPerFrame, track_.channels);
WriteContextToPSPMem();
}
int Atrac::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) {
const int channels = outputChannels_;
int outSamples = 0;
decoder_->Decode(srcData, track_.BytesPerFrame(), bytesConsumed, channels, dstData, &outSamples);
*bytesWritten = outSamples * channels * sizeof(int16_t);
return 0;
}
void Atrac::CheckForSas() {
SetOutputChannels(1);
}
int Atrac::EnqueueForSas(u32 bufPtr, u32 bytesToAdd) {
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra());
Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData");
first_.size += bytesToAdd;
if (first_.size >= track_.fileSize) {
first_.size = track_.fileSize;
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
first_.fileoffset += addbytes;
WriteContextToPSPMem();
return 0;
}
void Atrac::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) {
int samplesNum;
DecodeData((u8 *)dstData, 0, &samplesNum, finish, nullptr);
}
void Atrac::NotifyGetContextAddress() {
if (!context_.IsValid()) {
u32 contextSize = sizeof(SceAtracContext);
context_ = kernelMemory.Alloc(contextSize, false, StringFromFormat("AtracCtx/%d", atracID_).c_str());
if (context_.IsValid())
Memory::Memset(context_.ptr, 0, contextSize, "AtracContextClear");
WARN_LOG(Log::Atrac, "%08x=_sceAtracGetContextAddress(%i): allocated new context", context_.ptr, atracID_);
} else {
WARN_LOG(Log::Atrac, "%08x=_sceAtracGetContextAddress(%i)", context_.ptr, atracID_);
}
WriteContextToPSPMem();
}