CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HLE/AtracCtx.h
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#pragma once1819#include <vector>2021#include "Common/CommonTypes.h"22#include "Common/Swap.h"2324#include "Core/MemMap.h"25#include "Core/HLE/sceAtrac.h"2627struct AtracSingleResetBufferInfo {28u32_le writePosPtr;29u32_le writableBytes;30u32_le minWriteBytes;31u32_le filePos;32};3334struct AtracResetBufferInfo {35AtracSingleResetBufferInfo first;36AtracSingleResetBufferInfo second;37};3839#define AT3_MAGIC 0x027040#define AT3_PLUS_MAGIC 0xFFFE41#define PSP_MODE_AT_3_PLUS 0x0000100042#define PSP_MODE_AT_3 0x000010014344#define ATRAC_ERROR_API_FAIL 0x8063000245#define ATRAC_ERROR_NO_ATRACID 0x8063000346#define ATRAC_ERROR_INVALID_CODECTYPE 0x8063000447#define ATRAC_ERROR_BAD_ATRACID 0x8063000548#define ATRAC_ERROR_UNKNOWN_FORMAT 0x8063000649#define ATRAC_ERROR_WRONG_CODECTYPE 0x8063000750#define ATRAC_ERROR_BAD_CODEC_PARAMS 0x8063000851#define ATRAC_ERROR_ALL_DATA_LOADED 0x8063000952#define ATRAC_ERROR_NO_DATA 0x8063001053#define ATRAC_ERROR_SIZE_TOO_SMALL 0x8063001154#define ATRAC_ERROR_SECOND_BUFFER_NEEDED 0x8063001255#define ATRAC_ERROR_INCORRECT_READ_SIZE 0x8063001356#define ATRAC_ERROR_BAD_SAMPLE 0x8063001557#define ATRAC_ERROR_BAD_FIRST_RESET_SIZE 0x8063001658#define ATRAC_ERROR_BAD_SECOND_RESET_SIZE 0x8063001759#define ATRAC_ERROR_ADD_DATA_IS_TOO_BIG 0x8063001860#define ATRAC_ERROR_NOT_MONO 0x8063001961#define ATRAC_ERROR_NO_LOOP_INFORMATION 0x8063002162#define ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED 0x8063002263#define ATRAC_ERROR_BUFFER_IS_EMPTY 0x8063002364#define ATRAC_ERROR_ALL_DATA_DECODED 0x8063002465#define ATRAC_ERROR_IS_LOW_LEVEL 0x8063003166#define ATRAC_ERROR_IS_FOR_SCESAS 0x8063004067#define ATRAC_ERROR_AA3_INVALID_DATA 0x8063100368#define ATRAC_ERROR_AA3_SIZE_TOO_SMALL 0x806310046970const u32 ATRAC3_MAX_SAMPLES = 0x400;71const u32 ATRAC3PLUS_MAX_SAMPLES = 0x800;7273const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1;74const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2;75const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3;7677// This is not a PSP-native struct.78// But, it's stored in its entirety in savestates, which makes it awkward to change it.79struct InputBuffer {80// Address of the buffer.81u32 addr;82// Size of data read so far into dataBuf_ (to be removed.)83u32 size;84// Offset into addr at which new data is added.85u32 offset;86// Last writableBytes number (to be removed.)87u32 writableBytes;88// Unused, always 0.89u32 neededBytes;90// Total size of the entire file data.91u32 _filesize_dontuse;92// Offset into the file at which new data is read.93u32 fileoffset;94};9596struct AtracLoopInfo {97int cuePointID;98int type;99int startSample;100int endSample;101int fraction;102int playCount;103};104105class AudioDecoder;106107struct Track {108// This both does and doesn't belong in Track - it's fixed for an Atrac instance. Oh well.109u32 codecType = 0;110111// Size of the full track being streamed or played. Can be a lot larger than the in-memory buffer in the streaming modes.112u32 fileSize = 0;113114// Not really used for much except queries, this keeps track of the bitrate of the track.115u32 bitrate = 64;116117// Signifies whether to use a more efficient coding mode with less stereo separation. For our purposes, just metadata.118int jointStereo = 0;119120// Number of audio channels in the track.121u16 channels = 0;122123// The size of an encoded frame in bytes.124u16 bytesPerFrame = 0;125126// Byte offset of the first encoded frame in the input buffer. Note: Some samples may be skipped according to firstSampleOffset.127int dataByteOffset = 0;128129// How many samples to skip from the beginning of a track when decoding.130// Actually, the real number is this added to FirstOffsetExtra(codecType). You can call131// FirstSampleOffset2() to get that.132// Some use of these offsets around the code seem to be inconsistent, sometimes the extra is included,133// sometimes not.134int firstSampleOffset = 0;135136// Last sample number. Though, we made it so in Analyze, it's exclusive in the file.137// Does not take firstSampleOffset into account.138int endSample = 0;139140// Loop configuration. The PSP only supports one loop but we store them all.141std::vector<AtracLoopInfo> loopinfo;142// The actual used loop offsets. These appear to be raw offsets, not taking FirstSampleOffset2() into account.143int loopStartSample = -1;144int loopEndSample = -1;145146// Input frame size147int BytesPerFrame() const {148return bytesPerFrame;149}150151inline int FirstOffsetExtra() const {152return codecType == PSP_MODE_AT_3_PLUS ? 368 : 69;153}154155// Includes the extra offset. See firstSampleOffset comment above.156int FirstSampleOffsetFull() const {157return FirstOffsetExtra() + firstSampleOffset;158}159160// Output frame size, different between the two supported codecs.161u32 SamplesPerFrame() const {162return codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES;163}164165void UpdateBitrate() {166bitrate = (bytesPerFrame * 352800) / 1000;167if (codecType == PSP_MODE_AT_3_PLUS)168bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0;169else170bitrate = (bitrate + 511) >> 10;171}172173// This appears to be buggy, should probably include FirstOffsetExtra?174// Actually the units don't even make sense here.175u32 DecodePosBySample(int sample) const {176return (u32)(firstSampleOffset + sample / (int)SamplesPerFrame() * bytesPerFrame);177}178179// This appears to be buggy, should probably include FirstOffsetExtra?180u32 FileOffsetBySample(int sample) const {181int offsetSample = sample + firstSampleOffset;182int frameOffset = offsetSample / (int)SamplesPerFrame();183return (u32)(dataByteOffset + bytesPerFrame + frameOffset * bytesPerFrame);184}185186void AnalyzeReset() {187endSample = -1;188loopinfo.clear();189loopStartSample = -1;190loopEndSample = -1;191channels = 2;192// TODO: Could probably reset more.193}194195void DebugLog();196};197198int AnalyzeAA3Track(u32 addr, u32 size, u32 filesize, Track *track);199int AnalyzeAtracTrack(u32 addr, u32 size, Track *track);200201class AtracBase {202public:203virtual ~AtracBase() {}204205virtual void DoState(PointerWrap &p) = 0;206207const Track &GetTrack() const {208return track_;209}210// This should be rare.211Track &GetTrackMut() {212return track_;213}214215int GetOutputChannels() const {216return outputChannels_;217}218void SetOutputChannels(int channels) {219// Only used for sceSas audio. To be refactored away in the future.220outputChannels_ = channels;221}222223int atracID_ = -1;224225PSPPointer<SceAtracContext> context_{};226227AtracStatus BufferState() const {228return bufferState_;229}230231int LoopNum() const {232return loopNum_;233}234u32 CodecType() const {235return track_.codecType;236}237AudioDecoder *Decoder() const {238return decoder_;239}240241void CreateDecoder();242243virtual int CurrentSample() const = 0;244virtual int RemainingFrames() const = 0;245virtual u32 SecondBufferSize() const = 0;246247virtual int Analyze(u32 addr, u32 size) = 0;248virtual int AnalyzeAA3(u32 addr, u32 size, u32 filesize) = 0;249250void UpdateContextFromPSPMem();251virtual void WriteContextToPSPMem() = 0;252253virtual void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) = 0;254virtual int AddStreamData(u32 bytesToAdd) = 0;255virtual u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) = 0;256virtual void SetLoopNum(int loopNum);257virtual u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) = 0;258virtual void GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) = 0;259virtual int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) = 0;260261virtual int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize);262virtual u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0;263virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) = 0;264virtual u32 GetNextSamples() = 0;265virtual void InitLowLevel(u32 paramsAddr, bool jointStereo) = 0;266267protected:268Track track_{};269u16 outputChannels_ = 2;270int loopNum_ = 0;271272// TODO: Save the internal state of this, now technically possible.273AudioDecoder *decoder_ = nullptr;274AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA;275};276277class Atrac : public AtracBase {278public:279~Atrac() {280ResetData();281}282283uint32_t CurBufferAddress(int adjust = 0) const {284u32 off = track_.FileOffsetBySample(currentSample_ + adjust);285if (off < first_.size && ignoreDataBuf_) {286return first_.addr + off;287}288// If it's in dataBug, it's not in PSP memory.289return 0;290}291292u8 *BufferStart();293void DoState(PointerWrap &p) override;294void WriteContextToPSPMem() override;295296int Analyze(u32 addr, u32 size) override;297int AnalyzeAA3(u32 addr, u32 size, u32 filesize) override;298299int CurrentSample() const override {300return currentSample_;301}302int RemainingFrames() const override;303u32 SecondBufferSize() const override {304return second_.size;305}306307void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override;308int AddStreamData(u32 bytesToAdd) override;309u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override;310u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) override;311void GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) override;312int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) override;313u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override;314u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override;315u32 GetNextSamples() override;316void InitLowLevel(u32 paramsAddr, bool jointStereo) override;317318protected:319void AnalyzeReset();320321private:322void UpdateBufferState();323void ResetData();324void SeekToSample(int sample);325void ForceSeekToSample(int sample);326u32 StreamBufferEnd() const {327// The buffer is always aligned to a frame in size, not counting an optional header.328// The header will only initially exist after the data is first set.329u32 framesAfterHeader = (bufferMaxSize_ - bufferHeaderSize_) / track_.bytesPerFrame;330return framesAfterHeader * track_.bytesPerFrame + bufferHeaderSize_;331}332void ConsumeFrame();333void CalculateStreamInfo(u32 *readOffset);334335InputBuffer first_{};336InputBuffer second_{}; // only addr, size, fileoffset are used (incomplete)337338u8 *dataBuf_ = nullptr;339// Indicates that the dataBuf_ array should not be used.340bool ignoreDataBuf_ = false;341342int currentSample_ = 0;343u32 decodePos_ = 0;344u32 bufferMaxSize_ = 0;345346// Used to track streaming.347u32 bufferPos_ = 0;348u32 bufferValidBytes_ = 0;349u32 bufferHeaderSize_ = 0;350};351352353