Slim down the AtracBase class

This commit is contained in:
Henrik Rydgård 2024-04-15 12:41:22 +02:00
parent 6c648a2cdd
commit 5e8a46fde0
3 changed files with 70 additions and 75 deletions

View file

@ -217,7 +217,7 @@ void Atrac::WriteContextToPSPMem() {
context->info.endSample = track_.endSample + track_.firstSampleOffset + FirstOffsetExtra();
context->info.dataEnd = track_.fileSize;
context->info.curOff = first_.fileoffset;
context->info.decodePos = DecodePosBySample(currentSample_);
context->info.decodePos = track_.DecodePosBySample(currentSample_);
context->info.streamDataByte = first_.size - track_.dataOff;
u8 *buf = (u8 *)context;
@ -537,7 +537,7 @@ void Atrac::CalculateStreamInfo(u32 *outReadOffset) {
first_.offset = 0;
first_.writableBytes = 0;
} else {
readOffset = FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
readOffset = track_.FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
}
}
@ -592,7 +592,7 @@ void Atrac::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) {
// This is because we're filling the buffer start to finish, not streaming.
bufferInfo->first.writePosPtr = first_.addr + first_.size;
bufferInfo->first.writableBytes = track_.fileSize - first_.size;
int minWriteBytes = FileOffsetBySample(sample) - first_.size;
int minWriteBytes = track_.FileOffsetBySample(sample) - first_.size;
if (minWriteBytes > 0) {
bufferInfo->first.minWriteBytes = minWriteBytes;
} else {
@ -601,7 +601,7 @@ void Atrac::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) {
bufferInfo->first.filePos = first_.size;
} else {
// This is without the sample offset. The file offset also includes the previous batch of samples?
int sampleFileOffset = FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame());
int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame());
// Update the writable bytes. When streaming, this is just the number of bytes until the end.
const u32 bufSizeAligned = (bufferMaxSize_ / track_.bytesPerFrame) * track_.bytesPerFrame;
@ -688,7 +688,7 @@ int Atrac::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels,
}
u32 Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
u32 secondFileOffset = FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
u32 secondFileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
u32 desiredSize = track_.fileSize - secondFileOffset;
// 3 seems to be the number of frames required to handle a loop.
@ -713,7 +713,7 @@ int Atrac::GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) {
return hleLogWarning(ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed");
}
*fileOffset = FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
*fileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
*desiredSize = track_.fileSize - *fileOffset;
return hleLogSuccessI(ME, 0);
}
@ -728,6 +728,26 @@ void Atrac::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset
*readOffset = calculatedReadOffset;
}
void Atrac::UpdateBufferState() {
if (bufferMaxSize_ >= track_.fileSize) {
if (first_.size < track_.fileSize) {
// The buffer is big enough, but we don't have all the data yet.
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
} else {
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
if (track_.loopEndSample <= 0) {
// There's no looping, but we need to stream the data in our buffer.
bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
} else if (track_.loopEndSample == track_.endSample + track_.firstSampleOffset + (int)FirstOffsetExtra()) {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
} else {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
}
}
}
int Atrac::AddStreamData(u32 bytesToAdd) {
u32 readOffset;
CalculateStreamInfo(&readOffset);
@ -819,7 +839,7 @@ void Atrac::SeekToSample(int sample) {
int offsetSamples = track_.firstSampleOffset + FirstOffsetExtra();
adjust = -(int)(offsetSamples % track_.SamplesPerFrame());
}
const u32 off = FileOffsetBySample(sample + adjust);
const u32 off = track_.FileOffsetBySample(sample + adjust);
const u32 backfill = track_.bytesPerFrame * 2;
const u32 start = off - track_.dataOff < backfill ? track_.dataOff : off - backfill;
@ -837,7 +857,7 @@ int Atrac::RemainingFrames() const {
return PSP_ATRAC_ALLDATA_IS_ON_MEMORY;
}
u32 currentFileOffset = FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + FirstOffsetExtra());
u32 currentFileOffset = track_.FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + FirstOffsetExtra());
if (first_.fileoffset >= track_.fileSize) {
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
@ -921,7 +941,7 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i
SeekToSample(currentSample_);
bool gotFrame = false;
u32 off = FileOffsetBySample(currentSample_ - skipSamples);
u32 off = track_.FileOffsetBySample(currentSample_ - skipSamples);
if (off < first_.size) {
uint8_t *indata = BufferStart() + off;
int bytesConsumed = 0;
@ -957,7 +977,7 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i
if (!gotFrame && currentSample_ < track_.endSample) {
// Never got a frame. We may have dropped a GHA frame or otherwise have a bug.
// For now, let's try to provide an extra "frame" if possible so games don't infinite loop.
if (FileOffsetBySample(currentSample_) < track_.fileSize) {
if (track_.FileOffsetBySample(currentSample_) < track_.fileSize) {
numSamples = std::min(maxSamples, track_.SamplesPerFrame());
u32 outBytes = numSamples * outputChannels_ * sizeof(s16);
if (outbuf != nullptr) {
@ -970,7 +990,7 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i
*SamplesNum = numSamples;
// update current sample and decodePos
currentSample_ += numSamples;
decodePos_ = DecodePosBySample(currentSample_);
decodePos_ = track_.DecodePosBySample(currentSample_);
ConsumeFrame();
@ -986,11 +1006,11 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i
}
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
// Whatever bytes we have left were added from the loop.
u32 loopOffset = FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
u32 loopOffset = track_.FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
// TODO: Hmm, need to manage the buffer better. But don't move fileoffset if we already have valid data.
if (loopOffset > first_.fileoffset || loopOffset + bufferValidBytes_ < first_.fileoffset) {
// Skip the initial frame at the start.
first_.fileoffset = FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
first_.fileoffset = track_.FileOffsetBySample(track_.loopStartSample - FirstOffsetExtra() - track_.firstSampleOffset - track_.SamplesPerFrame() * 2);
}
}
} else if (hitEnd) {

View file

@ -141,6 +141,16 @@ struct Track {
bitrate = (bitrate + 511) >> 10;
}
u32 DecodePosBySample(int sample) const {
return (u32)(firstSampleOffset + sample / (int)SamplesPerFrame() * bytesPerFrame);
}
u32 FileOffsetBySample(int sample) const {
int offsetSample = sample + firstSampleOffset;
int frameOffset = offsetSample / (int)SamplesPerFrame();
return (u32)(dataOff + bytesPerFrame + frameOffset * bytesPerFrame);
}
void AnalyzeReset() {
endSample = -1;
loopinfo.clear();
@ -157,20 +167,9 @@ int AnalyzeAtracTrack(u32 addr, u32 size, Track *track);
class AtracBase {
public:
virtual ~AtracBase() {}
virtual void UpdateBufferState() = 0;
virtual void DoState(PointerWrap &p) = 0;
u32 DecodePosBySample(int sample) const {
return (u32)(track_.firstSampleOffset + sample / (int)track_.SamplesPerFrame() * track_.bytesPerFrame);
}
u32 FileOffsetBySample(int sample) const {
int offsetSample = sample + track_.firstSampleOffset;
int frameOffset = offsetSample / (int)track_.SamplesPerFrame();
return (u32)(track_.dataOff + track_.bytesPerFrame + frameOffset * track_.bytesPerFrame);
}
const Track &GetTrack() const {
return track_;
}
@ -179,21 +178,11 @@ public:
return track_;
}
int Bitrate() const {
return track_.bitrate;
}
int Channels() const {
return track_.channels;
}
int GetOutputChannels() const {
return outputChannels_;
}
int atracID_ = -1;
u16 outputChannels_ = 2;
int loopNum_ = 0;
Track track_{};
PSPPointer<SceAtracContext> context_{};
@ -201,15 +190,19 @@ public:
return bufferState_;
}
int LoopNum() const {
return loopNum_;
}
u32 CodecType() const {
return track_.codecType;
}
AudioDecoder *GetDecoder() const {
AudioDecoder *Decoder() const {
return decoder_;
}
u32 FirstOffsetExtra() const {
return ::FirstOffsetExtra(track_.codecType);
}
void CreateDecoder();
virtual uint32_t CurBufferAddress(int adjust = 0) const = 0;
@ -232,8 +225,6 @@ public:
virtual int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) = 0;
virtual u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0;
virtual int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) = 0;
virtual void ForceSeekToSample(int sample) = 0;
virtual void SeekToSample(int sample) = 0;
virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) = 0;
virtual u32 GetNextSamples() = 0;
virtual void InitLowLevel(u32 paramsAddr, bool jointStereo) = 0;
@ -241,6 +232,10 @@ public:
protected:
virtual void AnalyzeReset() = 0;
Track track_{};
u16 outputChannels_ = 2;
int loopNum_ = 0;
// TODO: Save the internal state of this, now technically possible.
AudioDecoder *decoder_ = nullptr;
AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA;
@ -251,30 +246,9 @@ public:
~Atrac() {
ResetData();
}
void ResetData();
virtual void UpdateBufferState() {
if (bufferMaxSize_ >= track_.fileSize) {
if (first_.size < track_.fileSize) {
// The buffer is big enough, but we don't have all the data yet.
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
} else {
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
if (track_.loopEndSample <= 0) {
// There's no looping, but we need to stream the data in our buffer.
bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
} else if (track_.loopEndSample == track_.endSample + track_.firstSampleOffset + (int)FirstOffsetExtra()) {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
} else {
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
}
}
}
uint32_t CurBufferAddress(int adjust = 0) const override {
u32 off = FileOffsetBySample(currentSample_ + adjust);
u32 off = track_.FileOffsetBySample(currentSample_ + adjust);
if (off < first_.size && ignoreDataBuf_) {
return first_.addr + off;
}
@ -309,22 +283,18 @@ public:
int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) override;
u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override;
int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) override;
void ForceSeekToSample(int sample) override;
void SeekToSample(int sample) override;
u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override;
u32 GetNextSamples() override;
void InitLowLevel(u32 paramsAddr, bool jointStereo);
// Indicates that the dataBuf_ array should not be used.
u8 *dataBuf_ = nullptr;
InputBuffer first_{};
InputBuffer second_{};
protected:
void AnalyzeReset();
private:
void UpdateBufferState();
void ResetData();
void SeekToSample(int sample);
void ForceSeekToSample(int sample);
u32 StreamBufferEnd() const {
// The buffer is always aligned to a frame in size, not counting an optional header.
// The header will only initially exist after the data is first set.
@ -334,6 +304,11 @@ private:
void ConsumeFrame();
void CalculateStreamInfo(u32 *readOffset);
InputBuffer first_{};
InputBuffer second_{};
u8 *dataBuf_ = nullptr;
// Indicates that the dataBuf_ array should not be used.
bool ignoreDataBuf_ = false;
int currentSample_ = 0;

View file

@ -176,7 +176,7 @@ static u32 sceAtracGetAtracID(int codecType) {
}
AtracBase *atrac = new Atrac();
atrac->track_.codecType = codecType;
atrac->GetTrackMut().codecType = codecType;
int atracID = createAtrac(atrac);
if (atracID < 0) {
delete atrac;
@ -310,7 +310,7 @@ static u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr) {
atrac->GetTrackMut().UpdateBitrate();
if (Memory::IsValidAddress(outBitrateAddr)) {
Memory::WriteUnchecked_U32(atrac->Bitrate(), outBitrateAddr);
Memory::WriteUnchecked_U32(atrac->GetTrack().bitrate, outBitrateAddr);
return hleLogSuccessI(ME, 0);
} else {
return hleLogError(ME, 0, "invalid address");
@ -326,7 +326,7 @@ static u32 sceAtracGetChannel(int atracID, u32 channelAddr) {
}
if (Memory::IsValidAddress(channelAddr)){
Memory::WriteUnchecked_U32(atrac->Channels(), channelAddr);
Memory::WriteUnchecked_U32(atrac->GetTrack().channels, channelAddr);
return hleLogSuccessI(ME, 0);
} else {
return hleLogError(ME, 0, "invalid address");
@ -342,7 +342,7 @@ static u32 sceAtracGetLoopStatus(int atracID, u32 loopNumAddr, u32 statusAddr) {
}
if (Memory::IsValidAddress(loopNumAddr))
Memory::WriteUnchecked_U32(atrac->loopNum_, loopNumAddr);
Memory::WriteUnchecked_U32(atrac->LoopNum(), loopNumAddr);
// return audio's loopinfo in at3 file
if (Memory::IsValidAddress(statusAddr)) {
if (atrac->GetTrack().loopinfo.size() > 0)
@ -603,7 +603,7 @@ static u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) {
return ret;
}
if (atrac->track_.codecType != atracContextTypes[atracID]) {
if (atrac->GetTrack().codecType != atracContextTypes[atracID]) {
// TODO: Should this not change the buffer size?
return hleReportError(ME, ATRAC_ERROR_WRONG_CODECTYPE, "atracID uses different codec type than data");
}
@ -883,7 +883,7 @@ struct At3HeaderMap {
u8 jointStereo;
bool Matches(const AtracBase *at) const {
return bytes == at->GetTrack().BytesPerFrame() && channels == at->Channels();
return bytes == at->GetTrack().BytesPerFrame() && channels == at->GetTrack().channels;
}
};
@ -919,7 +919,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) {
}
}
if (!found) {
ERROR_LOG_REPORT(ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->GetTrack().BytesPerFrame(), atrac->Channels());
ERROR_LOG_REPORT(ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->GetTrack().BytesPerFrame(), atrac->GetTrack().channels);
// TODO: Should we return an error code for these values?
}
}
@ -949,7 +949,7 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo
int bytesConsumed = 0;
int bytesWritten = 0;
atrac->GetDecoder()->Decode(srcp, atrac->GetTrack().BytesPerFrame(), &bytesConsumed, 2, outp, &bytesWritten);
atrac->Decoder()->Decode(srcp, atrac->GetTrack().BytesPerFrame(), &bytesConsumed, 2, outp, &bytesWritten);
*srcConsumed = bytesConsumed;
*outWritten = bytesWritten;