Work on the new implementation.

This commit is contained in:
Henrik Rydgård 2025-03-09 10:44:33 +01:00
parent 78e763b050
commit 724fc1dd95
4 changed files with 246 additions and 39 deletions

View file

@ -192,9 +192,7 @@ public:
PSPPointer<SceAtracContext> context_{};
AtracStatus BufferState() const {
return bufferState_;
}
virtual AtracStatus BufferState() const = 0;
virtual int SetLoopNum(int loopNum) = 0;
virtual int LoopNum() const = 0;
@ -241,7 +239,6 @@ protected:
// TODO: Save the internal state of this, now technically possible.
AudioDecoder *decoder_ = nullptr;
AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA;
};
class Atrac : public AtracBase {
@ -264,6 +261,10 @@ public:
u8 *BufferStart();
AtracStatus BufferState() const {
return bufferState_;
}
void DoState(PointerWrap &p) override;
int GetNextDecodePosition(int *pos) const override;
@ -357,4 +358,5 @@ private:
u32 bufferHeaderSize_ = 0;
int atracID_ = -1;
AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA;
};

View file

@ -15,6 +15,8 @@ Atrac2::Atrac2(int atracID, u32 contextAddr, int codecType) {
context_ = PSPPointer<SceAtracContext>::Create(contextAddr);
track_.codecType = codecType;
context_->info.codec = codecType;
context_->info.atracID = atracID;
context_->info.state = ATRAC_STATUS_NO_DATA;
}
void Atrac2::DoState(PointerWrap &p) {
@ -22,22 +24,53 @@ void Atrac2::DoState(PointerWrap &p) {
}
int Atrac2::RemainingFrames() const {
return 0;
const SceAtracIdInfo &info = context_->info;
if (info.state == ATRAC_STATUS_ALL_DATA_LOADED) {
// The buffer contains everything.
return PSP_ATRAC_ALLDATA_IS_ON_MEMORY;
}
const bool isStreaming = (info.state & ATRAC_STATUS_STREAMED_MASK) != 0;
if (info.decodePos >= track_.endSample) {
if (info.state == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
}
int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset;
if (info.state == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && info.decodePos > loopEndAdjusted) {
// No longer looping in this case, outside the loop.
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
}
if (isStreaming && loopNum_ == 0) {
return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY;
}
return info.streamDataByte / info.sampleSize;
}
if (isStreaming) {
// Since we're streaming, the remaining frames are what's valid in the buffer.
return info.streamDataByte / info.sampleSize;
}
// Fallback
return info.dataEnd / info.sampleSize;
}
u32 Atrac2::SecondBufferSize() const {
return 0;
}
void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) {
}
int Atrac2::AddStreamData(u32 bytesToAdd) {
return 0;
const SceAtracIdInfo &info = context_->info;
return info.secondBufferByte;
}
u32 Atrac2::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) {
_dbg_assert_(false);
return 0;
}
int Atrac2::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;
}
@ -47,19 +80,158 @@ int Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWri
}
int Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) {
_dbg_assert_(false);
return 0;
}
int Atrac2::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const {
return 0;
}
int Atrac2::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) {
if (readSize == bufferSize) {
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
} else {
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
int Atrac2::SetLoopNum(int loopNum) {
SceAtracIdInfo &info = context_->info;
if (info.loopEnd <= 0) {
return SCE_ERROR_ATRAC_NO_LOOP_INFORMATION;
}
info.loopNum = loopNum;
return 0;
}
u32 Atrac2::GetNextSamples() {
// This has to be possible to do in an easier way, from the existing state.
int currentSample = context_->info.decodePos;
// It seems like the PSP aligns the sample position to 0x800...?
u32 skipSamples = track_.FirstSampleOffsetFull();
u32 firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame();
u32 numSamples = track_.endSample + 1 - currentSample;
if (currentSample == 0 && firstSamples != 0) {
numSamples = firstSamples;
}
u32 unalignedSamples = (skipSamples + currentSample) % track_.SamplesPerFrame();
if (unalignedSamples != 0) {
// We're off alignment, possibly due to a loop. Force it back on.
numSamples = track_.SamplesPerFrame() - unalignedSamples;
}
if (numSamples > track_.SamplesPerFrame())
numSamples = track_.SamplesPerFrame();
return numSamples;
}
int Atrac2::AddStreamData(u32 bytesToAdd) {
SceAtracIdInfo &info = context_->info;
// if (bytesToAdd > first_.writableBytes)
// return SCE_ERROR_ATRAC_ADD_DATA_IS_TOO_BIG;
info.streamDataByte += bytesToAdd;
return 0;
}
void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) {
SceAtracIdInfo &info = context_->info;
*readOffset = info.bufferByte;
*writePtr = context_->codec.inBuf + info.curOff;
*writableBytes = 0;
// Probably we treat
}
u32 Atrac2::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) {
SceAtracIdInfo &info = context_->info;
if (!decodeTemp_) {
decodeTemp_ = new int16_t[track_.SamplesPerFrame() * track_.channels];
}
/*
const uint8_t *indata = Memory::GetPointer(context_->codec.inBuf + info.curOff);
int bytesConsumed = 0;
int outSamples = 0;
if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, decodeTemp_, &outSamples)) {
// Decode failed.
*SamplesNum = 0;
*finish = 1;
// Is this the right error code? Needs testing.
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
}
*/
info.streamDataByte -= info.sampleSize;
info.curOff += info.sampleSize;
info.decodePos += track_.SamplesPerFrame();
// This one starts out being the same as curOff but sometimes gets reset??
info.unk48 += info.sampleSize;
*remains = RemainingFrames();
return 0;
}
int Atrac2::SetData(const Track &track, u32 bufferAddr, u32 readSize, u32 bufferSize, int outputChannels) {
// TODO: Remove track_.
track_ = track;
if (track_.codecType != PSP_MODE_AT_3 && track_.codecType != PSP_MODE_AT_3_PLUS) {
// Shouldn't have gotten here, Analyze() checks this.
context_->info.state = ATRAC_STATUS_NO_DATA;
ERROR_LOG(Log::ME, "unexpected codec type %d in set data", track_.codecType);
return SCE_ERROR_ATRAC_UNKNOWN_FORMAT;
}
if (outputChannels != track_.channels) {
// TODO: Figure out what this means
WARN_LOG(Log::ME, "Atrac::SetData: outputChannels %d doesn't match track_.channels %d", outputChannels, track_.channels);
}
context_->codec.inBuf = bufferAddr;
// Copied from the old implementation, let's see where they are useful.
int bufOff = track_.dataByteOffset + track_.bytesPerFrame;
int skipSamples = track_.FirstSampleOffsetFull();
int firstExtra = track_.FirstOffsetExtra();
SceAtracIdInfo &info = context_->info;
// Copy parameters into struct.
info.buffer = bufferAddr;
info.bufferByte = bufferSize;
info.samplesPerChan = track_.FirstSampleOffsetFull(); // TODO: Where does 970 come from?
info.endSample = track_.endSample + info.samplesPerChan;
if (track_.loopStartSample != 0xFFFFFFFF) {
info.loopStart = track_.loopStartSample;
info.loopEnd = track_.loopEndSample;
}
info.codec = track_.codecType;
info.sampleSize = track_.bytesPerFrame;
info.numChan = track_.channels;
info.numFrame = 0;
info.dataOff = track_.dataByteOffset;
info.curOff = 0x1D8; // 472
info.unk48 = info.curOff;
info.streamDataByte = readSize - info.curOff;
info.dataEnd = track_.fileSize;
if (readSize > track_.fileSize) {
WARN_LOG(Log::ME, "readSize %d > track_.fileSize", readSize, track_.fileSize);
readSize = track_.fileSize;
}
if (bufferSize >= track_.fileSize) {
// Buffer is big enough to fit the whole track.
if (readSize < bufferSize) {
info.state = ATRAC_STATUS_HALFWAY_BUFFER;
} else {
info.state = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
// Streaming cases with various looping types.
if (track_.loopEndSample <= 0) {
// There's no looping, but we need to stream the data in our buffer.
info.state = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
} else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) {
info.state = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
} else {
info.state = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
}
}
CreateDecoder();
return 0;
}
@ -67,16 +239,37 @@ u32 Atrac2::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
return 0;
}
u32 Atrac2::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) {
int Atrac2::Bitrate() const {
const SceAtracIdInfo &info = context_->info;
return 0;
}
u32 Atrac2::GetNextSamples() {
return 0;
int bitrate = (info.sampleSize * 352800) / 1000;
if (info.codec == PSP_MODE_AT_3_PLUS)
bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0;
else
bitrate = (bitrate + 511) >> 10;
return bitrate;
}
void Atrac2::InitLowLevel(u32 paramsAddr, bool jointStereo, int codecType) {
track_ = Track();
track_.codecType = codecType;
track_.channels = Memory::Read_U32(paramsAddr);
outputChannels_ = Memory::Read_U32(paramsAddr + 4);
track_.bytesPerFrame = Memory::Read_U32(paramsAddr + 8);
if (track_.codecType == PSP_MODE_AT_3) {
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
track_.bitrate = (track_.bitrate + 511) >> 10;
track_.jointStereo = false;
} else if (track_.codecType == PSP_MODE_AT_3_PLUS) {
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0;
track_.jointStereo = false;
}
track_.dataByteOffset = 0;
context_->info.decodePos = 0;
context_->info.state = ATRAC_STATUS_LOW_LEVEL;
CreateDecoder();
}
int Atrac2::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) {

View file

@ -7,20 +7,28 @@
class Atrac2 : public AtracBase {
public:
Atrac2(int atracID, u32 contextAddr, int codecType);
~Atrac2() {
delete[] decodeTemp_;
}
AtracStatus BufferState() const {
return context_->info.state;
}
void DoState(PointerWrap &p) override;
int GetID() const override { return 0; }
int GetID() const override { return context_->info.atracID; }
int GetNextDecodePosition(int *pos) const override { return context_->info.decodePos; }
int GetNextDecodePosition(int *pos) const { return 0; }
int RemainingFrames() const override;
int LoopStatus() const override { return 0; }
int Bitrate() const override { return 0; }
int LoopNum() const override { return 0; }
int Bitrate() const override;
int LoopNum() const override { return context_->info.loopNum; }
int SamplesPerFrame() const override { return 0; }
int Channels() const override { return 2; }
int BytesPerFrame() const override { return 0; }
int SetLoopNum(int loopNum) override { return 0; }
int Channels() const override { return context_->info.numChan; }
int BytesPerFrame() const override { return context_->info.sampleSize; }
int SetLoopNum(int loopNum) override;
void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override;
int AddStreamData(u32 bytesToAdd) override;
@ -34,6 +42,7 @@ public:
u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override;
int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) override;
u32 GetNextSamples() override;
void InitLowLevel(u32 paramsAddr, bool jointStereo, int codecType) override;
int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const override;
@ -43,5 +52,8 @@ public:
void NotifyGetContextAddress() override {}
private:
int currentSample_ = 0;
// Just the current decoded frame, in order to be able to cut off the first part of it
// to write the initial partial frame.
// Does not need to be saved.
int16_t *decodeTemp_ = nullptr;
};

View file

@ -58,7 +58,7 @@ struct SceAtracIdInfo {
u32_le endSample; // 4
u32_le loopStart; // 8
u32_le loopEnd; // 12
s32_le samplesPerChan; // 16
s32_le samplesPerChan; // 16 // This rather seems to be the number of skipped samples at the start. (plus one frame?)
char numFrame; // 20
// 2: all the stream data on the buffer
// 6: looping -> second buffer needed
@ -79,7 +79,7 @@ struct SceAtracIdInfo {
u32_le bufferByte; // 64
u32_le secondBufferByte; // 68
// make sure the size is 128
u8 unk[52];
u32_le unk[13];
u32_le atracID;
};