mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Atrac: Rework the header dependencies
This commit is contained in:
1 parent
45a79f94e8
commit
5c77ff9147
10 files changed
+251
-234
No files matched your search
@@ -2169,6 +2169,7 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/HLE/__sceAudio.h
|
||||
Core/HLE/sceAdler.cpp
|
||||
Core/HLE/sceAdler.h
|
||||
Core/HLE/AtracBase.h
|
||||
Core/HLE/AtracCtx.cpp
|
||||
Core/HLE/AtracCtx.h
|
||||
Core/HLE/AtracCtx2.cpp
|
||||
|
||||
@@ -1014,6 +1014,7 @@
|
||||
<ClInclude Include="FileLoaders\ZipFileLoader.h" />
|
||||
<ClInclude Include="FileSystems\BlobFileSystem.h" />
|
||||
<ClInclude Include="FrameTiming.h" />
|
||||
<ClInclude Include="HLE\AtracBase.h" />
|
||||
<ClInclude Include="HLE\AtracCtx.h" />
|
||||
<ClInclude Include="HLE\AtracCtx2.h" />
|
||||
<ClInclude Include="HLE\ErrorCodes.h" />
|
||||
|
||||
@@ -2190,6 +2190,9 @@
|
||||
<ClInclude Include="FileLoaders\ZipFileLoader.h">
|
||||
<Filter>FileLoaders</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\AtracBase.h">
|
||||
<Filter>HLE\Libraries</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE.TXT" />
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Swap.h"
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/HLE/sceAudiocodec.h"
|
||||
|
||||
constexpr u32 ATRAC3_MAX_SAMPLES = 0x400; // 1024
|
||||
constexpr u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; // 2048
|
||||
|
||||
// The "state" member of SceAtracIdInfo.
|
||||
enum AtracStatus : u8 {
|
||||
ATRAC_STATUS_UNINITIALIZED = 0, // bad state
|
||||
|
||||
ATRAC_STATUS_NO_DATA = 1,
|
||||
|
||||
// The entire file is loaded into memory, no further file access needed.
|
||||
ATRAC_STATUS_ALL_DATA_LOADED = 2,
|
||||
|
||||
// The buffer is sized to fit the entire file, but it's only partially loaded, so you can start playback before loading the whole file.
|
||||
ATRAC_STATUS_HALFWAY_BUFFER = 3,
|
||||
|
||||
// In these ones, the buffer is smaller than the file, and data is streamed into it as needed for playback.
|
||||
// These are the most complex modes, both to implement and use.
|
||||
ATRAC_STATUS_STREAMED_WITHOUT_LOOP = 4,
|
||||
ATRAC_STATUS_STREAMED_LOOP_FROM_END = 5,
|
||||
// This means there's additional audio after the loop.
|
||||
// i.e. ~~before loop~~ [ ~~this part loops~~ ] ~~after loop~~
|
||||
// The "fork in the road" means a second buffer is needed for the second path.
|
||||
ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER = 6,
|
||||
|
||||
// In this mode, the only API to call is sceAtracLowLevelDecode, which decodes a stream packet by packet without any other metadata.
|
||||
ATRAC_STATUS_LOW_LEVEL = 8,
|
||||
|
||||
// This mode is for using an Atrac context as the audio source for an sceSas channel. Not used a lot (Sol Trigger).
|
||||
ATRAC_STATUS_FOR_SCESAS = 16,
|
||||
|
||||
// Bitwise-and the status with this to check for any of the streaming modes in a single test.
|
||||
ATRAC_STATUS_STREAMED_MASK = 4,
|
||||
};
|
||||
|
||||
const char *AtracStatusToString(AtracStatus status);
|
||||
|
||||
inline bool AtracStatusIsStreaming(AtracStatus status) {
|
||||
return (status & ATRAC_STATUS_STREAMED_MASK) != 0;
|
||||
}
|
||||
inline bool AtracStatusIsNormal(AtracStatus status) {
|
||||
return (int)status >= ATRAC_STATUS_ALL_DATA_LOADED && (int)status <= ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
|
||||
}
|
||||
|
||||
struct SceAtracIdInfo {
|
||||
s32 decodePos; // Sample position in the song that we'll next be decoding from.
|
||||
s32 endSample; // Last sample index of the track.
|
||||
s32 loopStart; // Start of the loop (sample index)
|
||||
s32 loopEnd; // End of the loop (sample index)
|
||||
s32 firstValidSample; // Seems to be the number of skipped samples at the start. After SetID, decodePos will match this. Was previously misnamed 'samplesPerChan'.
|
||||
u8 numSkipFrames; // This is 1 for a single frame when a loop is triggered, otherwise seems to stay at 0. Likely mis-named.
|
||||
AtracStatus state; // State enum, see AtracStatus.
|
||||
u8 curBuffer; // Current buffer (1 == second, 2 == done?) Previously unk
|
||||
u8 numChan; // Number of audio channels, usually 2 but 1 is possible.
|
||||
u16 sampleSize; // Size in bytes of an encoded audio frame.
|
||||
u16 codec; // Codec. 0x1000 is Atrac3+, 0x1001 is Atrac3. See the PSP_CODEC_ enum (only these two are supported).
|
||||
s32 dataOff; // File offset in bytes where the Atrac3+ frames start appearing. The first dummy packet starts here.
|
||||
s32 curFileOff; // File offset in bytes corresponding to the start of next packet that will be *decoded* (on the next call to sceAtracDecodeData).
|
||||
s32 fileDataEnd; // File size in bytes.
|
||||
s32 loopNum; // Current loop counter. If 0, will not loop. -1 loops for ever, positive numbers get decremented on the loop end. So to play a song 3 times and then end, set this to 2.
|
||||
s32 streamDataByte; // Number of bytes of queued/buffered/uploaded data. In full and half-way modes, this isn't decremented as you decode.
|
||||
s32 streamOff; // Streaming modes only: The byte offset inside the RAM buffer where sceAtracDecodeData will read from next. ONLY points to even packet boundaries.
|
||||
s32 secondStreamOff; // A kind of stream position in the secondary buffer.
|
||||
u32 buffer; // Address in RAM of the main buffer.
|
||||
u32 secondBuffer; // Address in RAM of the second buffer, or 0 if not used.
|
||||
u32 bufferByte; // Size in bytes of the main buffer.
|
||||
u32 secondBufferByte; // Size in bytes of the second buffer.
|
||||
// Offset 72 here.
|
||||
// make sure the size is 128
|
||||
u32 unk[14];
|
||||
|
||||
// Simple helpers. Similar ones are on track_, but we shouldn't need track_ anymore when playing back.
|
||||
|
||||
int SamplesPerFrame() const {
|
||||
return codec == 0x1000 ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES;
|
||||
}
|
||||
int SamplesFrameMask() const {
|
||||
return SamplesPerFrame() - 1;
|
||||
}
|
||||
int SkipSamples() const {
|
||||
// These first samples are skipped, after first possibly skipping 0-2 full frames, it seems.
|
||||
return codec == 0x1000 ? 0x170 : 0x45;
|
||||
}
|
||||
};
|
||||
|
||||
// One of these structs is allocated for each Atrac context.
|
||||
// The raw codec state is stored in 'codec'.
|
||||
// The internal playback state is stored in 'info', and that is used for all state keeping in the Atrac2 implementation,
|
||||
// imitating what happens on hardware as closely as possible.
|
||||
struct SceAtracContext {
|
||||
// size 128
|
||||
SceAudiocodecCodec codec;
|
||||
// size 128
|
||||
SceAtracIdInfo info;
|
||||
};
|
||||
|
||||
struct Atrac3LowLevelParams {
|
||||
int encodedChannels;
|
||||
int outputChannels;
|
||||
int bytesPerFrame;
|
||||
};
|
||||
|
||||
struct AtracSingleResetBufferInfo {
|
||||
u32_le writePosPtr;
|
||||
u32_le writableBytes;
|
||||
u32_le minWriteBytes;
|
||||
u32_le filePos;
|
||||
};
|
||||
|
||||
struct AtracResetBufferInfo {
|
||||
AtracSingleResetBufferInfo first;
|
||||
AtracSingleResetBufferInfo second;
|
||||
};
|
||||
|
||||
struct AtracSasStreamState {
|
||||
u32 bufPtr[2]{};
|
||||
u32 bufSize[2]{};
|
||||
int streamOffset = 0;
|
||||
int fileOffset = 0;
|
||||
int curBuffer = 0;
|
||||
bool isStreaming = false;
|
||||
|
||||
int CurPos() const {
|
||||
int retval = fileOffset - bufSize[curBuffer] + streamOffset;
|
||||
_dbg_assert_(retval >= 0);
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1;
|
||||
const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2;
|
||||
const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3;
|
||||
|
||||
// This is not a PSP-native struct.
|
||||
// But, it's stored in its entirety in savestates, which makes it awkward to change it.
|
||||
// This is used for both first_ and second_, but the latter doesn't use all the fields.
|
||||
struct InputBuffer {
|
||||
// Address of the buffer.
|
||||
u32 addr;
|
||||
// Size of data read so far into dataBuf_ (to be removed.)
|
||||
u32 size;
|
||||
// Offset into addr at which new data is added.
|
||||
u32 offset;
|
||||
// Last writableBytes number (to be removed.)
|
||||
u32 writableBytes;
|
||||
// Unused, always 0.
|
||||
u32 neededBytes;
|
||||
// Total size of the entire file data.
|
||||
u32 _filesize_dontuse;
|
||||
// Offset into the file at which new data is read.
|
||||
u32 fileoffset;
|
||||
};
|
||||
|
||||
class AudioDecoder;
|
||||
class PointerWrap;
|
||||
struct Track;
|
||||
|
||||
class AtracBase {
|
||||
public:
|
||||
virtual ~AtracBase();
|
||||
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
// TODO: Find a way to get rid of this from the base class.
|
||||
virtual void UpdateContextFromPSPMem() = 0;
|
||||
|
||||
virtual int Channels() const = 0;
|
||||
|
||||
int GetOutputChannels() const {
|
||||
return outputChannels_;
|
||||
}
|
||||
void SetOutputChannels(int channels) {
|
||||
// Only used for sceSas audio. To be refactored away in the future.
|
||||
outputChannels_ = channels;
|
||||
}
|
||||
|
||||
virtual u32 GetInternalCodecError() const { return 0; }
|
||||
|
||||
PSPPointer<SceAtracContext> context_{};
|
||||
|
||||
virtual AtracStatus BufferState() const = 0;
|
||||
|
||||
virtual int SetLoopNum(int loopNum) = 0;
|
||||
virtual int LoopNum() const = 0;
|
||||
virtual int LoopStatus() const = 0;
|
||||
|
||||
virtual int CodecType() const = 0;
|
||||
|
||||
AudioDecoder *Decoder() const {
|
||||
return decoder_;
|
||||
}
|
||||
|
||||
void CreateDecoder(int codecType, int bytesPerFrame, int channels);
|
||||
|
||||
virtual void NotifyGetContextAddress() = 0;
|
||||
|
||||
virtual int GetNextDecodePosition(int *pos) const = 0;
|
||||
virtual int RemainingFrames() const = 0;
|
||||
virtual bool HasSecondBuffer() const = 0;
|
||||
virtual int Bitrate() const = 0;
|
||||
virtual int BytesPerFrame() const = 0;
|
||||
virtual int SamplesPerFrame() const = 0;
|
||||
|
||||
virtual void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) = 0; // This should be const, but the legacy impl stops it (it's wrong).
|
||||
virtual int AddStreamData(u32 bytesToAdd) = 0;
|
||||
virtual int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) = 0;
|
||||
virtual int GetBufferInfoForResetting(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) = 0; // NOTE: Not const! This can cause SkipFrames!
|
||||
virtual int SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) = 0;
|
||||
|
||||
virtual int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) const = 0;
|
||||
virtual int SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0;
|
||||
virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) = 0;
|
||||
virtual int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) = 0;
|
||||
|
||||
virtual u32 GetNextSamples() = 0; // This should be const, but the legacy impl stops it (it's wrong).
|
||||
virtual void InitLowLevel(const Atrac3LowLevelParams ¶ms, int codecType) = 0;
|
||||
|
||||
virtual void CheckForSas() = 0;
|
||||
virtual int EnqueueForSas(u32 address, u32 ptr) = 0;
|
||||
virtual void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) = 0;
|
||||
virtual const AtracSasStreamState *StreamStateForSas() const { return nullptr; }
|
||||
|
||||
virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0;
|
||||
|
||||
virtual int GetContextVersion() const = 0;
|
||||
|
||||
protected:
|
||||
u16 outputChannels_ = 2;
|
||||
|
||||
// TODO: Save the internal state of this, now technically possible.
|
||||
AudioDecoder *decoder_ = nullptr;
|
||||
};
|
||||
@@ -28,8 +28,7 @@
|
||||
#include "Core/HLE/AtracCtx.h"
|
||||
#include "Core/HW/Atrac3Standalone.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
const size_t overAllocBytes = 16384;
|
||||
|
||||
|
||||
+2
-130
@@ -23,136 +23,8 @@
|
||||
#include "Common/Swap.h"
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/HLE/sceAtrac.h"
|
||||
|
||||
struct AtracSingleResetBufferInfo {
|
||||
u32_le writePosPtr;
|
||||
u32_le writableBytes;
|
||||
u32_le minWriteBytes;
|
||||
u32_le filePos;
|
||||
};
|
||||
|
||||
struct AtracResetBufferInfo {
|
||||
AtracSingleResetBufferInfo first;
|
||||
AtracSingleResetBufferInfo second;
|
||||
};
|
||||
|
||||
struct AtracSasStreamState {
|
||||
u32 bufPtr[2]{};
|
||||
u32 bufSize[2]{};
|
||||
int streamOffset = 0;
|
||||
int fileOffset = 0;
|
||||
int curBuffer = 0;
|
||||
bool isStreaming = false;
|
||||
|
||||
int CurPos() const {
|
||||
int retval = fileOffset - bufSize[curBuffer] + streamOffset;
|
||||
_dbg_assert_(retval >= 0);
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1;
|
||||
const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2;
|
||||
const int PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY = -3;
|
||||
|
||||
// This is not a PSP-native struct.
|
||||
// But, it's stored in its entirety in savestates, which makes it awkward to change it.
|
||||
// This is used for both first_ and second_, but the latter doesn't use all the fields.
|
||||
struct InputBuffer {
|
||||
// Address of the buffer.
|
||||
u32 addr;
|
||||
// Size of data read so far into dataBuf_ (to be removed.)
|
||||
u32 size;
|
||||
// Offset into addr at which new data is added.
|
||||
u32 offset;
|
||||
// Last writableBytes number (to be removed.)
|
||||
u32 writableBytes;
|
||||
// Unused, always 0.
|
||||
u32 neededBytes;
|
||||
// Total size of the entire file data.
|
||||
u32 _filesize_dontuse;
|
||||
// Offset into the file at which new data is read.
|
||||
u32 fileoffset;
|
||||
};
|
||||
|
||||
class AudioDecoder;
|
||||
|
||||
class AtracBase {
|
||||
public:
|
||||
virtual ~AtracBase();
|
||||
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
// TODO: Find a way to get rid of this from the base class.
|
||||
virtual void UpdateContextFromPSPMem() = 0;
|
||||
|
||||
virtual int Channels() const = 0;
|
||||
|
||||
int GetOutputChannels() const {
|
||||
return outputChannels_;
|
||||
}
|
||||
void SetOutputChannels(int channels) {
|
||||
// Only used for sceSas audio. To be refactored away in the future.
|
||||
outputChannels_ = channels;
|
||||
}
|
||||
|
||||
virtual u32 GetInternalCodecError() const { return 0; }
|
||||
|
||||
PSPPointer<SceAtracContext> context_{};
|
||||
|
||||
virtual AtracStatus BufferState() const = 0;
|
||||
|
||||
virtual int SetLoopNum(int loopNum) = 0;
|
||||
virtual int LoopNum() const = 0;
|
||||
virtual int LoopStatus() const = 0;
|
||||
|
||||
virtual int CodecType() const = 0;
|
||||
|
||||
AudioDecoder *Decoder() const {
|
||||
return decoder_;
|
||||
}
|
||||
|
||||
void CreateDecoder(int codecType, int bytesPerFrame, int channels);
|
||||
|
||||
virtual void NotifyGetContextAddress() = 0;
|
||||
|
||||
virtual int GetNextDecodePosition(int *pos) const = 0;
|
||||
virtual int RemainingFrames() const = 0;
|
||||
virtual bool HasSecondBuffer() const = 0;
|
||||
virtual int Bitrate() const = 0;
|
||||
virtual int BytesPerFrame() const = 0;
|
||||
virtual int SamplesPerFrame() const = 0;
|
||||
|
||||
virtual void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) = 0; // This should be const, but the legacy impl stops it (it's wrong).
|
||||
virtual int AddStreamData(u32 bytesToAdd) = 0;
|
||||
virtual int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) = 0;
|
||||
virtual int GetBufferInfoForResetting(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) = 0; // NOTE: Not const! This can cause SkipFrames!
|
||||
virtual int SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) = 0;
|
||||
|
||||
virtual int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) const = 0;
|
||||
virtual int SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0;
|
||||
virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) = 0;
|
||||
virtual int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) = 0;
|
||||
|
||||
virtual u32 GetNextSamples() = 0; // This should be const, but the legacy impl stops it (it's wrong).
|
||||
virtual void InitLowLevel(const Atrac3LowLevelParams ¶ms, int codecType) = 0;
|
||||
|
||||
virtual void CheckForSas() = 0;
|
||||
virtual int EnqueueForSas(u32 address, u32 ptr) = 0;
|
||||
virtual void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) = 0;
|
||||
virtual const AtracSasStreamState *StreamStateForSas() const { return nullptr; }
|
||||
|
||||
virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0;
|
||||
|
||||
virtual int GetContextVersion() const = 0;
|
||||
|
||||
protected:
|
||||
u16 outputChannels_ = 2;
|
||||
|
||||
// TODO: Save the internal state of this, now technically possible.
|
||||
AudioDecoder *decoder_ = nullptr;
|
||||
};
|
||||
#include "Core/HLE/AtracBase.h"
|
||||
#include "Core/Util/AtracTrack.h"
|
||||
|
||||
class Atrac : public AtracBase {
|
||||
public:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Core/HLE/FunctionWrappers.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/HLE/AtracCtx2.h"
|
||||
#include "Core/Util/AtracTrack.h"
|
||||
#include "Core/HW/Atrac3Standalone.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MemMap.h"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Core/HLE/AtracCtx.h"
|
||||
#include "Core/HLE/AtracBase.h"
|
||||
|
||||
class Atrac2 : public AtracBase {
|
||||
public:
|
||||
|
||||
+1
-98
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "Core/HLE/sceAudiocodec.h"
|
||||
#include "Core/Util/AtracTrack.h"
|
||||
#include "Core/HLE/AtracCtx.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
@@ -31,104 +32,6 @@ int __AtracMaxContexts();
|
||||
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize);
|
||||
void __AtracNotifyUnloadModule();
|
||||
|
||||
// The "state" member of SceAtracIdInfo.
|
||||
enum AtracStatus : u8 {
|
||||
ATRAC_STATUS_UNINITIALIZED = 0, // bad state
|
||||
|
||||
ATRAC_STATUS_NO_DATA = 1,
|
||||
|
||||
// The entire file is loaded into memory, no further file access needed.
|
||||
ATRAC_STATUS_ALL_DATA_LOADED = 2,
|
||||
|
||||
// The buffer is sized to fit the entire file, but it's only partially loaded, so you can start playback before loading the whole file.
|
||||
ATRAC_STATUS_HALFWAY_BUFFER = 3,
|
||||
|
||||
// In these ones, the buffer is smaller than the file, and data is streamed into it as needed for playback.
|
||||
// These are the most complex modes, both to implement and use.
|
||||
ATRAC_STATUS_STREAMED_WITHOUT_LOOP = 4,
|
||||
ATRAC_STATUS_STREAMED_LOOP_FROM_END = 5,
|
||||
// This means there's additional audio after the loop.
|
||||
// i.e. ~~before loop~~ [ ~~this part loops~~ ] ~~after loop~~
|
||||
// The "fork in the road" means a second buffer is needed for the second path.
|
||||
ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER = 6,
|
||||
|
||||
// In this mode, the only API to call is sceAtracLowLevelDecode, which decodes a stream packet by packet without any other metadata.
|
||||
ATRAC_STATUS_LOW_LEVEL = 8,
|
||||
|
||||
// This mode is for using an Atrac context as the audio source for an sceSas channel. Not used a lot (Sol Trigger).
|
||||
ATRAC_STATUS_FOR_SCESAS = 16,
|
||||
|
||||
// Bitwise-and the status with this to check for any of the streaming modes in a single test.
|
||||
ATRAC_STATUS_STREAMED_MASK = 4,
|
||||
};
|
||||
|
||||
const char *AtracStatusToString(AtracStatus status);
|
||||
|
||||
inline bool AtracStatusIsStreaming(AtracStatus status) {
|
||||
return (status & ATRAC_STATUS_STREAMED_MASK) != 0;
|
||||
}
|
||||
inline bool AtracStatusIsNormal(AtracStatus status) {
|
||||
return (int)status >= ATRAC_STATUS_ALL_DATA_LOADED && (int)status <= ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
|
||||
}
|
||||
|
||||
struct SceAtracIdInfo {
|
||||
s32 decodePos; // Sample position in the song that we'll next be decoding from.
|
||||
s32 endSample; // Last sample index of the track.
|
||||
s32 loopStart; // Start of the loop (sample index)
|
||||
s32 loopEnd; // End of the loop (sample index)
|
||||
s32 firstValidSample; // Seems to be the number of skipped samples at the start. After SetID, decodePos will match this. Was previously misnamed 'samplesPerChan'.
|
||||
u8 numSkipFrames; // This is 1 for a single frame when a loop is triggered, otherwise seems to stay at 0. Likely mis-named.
|
||||
AtracStatus state; // State enum, see AtracStatus.
|
||||
u8 curBuffer; // Current buffer (1 == second, 2 == done?) Previously unk
|
||||
u8 numChan; // Number of audio channels, usually 2 but 1 is possible.
|
||||
u16 sampleSize; // Size in bytes of an encoded audio frame.
|
||||
u16 codec; // Codec. 0x1000 is Atrac3+, 0x1001 is Atrac3. See the PSP_CODEC_ enum (only these two are supported).
|
||||
s32 dataOff; // File offset in bytes where the Atrac3+ frames start appearing. The first dummy packet starts here.
|
||||
s32 curFileOff; // File offset in bytes corresponding to the start of next packet that will be *decoded* (on the next call to sceAtracDecodeData).
|
||||
s32 fileDataEnd; // File size in bytes.
|
||||
s32 loopNum; // Current loop counter. If 0, will not loop. -1 loops for ever, positive numbers get decremented on the loop end. So to play a song 3 times and then end, set this to 2.
|
||||
s32 streamDataByte; // Number of bytes of queued/buffered/uploaded data. In full and half-way modes, this isn't decremented as you decode.
|
||||
s32 streamOff; // Streaming modes only: The byte offset inside the RAM buffer where sceAtracDecodeData will read from next. ONLY points to even packet boundaries.
|
||||
s32 secondStreamOff; // A kind of stream position in the secondary buffer.
|
||||
u32 buffer; // Address in RAM of the main buffer.
|
||||
u32 secondBuffer; // Address in RAM of the second buffer, or 0 if not used.
|
||||
u32 bufferByte; // Size in bytes of the main buffer.
|
||||
u32 secondBufferByte; // Size in bytes of the second buffer.
|
||||
// Offset 72 here.
|
||||
// make sure the size is 128
|
||||
u32 unk[14];
|
||||
|
||||
// Simple helpers. Similar ones are on track_, but we shouldn't need track_ anymore when playing back.
|
||||
|
||||
int SamplesPerFrame() const {
|
||||
return codec == 0x1000 ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES;
|
||||
}
|
||||
int SamplesFrameMask() const {
|
||||
return SamplesPerFrame() - 1;
|
||||
}
|
||||
int SkipSamples() const {
|
||||
// These first samples are skipped, after first possibly skipping 0-2 full frames, it seems.
|
||||
return codec == 0x1000 ? 0x170 : 0x45;
|
||||
}
|
||||
};
|
||||
|
||||
// One of these structs is allocated for each Atrac context.
|
||||
// The raw codec state is stored in 'codec'.
|
||||
// The internal playback state is stored in 'info', and that is used for all state keeping in the Atrac2 implementation,
|
||||
// imitating what happens on hardware as closely as possible.
|
||||
struct SceAtracContext {
|
||||
// size 128
|
||||
SceAudiocodecCodec codec;
|
||||
// size 128
|
||||
SceAtracIdInfo info;
|
||||
};
|
||||
|
||||
struct Atrac3LowLevelParams {
|
||||
int encodedChannels;
|
||||
int outputChannels;
|
||||
int bytesPerFrame;
|
||||
};
|
||||
|
||||
constexpr int PSP_MAX_ATRAC_IDS = 6;
|
||||
|
||||
class AtracBase;
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Core/HLE/sceAudiocodec.h"
|
||||
|
||||
constexpr u32 ATRAC3_MAX_SAMPLES = 0x400; // 1024
|
||||
constexpr u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; // 2048
|
||||
#include "Core/HLE/AtracBase.h"
|
||||
|
||||
struct AtracLoopInfo {
|
||||
int cuePointID;
|
||||
|
||||
Reference in new issue
Block a user