mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Reimplement a lot of logic, implement loop streaming properly
This commit is contained in:
@@ -342,7 +342,10 @@ int AnalyzeAtracTrack(u32 addr, u32 size, Track *track) {
|
||||
|
||||
if (at3fmt->fmtTag == AT3_MAGIC) {
|
||||
// This is the offset to the jointStereo_ field.
|
||||
track->jointStereo = Memory::Read_U32(addr + offset + 24);
|
||||
track->jointStereo = Memory::Read_U16(addr + offset + 24);
|
||||
// Then there are more fields here.
|
||||
u16 unknown1_2 = Memory::Read_U16(addr + offset + 30);
|
||||
|
||||
}
|
||||
if (chunkSize > 16) {
|
||||
// Read and format extra bytes as hexadecimal
|
||||
@@ -393,7 +396,7 @@ int AnalyzeAtracTrack(u32 addr, u32 size, Track *track) {
|
||||
track->loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16);
|
||||
track->loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20);
|
||||
|
||||
if (track->loopinfo[i].startSample >= track->loopinfo[i].endSample) {
|
||||
if (i == 0 && track->loopinfo[i].startSample >= track->loopinfo[i].endSample) {
|
||||
ERROR_LOG(Log::ME, "AnalyzeTrack: loop starts after it ends");
|
||||
return SCE_ERROR_ATRAC_BAD_CODEC_PARAMS;
|
||||
}
|
||||
|
||||
@@ -42,9 +42,6 @@ struct AtracResetBufferInfo {
|
||||
#define PSP_MODE_AT_3_PLUS 0x00001000
|
||||
#define PSP_MODE_AT_3 0x00001001
|
||||
|
||||
const u32 ATRAC3_MAX_SAMPLES = 0x400;
|
||||
const u32 ATRAC3PLUS_MAX_SAMPLES = 0x800;
|
||||
|
||||
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;
|
||||
|
||||
+585
-398
File diff suppressed because it is too large
Load Diff
@@ -56,8 +56,13 @@ public:
|
||||
u32 GetInternalCodecError() const override;
|
||||
|
||||
private:
|
||||
void InitContext(int offset, u32 bufferAddr, u32 readSize, u32 bufferSize, int sampleOffset);
|
||||
void FastForwardDummyFrames(int discardedSamples);
|
||||
u32 DecodeInternal(u32 outbufAddr, u32 *SamplesNum, u32 *finish);
|
||||
void GetResetBufferInfoInternal(AtracResetBufferInfo *bufferInfo, int sample);
|
||||
u32 ResetPlayPositionInternal(int seekPos, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf);
|
||||
|
||||
u32 InitContext(u32 bufferAddr, u32 readSize, u32 bufferSize);
|
||||
u32 SkipFrames();
|
||||
void WrapLastPacket();
|
||||
|
||||
void SeekToSample(int sample);
|
||||
|
||||
|
||||
+14
-7
@@ -38,9 +38,10 @@
|
||||
#include "Core/HLE/AtracCtx2.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
// (Old) notes about sceAtrac buffer management
|
||||
// Notes about sceAtrac buffer management
|
||||
//
|
||||
// sceAtrac decodes from a buffer the game fills, where this buffer has a status, one of:
|
||||
//
|
||||
// * Not yet initialized (state NO_DATA = 1)
|
||||
// * The entire size of the audio data, and filled with audio data (state ALL_DATA_LOADED = 2)
|
||||
// * The entire size, but only partially filled so far (state HALFWAY_BUFFER = 3)
|
||||
@@ -50,9 +51,11 @@
|
||||
// * Not managed, decoding using "low level" manual looping etc. (LOW_LEVEL = 8)
|
||||
// * Not managed, reserved externally - possibly by sceSas - through low level (RESERVED = 16)
|
||||
//
|
||||
// A game will call sceAtracAddStreamData after filling data, and where it filled it was given by
|
||||
// either sceAtracGetStreamDataInfo when continuing to move forwards in the stream of audio data,
|
||||
// or sceAtracGetBufferInfoForResetting when seeking to a specific location in the audio stream.
|
||||
// When streaming (modes 3-6), a game will call sceAtracGetStreamDataInfo to figure out what data
|
||||
// to read and where to place it, and after doing that it'll call sceAtracAddStreamData with the amount
|
||||
// of data it actually read. This will move the various pointers forward.
|
||||
// Similarly, for a game to seek, it'll call sceAtracGetBufferInfoForResetting with a sample offset,
|
||||
// and read that data into the buffer.
|
||||
//
|
||||
// State 6 indicates a second buffer is needed. This buffer is used to manage looping correctly.
|
||||
// To determine how to fill it, the game will call sceAtracGetSecondBufferInfo, then after filling
|
||||
@@ -60,10 +63,11 @@
|
||||
//
|
||||
// The second buffer will just contain the data for the end of loop. The "first" buffer may manage
|
||||
// only the looped portion, or some of the part after the loop (depending on second buf size.)
|
||||
//
|
||||
// TODO: What games use this?
|
||||
//
|
||||
// Most files will be in RIFF format. It's also possible to load in an OMA/AA3 format file, but
|
||||
// ultimately this will share the same buffer - it's just offset a bit more.
|
||||
// ultimately this works the same, just the loading process is a little different.
|
||||
//
|
||||
// Low level decoding doesn't use the buffer, and decodes only a single packet at a time.
|
||||
//
|
||||
@@ -302,7 +306,7 @@ static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32
|
||||
numSamplesAddr, numSamples,
|
||||
finishFlagAddr, finish,
|
||||
remainAddr, remains);
|
||||
if (ret == 0) {
|
||||
if (ret == 0 || ret == SCE_ERROR_ATRAC_API_FAIL) {
|
||||
// decode data successfully, delay thread
|
||||
return hleDelayResult(hleNoLog(ret), "atrac decode data", atracDecodeDelay);
|
||||
}
|
||||
@@ -337,6 +341,8 @@ static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 buffer
|
||||
}
|
||||
*/
|
||||
|
||||
// Note: If we error here, it's because of the internal SkipFrames.
|
||||
// Note again: We should probably delayresult if we skipframes..
|
||||
int ret = atrac->GetResetBufferInfo(bufferInfo, sample);
|
||||
return hleLogDebugOrError(Log::ME, ret);
|
||||
}
|
||||
@@ -586,7 +592,8 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi
|
||||
return hleLogError(Log::ME, res);
|
||||
}
|
||||
}
|
||||
return hleDelayResult(hleLogDebug(Log::ME, res), "reset play pos", 3000);
|
||||
|
||||
return hleDelayResult(res, "reset play pos", 3000);
|
||||
}
|
||||
|
||||
static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 bufferSize) {
|
||||
|
||||
+19
-2
@@ -29,6 +29,9 @@ void __AtracShutdown();
|
||||
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize);
|
||||
void __AtracNotifyUnloadModule();
|
||||
|
||||
constexpr u32 ATRAC3_MAX_SAMPLES = 0x400; // 1024
|
||||
constexpr u32 ATRAC3PLUS_MAX_SAMPLES = 0x800; // 2048
|
||||
|
||||
// The "state" member of SceAtracIdInfo.
|
||||
enum AtracStatus : u8 {
|
||||
ATRAC_STATUS_NO_DATA = 1,
|
||||
@@ -70,7 +73,7 @@ struct SceAtracIdInfo {
|
||||
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 framesToSkip; // This is 1 for a single frame when a loop is triggered, otherwise seems to stay at 0. Likely mis-named.
|
||||
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.
|
||||
@@ -82,7 +85,7 @@ struct SceAtracIdInfo {
|
||||
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.
|
||||
u32 secondStreamOff; // Secondary streamoff? previously unk.
|
||||
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.
|
||||
@@ -91,6 +94,19 @@ struct SceAtracIdInfo {
|
||||
// make sure the size is 128
|
||||
u32 unk[13];
|
||||
u32 atracID; // The atrac context number is stored here, for some reason.
|
||||
|
||||
// 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.
|
||||
@@ -108,6 +124,7 @@ constexpr int PSP_MAX_ATRAC_IDS = 6;
|
||||
|
||||
class AtracBase;
|
||||
|
||||
// For debugger use ONLY.
|
||||
const AtracBase *__AtracGetCtx(int i, u32 *type);
|
||||
|
||||
// External interface used by sceSas, see ATRAC_STATUS_FOR_SCESAS.
|
||||
|
||||
@@ -3450,7 +3450,14 @@ bool __KernelCheckCallbacks() {
|
||||
}
|
||||
|
||||
if (processed) {
|
||||
return __KernelExecutePendingMipsCalls(__GetCurrentThread(), true);
|
||||
PSPThread *thread = __GetCurrentThread();
|
||||
if (thread) {
|
||||
return __KernelExecutePendingMipsCalls(thread, true);
|
||||
} else {
|
||||
ERROR_LOG(Log::sceKernel, "No current thread in __KernelCheckCallbacks!");
|
||||
// stumble along?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ static void NotifyLoadStatusAtrac(int state, u32 loadAddr, u32 totalSize) {
|
||||
if (state == 1) {
|
||||
// We try to imitate a recent version of the prx.
|
||||
// Let's just give it a piece of the space.
|
||||
constexpr int version = 0x103;
|
||||
constexpr int version = 0x105; // latest.
|
||||
constexpr int bssSize = 0x67C;
|
||||
_dbg_assert_(bssSize <= totalSize);
|
||||
__AtracNotifyLoadModule(version, 0, loadAddr, bssSize);
|
||||
@@ -115,9 +115,10 @@ static const ModuleLoadInfo moduleLoadInfo[] = {
|
||||
ModuleLoadInfo(0x202, 0x00000000, "usb_gps"),
|
||||
ModuleLoadInfo(0x203, 0x00000000, "usb_unk_0x203"),
|
||||
ModuleLoadInfo(0x2ff, 0x00000000, "unk_0x2ff"),
|
||||
ModuleLoadInfo(0x300, 0x00000000, "av_avcodec", &NotifyLoadStatusAvcodec),
|
||||
ModuleLoadInfo(0x300, 0x00000000, "av_avcodec", &NotifyLoadStatusAvcodec), // AudioCodec
|
||||
ModuleLoadInfo(0x301, 0x00000000, "av_sascore"),
|
||||
ModuleLoadInfo(0x302, 0x00004000, "av_atrac3plus", atrac3PlusModuleDeps, &NotifyLoadStatusAtrac), // TODO: 0x8000 is likely too large.
|
||||
// TODO: We should put the Atrac contexts inside the allocated bss space. Also, current actual full size (including text, on latest fw) seems to be 0x45C0.
|
||||
ModuleLoadInfo(0x302, 0x00004000, "av_atrac3plus", atrac3PlusModuleDeps, &NotifyLoadStatusAtrac),
|
||||
ModuleLoadInfo(0x303, 0x0000c000, "av_mpegbase", mpegBaseModuleDeps),
|
||||
ModuleLoadInfo(0x304, 0x00004000, "av_mp3"),
|
||||
ModuleLoadInfo(0x305, 0x0000a300, "av_vaudio"),
|
||||
|
||||
@@ -1050,7 +1050,7 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) {
|
||||
ImGui::Text("Stream: offset %d, streamDataBytes: %d", info.streamOff, info.streamDataByte);
|
||||
}
|
||||
// Display unknown vars.
|
||||
ImGui::Text("numFrame: %d unk22: %d unk52: %d", info.numFrame, info.unk22, info.unk52);
|
||||
ImGui::Text("numFrame: %d curBuffer: %d streamOff2: %d", info.numSkipFrames, info.curBuffer, info.secondStreamOff);
|
||||
} else {
|
||||
ImGui::Text("loop: %d", ctx->LoopNum());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user