Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/AtracCtx.cpp
3187 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Common/Serialize/Serializer.h"
19
#include "Common/Serialize/SerializeFuncs.h"
20
#include "Common/Log.h"
21
#include "Core/Reporting.h"
22
#include "Core/MemMapHelpers.h"
23
#include "Core/System.h"
24
#include "Core/HLE/HLE.h"
25
#include "Core/HLE/ErrorCodes.h"
26
#include "Core/HLE/FunctionWrappers.h"
27
#include "Core/HLE/sceAtrac.h"
28
#include "Core/HLE/AtracCtx.h"
29
#include "Core/HW/Atrac3Standalone.h"
30
#include "Core/HLE/sceKernelMemory.h"
31
32
33
const size_t overAllocBytes = 16384;
34
35
Atrac::~Atrac() {
36
ResetData();
37
}
38
39
void Atrac::DoState(PointerWrap &p) {
40
auto s = p.Section("Atrac", 1, 9);
41
if (!s)
42
return;
43
44
Do(p, track_.channels);
45
Do(p, outputChannels_);
46
if (s >= 5) {
47
Do(p, track_.jointStereo);
48
}
49
50
Do(p, atracID_);
51
if (p.mode != p.MODE_READ) {
52
first_._filesize_dontuse = track_.fileSize;
53
}
54
Do(p, first_);
55
if (p.mode == p.MODE_READ) {
56
track_.fileSize = first_._filesize_dontuse;
57
}
58
59
Do(p, bufferMaxSize_);
60
Do(p, track_.codecType);
61
62
Do(p, currentSample_);
63
Do(p, track_.endSample);
64
Do(p, track_.firstSampleOffset);
65
if (s >= 3) {
66
Do(p, track_.dataByteOffset);
67
} else {
68
track_.dataByteOffset = track_.firstSampleOffset;
69
}
70
71
u32 hasDataBuf = dataBuf_ != nullptr;
72
Do(p, hasDataBuf);
73
if (hasDataBuf) {
74
if (p.mode == p.MODE_READ) {
75
if (dataBuf_)
76
delete[] dataBuf_;
77
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
78
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
79
}
80
DoArray(p, dataBuf_, track_.fileSize);
81
}
82
Do(p, second_);
83
84
Do(p, decodePos_);
85
if (s < 9) {
86
u32 oldDecodeEnd = 0;
87
Do(p, oldDecodeEnd);
88
}
89
if (s >= 4) {
90
Do(p, bufferPos_);
91
} else {
92
bufferPos_ = decodePos_;
93
}
94
95
Do(p, track_.bitrate);
96
Do(p, track_.bytesPerFrame);
97
98
Do(p, track_.loopinfo);
99
if (s < 9) {
100
int oldLoopInfoNum = 42;
101
Do(p, oldLoopInfoNum);
102
}
103
104
Do(p, track_.loopStartSample);
105
Do(p, track_.loopEndSample);
106
Do(p, loopNum_);
107
108
Do(p, context_);
109
if (s >= 6) {
110
Do(p, bufferState_);
111
} else {
112
if (dataBuf_ == nullptr) {
113
bufferState_ = ATRAC_STATUS_NO_DATA;
114
} else {
115
UpdateBufferState();
116
}
117
}
118
119
if (s >= 7) {
120
Do(p, ignoreDataBuf_);
121
} else {
122
ignoreDataBuf_ = false;
123
}
124
125
if (s >= 9) {
126
Do(p, bufferValidBytes_);
127
Do(p, bufferHeaderSize_);
128
} else {
129
bufferHeaderSize_ = track_.dataByteOffset;
130
bufferValidBytes_ = std::min(first_.size - track_.dataByteOffset, StreamBufferEnd() - track_.dataByteOffset);
131
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
132
bufferPos_ = track_.dataByteOffset;
133
}
134
}
135
136
if (s < 8 && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
137
// We didn't actually allow the second buffer to be set this far back.
138
// Pretend it's a regular loop, we'll just try our best.
139
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
140
}
141
142
// Make sure to do this late; it depends on track parameters.
143
if (p.mode == p.MODE_READ && bufferState_ != ATRAC_STATUS_NO_DATA) {
144
CreateDecoder(track_.codecType, track_.bytesPerFrame, track_.channels);
145
}
146
147
if (s >= 2 && s < 9) {
148
bool oldResetBuffer = false;
149
Do(p, oldResetBuffer);
150
}
151
}
152
153
void Atrac::ResetData() {
154
delete decoder_;
155
decoder_ = nullptr;
156
157
if (dataBuf_)
158
delete[] dataBuf_;
159
dataBuf_ = 0;
160
ignoreDataBuf_ = false;
161
bufferState_ = ATRAC_STATUS_NO_DATA;
162
163
if (context_.IsValid())
164
kernelMemory.Free(context_.ptr);
165
}
166
167
u8 *Atrac::BufferStart() {
168
return ignoreDataBuf_ ? Memory::GetPointerWrite(first_.addr) : dataBuf_;
169
}
170
171
AtracBase::~AtracBase() {
172
delete decoder_;
173
}
174
175
void Atrac::UpdateContextFromPSPMem() {
176
if (!context_.IsValid()) {
177
return;
178
}
179
180
// Read in any changes from the game to the context.
181
// TODO: Might be better to just always track in RAM. Actually, Atrac2 will do that.
182
bufferState_ = context_->info.state;
183
// This value is actually abused by games to store the SAS voice number.
184
loopNum_ = context_->info.loopNum;
185
}
186
187
void Atrac::WriteContextToPSPMem() {
188
if (!context_.IsValid()) {
189
return;
190
}
191
// context points into PSP memory.
192
SceAtracContext *context = context_;
193
context->info.buffer = first_.addr;
194
context->info.bufferByte = bufferMaxSize_;
195
context->info.secondBuffer = second_.addr;
196
context->info.secondBufferByte = second_.size;
197
context->info.codec = track_.codecType;
198
context->info.loopNum = loopNum_;
199
context->info.loopStart = track_.loopStartSample > 0 ? track_.loopStartSample : 0;
200
context->info.loopEnd = track_.loopEndSample > 0 ? track_.loopEndSample : 0;
201
202
// Note that we read in the state when loading the atrac object, so it's safe
203
// to update it back here all the time. Some games, like Sol Trigger, change it.
204
// TODO: Should we just keep this in PSP ram then, or something?
205
context->info.state = bufferState_;
206
if (track_.firstSampleOffset != 0) {
207
context->info.firstValidSample = track_.FirstSampleOffsetFull();
208
} else {
209
context->info.firstValidSample = (track_.codecType == PSP_CODEC_AT3PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
210
}
211
context->info.sampleSize = track_.bytesPerFrame;
212
context->info.numChan = track_.channels;
213
context->info.dataOff = track_.dataByteOffset;
214
context->info.endSample = track_.endSample + track_.FirstSampleOffsetFull();
215
context->info.fileDataEnd = track_.fileSize;
216
context->info.curFileOff = first_.fileoffset;
217
context->info.decodePos = track_.DecodePosBySample(currentSample_);
218
context->info.streamDataByte = first_.size - track_.dataByteOffset;
219
220
u8 *buf = (u8 *)context;
221
*(u32_le *)(buf + 0xfc) = atracID_;
222
223
NotifyMemInfo(MemBlockFlags::WRITE, context_.ptr, sizeof(SceAtracContext), "AtracContext");
224
}
225
226
void Track::DebugLog() const {
227
DEBUG_LOG(Log::Atrac, "ATRAC analyzed: %s channels: %d filesize: %d bitrate: %d kbps jointStereo: %d",
228
codecType == PSP_CODEC_AT3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo);
229
DEBUG_LOG(Log::Atrac, "dataoff: %d firstSampleOffset: %d endSample: %d", dataByteOffset, firstSampleOffset, endSample);
230
DEBUG_LOG(Log::Atrac, "loopStartSample: %d loopEndSample: %d", loopStartSample, loopEndSample);
231
DEBUG_LOG(Log::Atrac, "sampleSize: %d (%03x)", bytesPerFrame, bytesPerFrame);
232
}
233
234
int Atrac::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const {
235
*endSample = track_.endSample;
236
*loopStartSample = track_.loopStartSample == -1 ? -1 : track_.loopStartSample - track_.FirstSampleOffsetFull();
237
*loopEndSample = track_.loopEndSample == -1 ? -1 : track_.loopEndSample - track_.FirstSampleOffsetFull();
238
return 0;
239
}
240
241
int Atrac::GetNextDecodePosition(int *pos) const {
242
if (currentSample_ >= track_.endSample) {
243
*pos = 0;
244
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
245
} else {
246
*pos = currentSample_;
247
return 0;
248
}
249
}
250
251
void Atrac::CalculateStreamInfo(u32 *outReadOffset) {
252
u32 readOffset = first_.fileoffset;
253
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
254
// Nothing to write.
255
readOffset = 0;
256
first_.offset = 0;
257
first_.writableBytes = 0;
258
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
259
// If we're buffering the entire file, just give the same as readOffset.
260
first_.offset = readOffset;
261
// In this case, the bytes writable are just the remaining bytes, always.
262
first_.writableBytes = track_.fileSize - readOffset;
263
} else {
264
u32 bufferEnd = StreamBufferEnd();
265
u32 bufferValidExtended = bufferPos_ + bufferValidBytes_;
266
if (bufferValidExtended < bufferEnd) {
267
first_.offset = bufferValidExtended;
268
first_.writableBytes = bufferEnd - bufferValidExtended;
269
} else {
270
u32 bufferStartUsed = bufferValidExtended - bufferEnd;
271
first_.offset = bufferStartUsed;
272
first_.writableBytes = bufferPos_ - bufferStartUsed;
273
}
274
275
if (readOffset >= track_.fileSize) {
276
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
277
// We don't need anything more, so all 0s.
278
readOffset = 0;
279
first_.offset = 0;
280
first_.writableBytes = 0;
281
} else {
282
readOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
283
}
284
}
285
286
if (readOffset + first_.writableBytes > track_.fileSize) {
287
// Never ask for past the end of file, even when the space is free.
288
first_.writableBytes = track_.fileSize - readOffset;
289
}
290
291
// If you don't think this should be here, remove it. It's just a temporary safety check.
292
if (first_.offset + first_.writableBytes > bufferMaxSize_) {
293
ERROR_LOG_REPORT(Log::Atrac, "Somehow calculated too many writable bytes: %d + %d > %d", first_.offset, first_.writableBytes, bufferMaxSize_);
294
first_.offset = 0;
295
first_.writableBytes = bufferMaxSize_;
296
}
297
}
298
299
if (outReadOffset) {
300
*outReadOffset = readOffset;
301
}
302
}
303
304
void AtracBase::CreateDecoder(int codecType, int bytesPerFrame, int channels) {
305
if (decoder_) {
306
delete decoder_;
307
}
308
309
// First, init the standalone decoder.
310
if (codecType == PSP_CODEC_AT3) {
311
// TODO: This is maybe not entirely reliable? Mui Mui house in LocoRoco 2 fails. Although also fails
312
// when I override this, so maybe the issue is something different...
313
bool jointStereo = IsAtrac3StreamJointStereo(codecType, bytesPerFrame, channels);
314
315
// We don't pull this from the RIFF so that we can support OMA also.
316
uint8_t extraData[14]{};
317
// The only thing that changes are the jointStereo_ values.
318
extraData[0] = 1;
319
extraData[3] = channels << 3;
320
extraData[6] = jointStereo;
321
extraData[8] = jointStereo;
322
extraData[10] = 1;
323
decoder_ = CreateAtrac3Audio(channels, bytesPerFrame, extraData, sizeof(extraData));
324
} else {
325
decoder_ = CreateAtrac3PlusAudio(channels, bytesPerFrame);
326
}
327
}
328
329
int Atrac::GetBufferInfoForResetting(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) {
330
*delay = false;
331
if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && !HasSecondBuffer()) {
332
return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED;
333
} else if ((u32)sample + track_.firstSampleOffset > (u32)track_.endSample + track_.firstSampleOffset) {
334
// NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound.
335
return SCE_ERROR_ATRAC_BAD_SAMPLE;
336
}
337
338
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
339
bufferInfo->first.writePosPtr = first_.addr;
340
// Everything is loaded, so nothing needs to be read.
341
bufferInfo->first.writableBytes = 0;
342
bufferInfo->first.minWriteBytes = 0;
343
bufferInfo->first.filePos = 0;
344
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
345
// Here the message is: you need to read at least this many bytes to get to that position.
346
// This is because we're filling the buffer start to finish, not streaming.
347
bufferInfo->first.writePosPtr = first_.addr + first_.size;
348
bufferInfo->first.writableBytes = track_.fileSize - first_.size;
349
int minWriteBytes = track_.FileOffsetBySample(sample) - first_.size;
350
if (minWriteBytes > 0) {
351
bufferInfo->first.minWriteBytes = minWriteBytes;
352
} else {
353
bufferInfo->first.minWriteBytes = 0;
354
}
355
bufferInfo->first.filePos = first_.size;
356
} else {
357
// This is without the sample offset. The file offset also includes the previous batch of samples?
358
int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame());
359
360
// Update the writable bytes. When streaming, this is just the number of bytes until the end.
361
const u32 bufSizeAligned = (bufferMaxSize_ / track_.bytesPerFrame) * track_.bytesPerFrame;
362
const int needsMoreFrames = track_.FirstOffsetExtra(); // ?
363
364
bufferInfo->first.writePosPtr = first_.addr;
365
bufferInfo->first.writableBytes = std::min(track_.fileSize - sampleFileOffset, bufSizeAligned);
366
if (((sample + track_.firstSampleOffset) % (int)track_.SamplesPerFrame()) >= (int)track_.SamplesPerFrame() - needsMoreFrames) {
367
// Not clear why, but it seems it wants a bit extra in case the sample is late?
368
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 3;
369
} else {
370
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 2;
371
}
372
if ((u32)sample < (u32)track_.firstSampleOffset && sampleFileOffset != track_.dataByteOffset) {
373
sampleFileOffset -= track_.bytesPerFrame;
374
}
375
bufferInfo->first.filePos = sampleFileOffset;
376
377
if (second_.size != 0) {
378
// TODO: We have a second buffer. Within it, minWriteBytes should be zero.
379
// The filePos should be after the end of the second buffer (or zero.)
380
// We actually need to ensure we READ from the second buffer before implementing that.
381
}
382
}
383
384
// It seems like this is always the same as the first buffer's pos, weirdly.
385
bufferInfo->second.writePosPtr = first_.addr;
386
// Reset never needs a second buffer write, since the loop is in a fixed place.
387
bufferInfo->second.writableBytes = 0;
388
bufferInfo->second.minWriteBytes = 0;
389
bufferInfo->second.filePos = 0;
390
return 0;
391
}
392
393
int Atrac::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, u32 fileSize, int outputChannels, bool isAA3) {
394
// 72 is about the size of the minimum required data to even be valid.
395
if (readSize < 72) {
396
return SCE_ERROR_ATRAC_SIZE_TOO_SMALL;
397
}
398
399
// TODO: Check the range (addr, size) instead.
400
if (!Memory::IsValidAddress(buffer)) {
401
return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
402
}
403
404
first_ = {};
405
first_.addr = buffer;
406
first_.size = readSize;
407
408
currentSample_ = 0;
409
loopNum_ = 0;
410
decodePos_ = 0;
411
bufferPos_ = 0;
412
outputChannels_ = outputChannels;
413
414
track.DebugLog();
415
track_ = track;
416
first_._filesize_dontuse = track_.fileSize;
417
418
if (outputChannels != track_.channels) {
419
WARN_LOG(Log::Atrac, "Atrac::SetData: outputChannels %d doesn't match track_.channels %d", outputChannels, track_.channels);
420
}
421
422
first_.addr = buffer;
423
first_.size = readSize;
424
425
if (first_.size > track_.fileSize)
426
first_.size = track_.fileSize;
427
first_.fileoffset = first_.size;
428
429
// got the size of temp buf, and calculate offset
430
bufferMaxSize_ = bufferSize;
431
first_.offset = first_.size;
432
433
// some games may reuse an atracID for playing sound
434
ResetData();
435
UpdateBufferState();
436
437
if (track_.codecType != PSP_CODEC_AT3 && track_.codecType != PSP_CODEC_AT3PLUS) {
438
// Shouldn't have gotten here, Analyze() checks this.
439
bufferState_ = ATRAC_STATUS_NO_DATA;
440
ERROR_LOG(Log::Atrac, "unexpected codec type %d in set data", track_.codecType);
441
return SCE_ERROR_ATRAC_UNKNOWN_FORMAT;
442
}
443
444
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED || bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
445
// This says, don't use the dataBuf_ array, use the PSP RAM.
446
// This way, games can load data async into the buffer, and it still works.
447
// TODO: Support this always, even for streaming.
448
ignoreDataBuf_ = true;
449
}
450
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
451
bufferHeaderSize_ = track_.dataByteOffset;
452
bufferPos_ = track_.dataByteOffset + track_.bytesPerFrame;
453
bufferValidBytes_ = first_.size - bufferPos_;
454
}
455
456
const char *codecName = track_.codecType == PSP_CODEC_AT3 ? "atrac3" : "atrac3+";
457
const char *channelName = track_.channels == 1 ? "mono" : "stereo";
458
459
// Over-allocate databuf to prevent going off the end if the bitstream is bad or if there are
460
// bugs in the decoder. This happens, see issue #15788. Arbitrary, but let's make it a whole page on the popular
461
// architecture that has the largest pages (M1).
462
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
463
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
464
if (!ignoreDataBuf_) {
465
u32 copybytes = std::min(bufferSize, track_.fileSize);
466
Memory::Memcpy(dataBuf_, buffer, copybytes, "AtracSetData");
467
}
468
CreateDecoder(track.codecType, track.bytesPerFrame, track.channels);
469
INFO_LOG(Log::Atrac, "Atrac::SetData (buffer=%08x, readSize=%d, bufferSize=%d): %s %s (%d channels) audio", buffer, readSize, bufferSize, codecName, channelName, track_.channels);
470
INFO_LOG(Log::Atrac, "BufferState: %s", AtracStatusToString(bufferState_));
471
INFO_LOG(Log::Atrac,
472
"buffer: %08x bufferSize: %d readSize: %d bufferPos: %d\n",
473
buffer, bufferSize, readSize, bufferPos_
474
);
475
476
if (track_.channels == 2 && outputChannels == 1) {
477
// We still do all the tasks, we just return this error.
478
WARN_LOG(Log::Atrac, "Tried to load a stereo track into a mono context, returning NOT_MONO");
479
return SCE_ERROR_ATRAC_NOT_MONO;
480
}
481
return 0;
482
}
483
484
int Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
485
u32 secondFileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
486
u32 desiredSize = track_.fileSize - secondFileOffset;
487
488
// 3 seems to be the number of frames required to handle a loop.
489
if (secondBufferSize < desiredSize && secondBufferSize < (u32)track_.BytesPerFrame() * 3) {
490
return SCE_ERROR_ATRAC_SIZE_TOO_SMALL;
491
}
492
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
493
return SCE_ERROR_ATRAC_SECOND_BUFFER_NOT_NEEDED;
494
}
495
496
second_.addr = secondBuffer;
497
second_.size = secondBufferSize;
498
second_.fileoffset = secondFileOffset;
499
return 0;
500
}
501
502
int Atrac::GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) const {
503
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
504
// Writes zeroes in this error case.
505
*fileOffset = 0;
506
*desiredSize = 0;
507
return SCE_ERROR_ATRAC_SECOND_BUFFER_NOT_NEEDED;
508
}
509
510
*fileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
511
*desiredSize = track_.fileSize - *fileOffset;
512
return 0;
513
}
514
515
void Atrac::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) {
516
u32 calculatedReadOffset;
517
CalculateStreamInfo(&calculatedReadOffset);
518
519
*writePtr = first_.addr + first_.offset;
520
*writableBytes = first_.writableBytes;
521
*readOffset = calculatedReadOffset;
522
}
523
524
void Atrac::UpdateBufferState() {
525
if (bufferMaxSize_ >= track_.fileSize) {
526
if (first_.size < track_.fileSize) {
527
// The buffer is big enough in RAM, but we don't have all the data yet.
528
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
529
} else {
530
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
531
}
532
} else {
533
if (track_.loopEndSample <= 0) {
534
// There's no looping, but we need to stream the data in our buffer.
535
bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
536
} else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) {
537
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
538
} else {
539
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
540
}
541
}
542
}
543
544
// The game calls this after actually writing data to the buffer, as specified by the return values from GetStreamDataInfo.
545
// So, we should not have to call CalculateStreamInfo again here (although, might not be a bad idea for safety).
546
int Atrac::AddStreamData(u32 bytesToAdd) {
547
u32 readOffset;
548
CalculateStreamInfo(&readOffset);
549
if (bytesToAdd > first_.writableBytes)
550
return SCE_ERROR_ATRAC_ADD_DATA_IS_TOO_BIG;
551
552
if (bytesToAdd > 0) {
553
first_.fileoffset = readOffset;
554
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset);
555
if (!ignoreDataBuf_) {
556
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr + first_.offset, addbytes, "AtracAddStreamData");
557
}
558
first_.fileoffset += addbytes;
559
}
560
first_.size += bytesToAdd;
561
if (first_.size >= track_.fileSize) {
562
first_.size = track_.fileSize;
563
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
564
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
565
WriteContextToPSPMem();
566
}
567
568
first_.offset += bytesToAdd;
569
bufferValidBytes_ += bytesToAdd;
570
571
if (PSP_CoreParameter().compat.flags().AtracLoopHack && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && RemainingFrames() > 2) {
572
loopNum_++;
573
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
574
}
575
576
return 0;
577
}
578
579
u32 Atrac::GetNextSamples() {
580
if (currentSample_ >= track_.endSample) {
581
return 0;
582
}
583
584
// It seems like the PSP aligns the sample position to 0x800...?
585
int skipSamples = track_.FirstSampleOffsetFull();
586
int firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame();
587
int numSamples = track_.endSample + 1 - currentSample_;
588
if (currentSample_ == 0 && firstSamples != 0) {
589
numSamples = firstSamples;
590
}
591
int unalignedSamples = (skipSamples + currentSample_) % track_.SamplesPerFrame();
592
if (unalignedSamples != 0) {
593
// We're off alignment, possibly due to a loop. Force it back on.
594
numSamples = track_.SamplesPerFrame() - unalignedSamples;
595
}
596
if (numSamples > track_.SamplesPerFrame())
597
numSamples = track_.SamplesPerFrame();
598
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && (int)numSamples + currentSample_ > track_.endSample) {
599
// This probably only happens in PPSSPP due to our internal buffer, which needs to go away.
600
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
601
}
602
return numSamples;
603
}
604
605
void Atrac::ForceSeekToSample(int sample) {
606
if (decoder_) {
607
decoder_->FlushBuffers();
608
}
609
currentSample_ = sample;
610
}
611
612
void Atrac::SeekToSample(int sample) {
613
// It seems like the PSP aligns the sample position to 0x800...?
614
const u32 offsetSamples = track_.FirstSampleOffsetFull();
615
const u32 unalignedSamples = (offsetSamples + sample) % track_.SamplesPerFrame();
616
int seekFrame = sample + offsetSamples - unalignedSamples;
617
618
if ((sample != currentSample_ || sample == 0) && decoder_ != nullptr) {
619
// Prefill the decode buffer with packets before the first sample offset.
620
decoder_->FlushBuffers();
621
622
int adjust = 0;
623
if (sample == 0) {
624
int offsetSamples = track_.FirstSampleOffsetFull();
625
adjust = -(int)(offsetSamples % track_.SamplesPerFrame());
626
}
627
const u32 off = track_.FileOffsetBySample(sample + adjust);
628
const u32 backfill = track_.bytesPerFrame * 2;
629
const u32 start = off - track_.dataByteOffset < backfill ? track_.dataByteOffset : off - backfill;
630
631
for (u32 pos = start; pos < off; pos += track_.bytesPerFrame) {
632
decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, 2, nullptr, nullptr);
633
}
634
}
635
636
currentSample_ = sample;
637
}
638
639
int Atrac::RemainingFrames() const {
640
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
641
// Meaning, infinite I guess? We've got it all.
642
return PSP_ATRAC_ALLDATA_IS_ON_MEMORY;
643
}
644
645
u32 currentFileOffset = track_.FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + track_.FirstOffsetExtra());
646
if (first_.fileoffset >= track_.fileSize) {
647
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
648
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
649
}
650
int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset;
651
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && currentSample_ > loopEndAdjusted) {
652
// No longer looping in this case, outside the loop.
653
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
654
}
655
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK && loopNum_ == 0) {
656
return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY;
657
}
658
}
659
660
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
661
// Since we're streaming, the remaining frames are what's valid in the buffer.
662
return bufferValidBytes_ / track_.bytesPerFrame;
663
}
664
665
// Since the first frame is shorter by this offset, add to round up at this offset.
666
const int remainingBytes = first_.fileoffset - currentFileOffset;
667
if (remainingBytes < 0) {
668
// Just in case. Shouldn't happen, but once did by mistake.
669
return 0;
670
}
671
return remainingBytes / track_.bytesPerFrame;
672
}
673
674
void Atrac::ConsumeFrame() {
675
bufferPos_ += track_.bytesPerFrame;
676
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
677
if (bufferValidBytes_ > track_.bytesPerFrame) {
678
bufferValidBytes_ -= track_.bytesPerFrame;
679
} else {
680
bufferValidBytes_ = 0;
681
}
682
}
683
if (bufferPos_ >= StreamBufferEnd()) {
684
// Wrap around... theoretically, this should only happen at exactly StreamBufferEnd.
685
bufferPos_ -= StreamBufferEnd();
686
bufferHeaderSize_ = 0;
687
}
688
}
689
690
u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) {
691
int loopNum = loopNum_;
692
if (bufferState_ == ATRAC_STATUS_FOR_SCESAS) {
693
// TODO: Might need more testing.
694
loopNum = 0;
695
}
696
697
// We already passed the end - return an error (many games check for this.)
698
if (currentSample_ >= track_.endSample && loopNum == 0) {
699
*SamplesNum = 0;
700
*finish = 1;
701
// refresh context_
702
WriteContextToPSPMem();
703
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
704
}
705
706
int numSamples = 0;
707
708
// It seems like the PSP aligns the sample position to 0x800...?
709
int offsetSamples = track_.FirstSampleOffsetFull();
710
int skipSamples = 0;
711
int maxSamples = track_.endSample + 1 - currentSample_;
712
u32 unalignedSamples = (offsetSamples + currentSample_) % track_.SamplesPerFrame();
713
if (unalignedSamples != 0) {
714
// We're off alignment, possibly due to a loop. Force it back on.
715
maxSamples = track_.SamplesPerFrame() - unalignedSamples;
716
skipSamples = unalignedSamples;
717
}
718
719
if (skipSamples != 0 && bufferHeaderSize_ == 0) {
720
// Skip the initial frame used to load state for the looped frame.
721
// TODO: We will want to actually read this in.
722
// TODO again: This seems to happen on the first frame of playback regardless of loops.
723
// Actually, this is explained now if we look at AtracCtx2, although this isn't really accurate.
724
DEBUG_LOG(Log::Atrac, "Calling ConsumeFrame to skip the initial frame");
725
ConsumeFrame();
726
}
727
728
SeekToSample(currentSample_);
729
730
bool gotFrame = false;
731
u32 off = track_.FileOffsetBySample(currentSample_ - skipSamples);
732
733
DEBUG_LOG(Log::Atrac, "Decode(%08x): nextFileOff: %d", outbufPtr, off);
734
735
if (off < first_.size) {
736
uint8_t *indata = BufferStart() + off;
737
int bytesConsumed = 0;
738
int outSamples = track_.SamplesPerFrame();
739
int outBytes = outSamples * outputChannels_ * sizeof(int16_t);
740
gotFrame = true;
741
742
numSamples = outSamples;
743
uint32_t packetAddr = CurBufferAddress(-skipSamples);
744
// got a frame
745
int skipped = std::min(skipSamples, numSamples);
746
skipSamples -= skipped;
747
numSamples = numSamples - skipped;
748
// If we're at the end, clamp to samples we want. It always returns a full chunk.
749
numSamples = std::min(maxSamples, numSamples);
750
751
outSamples = numSamples;
752
if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, (int16_t *)outbuf, &outSamples)) {
753
// Decode failed.
754
*SamplesNum = 0;
755
*finish = 1;
756
return SCE_ERROR_ATRAC_ALL_DATA_DECODED;
757
}
758
759
if (packetAddr != 0 && MemBlockInfoDetailed()) {
760
char tagData[128];
761
size_t tagSize = FormatMemWriteTagAt(tagData, sizeof(tagData), "AtracDecode/", packetAddr, track_.bytesPerFrame);
762
NotifyMemInfo(MemBlockFlags::READ, packetAddr, track_.bytesPerFrame, tagData, tagSize);
763
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tagData, tagSize);
764
} else {
765
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
766
}
767
// We only want one frame per call, let's continue the next time.
768
}
769
770
if (!gotFrame && currentSample_ < track_.endSample) {
771
// Never got a frame. We may have dropped a GHA frame or otherwise have a bug.
772
// For now, let's try to provide an extra "frame" if possible so games don't infinite loop.
773
if (track_.FileOffsetBySample(currentSample_) < (int)track_.fileSize) {
774
numSamples = std::min(maxSamples, track_.SamplesPerFrame());
775
u32 outBytes = numSamples * outputChannels_ * sizeof(s16);
776
if (outbuf != nullptr) {
777
memset(outbuf, 0, outBytes);
778
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
779
}
780
}
781
}
782
783
*SamplesNum = numSamples;
784
// update current sample and decodePos
785
currentSample_ += numSamples;
786
decodePos_ = track_.DecodePosBySample(currentSample_);
787
788
ConsumeFrame();
789
790
int finishFlag = 0;
791
// TODO: Verify.
792
bool hitEnd = currentSample_ >= track_.endSample || (numSamples == 0 && first_.size >= track_.fileSize);
793
int loopEndAdjusted = track_.loopEndSample - track_.FirstSampleOffsetFull();
794
if ((hitEnd || currentSample_ > loopEndAdjusted) && loopNum != 0) {
795
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
796
if (bufferState_ != ATRAC_STATUS_FOR_SCESAS) {
797
if (loopNum_ > 0)
798
loopNum_--;
799
}
800
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
801
// Whatever bytes we have left were added from the loop.
802
u32 loopOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
803
// TODO: Hmm, need to manage the buffer better. But don't move fileoffset if we already have valid data.
804
if (loopOffset > first_.fileoffset || loopOffset + bufferValidBytes_ < first_.fileoffset) {
805
// Skip the initial frame at the start.
806
first_.fileoffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
807
}
808
}
809
} else if (hitEnd) {
810
finishFlag = 1;
811
812
// Still move forward, so we know that we've read everything.
813
// This seems to be reflected in the context as well.
814
currentSample_ += track_.SamplesPerFrame() - numSamples;
815
}
816
817
*finish = finishFlag;
818
if (remains) {
819
*remains = RemainingFrames();
820
}
821
// refresh context_
822
WriteContextToPSPMem();
823
return 0;
824
}
825
826
int Atrac::SetLoopNum(int loopNum) {
827
if (track_.loopinfo.size() == 0) {
828
return SCE_ERROR_ATRAC_NO_LOOP_INFORMATION;
829
}
830
831
// Spammed in MHU
832
loopNum_ = loopNum;
833
// Logic here looks wacky?
834
if (loopNum != 0 && track_.loopinfo.size() == 0) {
835
// Just loop the whole audio
836
// This is a rare modification of track_ after the fact.
837
// Maybe we can get away with setting these by default.
838
track_.loopStartSample = track_.FirstSampleOffsetFull();
839
track_.loopEndSample = track_.endSample + track_.FirstSampleOffsetFull();
840
}
841
WriteContextToPSPMem();
842
return 0;
843
}
844
845
int Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) {
846
*delay = false;
847
848
if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && !HasSecondBuffer()) {
849
return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED;
850
} else if ((u32)sample + track_.firstSampleOffset > (u32)track_.endSample + track_.firstSampleOffset) {
851
// NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound.
852
return SCE_ERROR_ATRAC_BAD_SAMPLE;
853
}
854
855
// Reuse the same calculation as before.
856
AtracResetBufferInfo bufferInfo;
857
bool ignored;
858
GetBufferInfoForResetting(&bufferInfo, sample, &ignored);
859
860
if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) {
861
return SCE_ERROR_ATRAC_BAD_FIRST_RESET_SIZE;
862
}
863
if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) {
864
return SCE_ERROR_ATRAC_BAD_SECOND_RESET_SIZE;
865
}
866
867
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
868
// Always adds zero bytes.
869
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
870
// Okay, it's a valid number of bytes. Let's set them up.
871
if (bytesWrittenFirstBuf != 0) {
872
if (!ignoreDataBuf_) {
873
Memory::Memcpy(dataBuf_ + first_.size, first_.addr + first_.size, bytesWrittenFirstBuf, "AtracResetPlayPosition");
874
}
875
first_.fileoffset += bytesWrittenFirstBuf;
876
first_.size += bytesWrittenFirstBuf;
877
first_.offset += bytesWrittenFirstBuf;
878
}
879
880
// Did we transition to a full buffer?
881
if (first_.size >= track_.fileSize) {
882
first_.size = track_.fileSize;
883
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
884
}
885
} else {
886
if (bufferInfo.first.filePos > track_.fileSize) {
887
*delay = true;
888
// The decoder failed during skip-frame operation.
889
return SCE_ERROR_ATRAC_API_FAIL;
890
}
891
892
// Move the offset to the specified position.
893
first_.fileoffset = bufferInfo.first.filePos;
894
895
if (bytesWrittenFirstBuf != 0) {
896
if (!ignoreDataBuf_) {
897
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr, bytesWrittenFirstBuf, "AtracResetPlayPosition");
898
}
899
first_.fileoffset += bytesWrittenFirstBuf;
900
}
901
first_.size = first_.fileoffset;
902
first_.offset = bytesWrittenFirstBuf;
903
904
bufferHeaderSize_ = 0;
905
bufferPos_ = track_.bytesPerFrame;
906
bufferValidBytes_ = bytesWrittenFirstBuf - bufferPos_;
907
}
908
909
if (track_.codecType == PSP_CODEC_AT3 || track_.codecType == PSP_CODEC_AT3PLUS) {
910
SeekToSample(sample);
911
}
912
913
WriteContextToPSPMem();
914
return 0;
915
}
916
917
void Atrac::InitLowLevel(const Atrac3LowLevelParams &params, int codecType) {
918
track_ = Track();
919
track_.codecType = codecType;
920
track_.endSample = 0;
921
track_.channels = params.encodedChannels;
922
outputChannels_ = params.outputChannels;
923
bufferMaxSize_ = params.bytesPerFrame;
924
track_.bytesPerFrame = bufferMaxSize_;
925
first_.writableBytes = track_.bytesPerFrame;
926
ResetData();
927
928
if (codecType == PSP_CODEC_AT3) {
929
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
930
track_.bitrate = (track_.bitrate + 511) >> 10;
931
track_.jointStereo = IsAtrac3StreamJointStereo(codecType, params.bytesPerFrame, params.encodedChannels);
932
} else if (codecType == PSP_CODEC_AT3PLUS) {
933
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
934
track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0;
935
track_.jointStereo = false;
936
} else {
937
_dbg_assert_msg_(false, "bad codec type %08x", codecType);
938
}
939
940
track_.dataByteOffset = 0;
941
first_.size = 0;
942
track_.fileSize = track_.bytesPerFrame; // not really meaningful
943
bufferState_ = ATRAC_STATUS_LOW_LEVEL;
944
currentSample_ = 0;
945
CreateDecoder(codecType, track_.bytesPerFrame, track_.channels);
946
WriteContextToPSPMem();
947
}
948
949
int Atrac::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) {
950
const int channels = outputChannels_;
951
int outSamples = 0;
952
decoder_->Decode(srcData, track_.BytesPerFrame(), bytesConsumed, channels, dstData, &outSamples);
953
*bytesWritten = outSamples * channels * sizeof(int16_t);
954
// TODO: Possibly return a decode error on bad data.
955
return 0;
956
}
957
958
void Atrac::CheckForSas() {
959
SetOutputChannels(1);
960
}
961
962
int Atrac::EnqueueForSas(u32 bufPtr, u32 bytesToAdd) {
963
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra());
964
Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData");
965
first_.size += bytesToAdd;
966
if (first_.size >= track_.fileSize) {
967
first_.size = track_.fileSize;
968
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
969
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
970
}
971
first_.fileoffset += addbytes;
972
// refresh context_
973
WriteContextToPSPMem();
974
return 0;
975
}
976
977
void Atrac::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) {
978
// Hack, but works.
979
int samplesNum;
980
DecodeData((u8 *)dstData, 0, &samplesNum, finish, nullptr);
981
}
982
983
void Atrac::NotifyGetContextAddress() {
984
if (!context_.IsValid()) {
985
// allocate a new context_
986
u32 contextSize = sizeof(SceAtracContext);
987
// Note that Alloc can increase contextSize to the "grain" size.
988
context_ = kernelMemory.Alloc(contextSize, false, StringFromFormat("AtracCtx/%d", atracID_).c_str());
989
if (context_.IsValid())
990
Memory::Memset(context_.ptr, 0, contextSize, "AtracContextClear");
991
WARN_LOG(Log::Atrac, "%08x=_sceAtracGetContextAddress(%i): allocated new context", context_.ptr, atracID_);
992
} else {
993
WARN_LOG(Log::Atrac, "%08x=_sceAtracGetContextAddress(%i)", context_.ptr, atracID_);
994
}
995
WriteContextToPSPMem();
996
}
997
998