CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/AtracCtx.cpp
Views: 1401
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/FunctionWrappers.h"
26
#include "Core/HLE/sceAtrac.h"
27
#include "Core/HLE/AtracCtx.h"
28
#include "Core/HW/Atrac3Standalone.h"
29
#include "Core/HLE/sceKernelMemory.h"
30
31
const size_t overAllocBytes = 16384;
32
33
const int RIFF_CHUNK_MAGIC = 0x46464952;
34
const int RIFF_WAVE_MAGIC = 0x45564157;
35
const int FMT_CHUNK_MAGIC = 0x20746D66;
36
const int DATA_CHUNK_MAGIC = 0x61746164;
37
const int SMPL_CHUNK_MAGIC = 0x6C706D73;
38
const int FACT_CHUNK_MAGIC = 0x74636166;
39
40
void Atrac::DoState(PointerWrap &p) {
41
auto s = p.Section("Atrac", 1, 9);
42
if (!s)
43
return;
44
45
Do(p, track_.channels);
46
Do(p, outputChannels_);
47
if (s >= 5) {
48
Do(p, track_.jointStereo);
49
}
50
51
Do(p, atracID_);
52
if (p.mode != p.MODE_READ) {
53
first_._filesize_dontuse = track_.fileSize;
54
}
55
Do(p, first_);
56
if (p.mode == p.MODE_READ) {
57
track_.fileSize = first_._filesize_dontuse;
58
}
59
60
Do(p, bufferMaxSize_);
61
Do(p, track_.codecType);
62
63
Do(p, currentSample_);
64
Do(p, track_.endSample);
65
Do(p, track_.firstSampleOffset);
66
if (s >= 3) {
67
Do(p, track_.dataByteOffset);
68
} else {
69
track_.dataByteOffset = track_.firstSampleOffset;
70
}
71
72
u32 hasDataBuf = dataBuf_ != nullptr;
73
Do(p, hasDataBuf);
74
if (hasDataBuf) {
75
if (p.mode == p.MODE_READ) {
76
if (dataBuf_)
77
delete[] dataBuf_;
78
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
79
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
80
}
81
DoArray(p, dataBuf_, track_.fileSize);
82
}
83
Do(p, second_);
84
85
Do(p, decodePos_);
86
if (s < 9) {
87
u32 oldDecodeEnd = 0;
88
Do(p, oldDecodeEnd);
89
}
90
if (s >= 4) {
91
Do(p, bufferPos_);
92
} else {
93
bufferPos_ = decodePos_;
94
}
95
96
Do(p, track_.bitrate);
97
Do(p, track_.bytesPerFrame);
98
99
Do(p, track_.loopinfo);
100
if (s < 9) {
101
int oldLoopInfoNum = 42;
102
Do(p, oldLoopInfoNum);
103
}
104
105
Do(p, track_.loopStartSample);
106
Do(p, track_.loopEndSample);
107
Do(p, loopNum_);
108
109
Do(p, context_);
110
if (s >= 6) {
111
Do(p, bufferState_);
112
} else {
113
if (dataBuf_ == nullptr) {
114
bufferState_ = ATRAC_STATUS_NO_DATA;
115
} else {
116
UpdateBufferState();
117
}
118
}
119
120
if (s >= 7) {
121
Do(p, ignoreDataBuf_);
122
} else {
123
ignoreDataBuf_ = false;
124
}
125
126
if (s >= 9) {
127
Do(p, bufferValidBytes_);
128
Do(p, bufferHeaderSize_);
129
} else {
130
bufferHeaderSize_ = track_.dataByteOffset;
131
bufferValidBytes_ = std::min(first_.size - track_.dataByteOffset, StreamBufferEnd() - track_.dataByteOffset);
132
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
133
bufferPos_ = track_.dataByteOffset;
134
}
135
}
136
137
if (s < 8 && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
138
// We didn't actually allow the second buffer to be set this far back.
139
// Pretend it's a regular loop, we'll just try our best.
140
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
141
}
142
143
// Make sure to do this late; it depends on things like bytesPerFrame_.
144
if (p.mode == p.MODE_READ && bufferState_ != ATRAC_STATUS_NO_DATA) {
145
CreateDecoder();
146
}
147
148
if (s >= 2 && s < 9) {
149
bool oldResetBuffer = false;
150
Do(p, oldResetBuffer);
151
}
152
}
153
154
void Atrac::ResetData() {
155
delete decoder_;
156
decoder_ = nullptr;
157
158
if (dataBuf_)
159
delete[] dataBuf_;
160
dataBuf_ = 0;
161
ignoreDataBuf_ = false;
162
bufferState_ = ATRAC_STATUS_NO_DATA;
163
164
if (context_.IsValid())
165
kernelMemory.Free(context_.ptr);
166
}
167
168
void Atrac::AnalyzeReset() {
169
// Reset some values.
170
track_.AnalyzeReset();
171
172
currentSample_ = 0;
173
loopNum_ = 0;
174
decodePos_ = 0;
175
bufferPos_ = 0;
176
}
177
178
u8 *Atrac::BufferStart() {
179
return ignoreDataBuf_ ? Memory::GetPointerWrite(first_.addr) : dataBuf_;
180
}
181
182
void AtracBase::UpdateContextFromPSPMem() {
183
if (!context_.IsValid()) {
184
return;
185
}
186
187
// Read in any changes from the game to the context.
188
// TODO: Might be better to just always track in RAM.
189
bufferState_ = context_->info.state;
190
// This value is actually abused by games to store the SAS voice number.
191
loopNum_ = context_->info.loopNum;
192
}
193
194
void Atrac::WriteContextToPSPMem() {
195
if (!context_.IsValid()) {
196
return;
197
}
198
// context points into PSP memory.
199
SceAtracContext *context = context_;
200
context->info.buffer = first_.addr;
201
context->info.bufferByte = bufferMaxSize_;
202
context->info.secondBuffer = second_.addr;
203
context->info.secondBufferByte = second_.size;
204
context->info.codec = track_.codecType;
205
context->info.loopNum = loopNum_;
206
context->info.loopStart = track_.loopStartSample > 0 ? track_.loopStartSample : 0;
207
context->info.loopEnd = track_.loopEndSample > 0 ? track_.loopEndSample : 0;
208
209
// Note that we read in the state when loading the atrac object, so it's safe
210
// to update it back here all the time. Some games, like Sol Trigger, change it.
211
// TODO: Should we just keep this in PSP ram then, or something?
212
context->info.state = bufferState_;
213
if (track_.firstSampleOffset != 0) {
214
context->info.samplesPerChan = track_.FirstSampleOffsetFull();
215
} else {
216
context->info.samplesPerChan = (track_.codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
217
}
218
context->info.sampleSize = track_.bytesPerFrame;
219
context->info.numChan = track_.channels;
220
context->info.dataOff = track_.dataByteOffset;
221
context->info.endSample = track_.endSample + track_.FirstSampleOffsetFull();
222
context->info.dataEnd = track_.fileSize;
223
context->info.curOff = first_.fileoffset;
224
context->info.decodePos = track_.DecodePosBySample(currentSample_);
225
context->info.streamDataByte = first_.size - track_.dataByteOffset;
226
227
u8 *buf = (u8 *)context;
228
*(u32_le *)(buf + 0xfc) = atracID_;
229
230
NotifyMemInfo(MemBlockFlags::WRITE, context_.ptr, sizeof(SceAtracContext), "AtracContext");
231
}
232
233
void Track::DebugLog() {
234
DEBUG_LOG(Log::ME, "ATRAC analyzed: %s channels: %d filesize: %d bitrate: %d kbps jointStereo: %d",
235
codecType == PSP_MODE_AT_3 ? "AT3" : "AT3Plus", channels, fileSize, bitrate / 1024, jointStereo);
236
DEBUG_LOG(Log::ME, "dataoff: %d firstSampleOffset: %d endSample: %d", dataByteOffset, firstSampleOffset, endSample);
237
DEBUG_LOG(Log::ME, "loopStartSample: %d loopEndSample: %d", loopStartSample, loopEndSample);
238
}
239
240
int Atrac::Analyze(u32 addr, u32 size) {
241
track_ = {};
242
first_ = {};
243
first_.addr = addr;
244
first_.size = size;
245
246
AnalyzeReset();
247
248
// 72 is about the size of the minimum required data to even be valid.
249
if (size < 72) {
250
return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "buffer too small");
251
}
252
253
// TODO: Check the range (addr, size) instead.
254
if (!Memory::IsValidAddress(addr)) {
255
return hleReportWarning(Log::ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address");
256
}
257
258
// TODO: Validate stuff.
259
if (Memory::ReadUnchecked_U32(addr) != RIFF_CHUNK_MAGIC) {
260
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid RIFF header");
261
}
262
263
int retval = AnalyzeAtracTrack(addr, size, &track_);
264
first_._filesize_dontuse = track_.fileSize;
265
track_.DebugLog();
266
return retval;
267
}
268
269
int AnalyzeAtracTrack(u32 addr, u32 size, Track *track) {
270
struct RIFFFmtChunk {
271
u16_le fmtTag;
272
u16_le channels;
273
u32_le samplerate;
274
u32_le avgBytesPerSec;
275
u16_le blockAlign;
276
};
277
278
u32 offset = 8;
279
track->firstSampleOffset = 0;
280
281
while (Memory::Read_U32(addr + offset) != RIFF_WAVE_MAGIC) {
282
// Get the size preceding the magic.
283
int chunk = Memory::Read_U32(addr + offset - 4);
284
// Round the chunk size up to the nearest 2.
285
offset += chunk + (chunk & 1);
286
if (offset + 12 > size) {
287
return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small for WAVE chunk at %d", offset);
288
}
289
if (Memory::Read_U32(addr + offset) != RIFF_CHUNK_MAGIC) {
290
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "RIFF chunk did not contain WAVE");
291
}
292
offset += 8;
293
}
294
offset += 4;
295
296
if (offset != 12) {
297
WARN_LOG_REPORT(Log::ME, "RIFF chunk at offset: %d", offset);
298
}
299
300
// RIFF size excluding chunk header.
301
track->fileSize = Memory::Read_U32(addr + offset - 8) + 8;
302
303
// Even if the RIFF size is too low, it may simply be incorrect. This works on real firmware.
304
u32 maxSize = std::max(track->fileSize, size);
305
306
bool bfoundData = false;
307
u32 dataChunkSize = 0;
308
int sampleOffsetAdjust = 0;
309
310
while (maxSize >= offset + 8 && !bfoundData) {
311
int chunkMagic = Memory::Read_U32(addr + offset);
312
u32 chunkSize = Memory::Read_U32(addr + offset + 4);
313
// Account for odd sized chunks.
314
if (chunkSize & 1) {
315
WARN_LOG_REPORT_ONCE(oddchunk, Log::ME, "RIFF chunk had uneven size");
316
}
317
chunkSize += (chunkSize & 1);
318
offset += 8;
319
if (chunkSize > maxSize - offset)
320
break;
321
switch (chunkMagic) {
322
case FMT_CHUNK_MAGIC:
323
{
324
if (track->codecType != 0) {
325
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "multiple fmt definitions");
326
}
327
328
auto at3fmt = PSPPointer<const RIFFFmtChunk>::Create(addr + offset);
329
if (chunkSize < 32 || (at3fmt->fmtTag == AT3_PLUS_MAGIC && chunkSize < 52)) {
330
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "fmt definition too small (%d)", chunkSize);
331
}
332
333
if (at3fmt->fmtTag == AT3_MAGIC)
334
track->codecType = PSP_MODE_AT_3;
335
else if (at3fmt->fmtTag == AT3_PLUS_MAGIC)
336
track->codecType = PSP_MODE_AT_3_PLUS;
337
else {
338
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid fmt magic: %04x", at3fmt->fmtTag);
339
}
340
track->channels = at3fmt->channels;
341
if (track->channels != 1 && track->channels != 2) {
342
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid channel count: %d", track->channels);
343
}
344
if (at3fmt->samplerate != 44100) {
345
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unsupported sample rate: %d", at3fmt->samplerate);
346
}
347
track->bitrate = at3fmt->avgBytesPerSec * 8;
348
track->bytesPerFrame = at3fmt->blockAlign;
349
if (track->bytesPerFrame == 0) {
350
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "invalid bytes per frame: %d", track->bytesPerFrame);
351
}
352
353
// TODO: There are some format specific bytes here which seem to have fixed values?
354
// Probably don't need them.
355
356
if (at3fmt->fmtTag == AT3_MAGIC) {
357
// This is the offset to the jointStereo_ field.
358
track->jointStereo = Memory::Read_U32(addr + offset + 24);
359
}
360
}
361
break;
362
case FACT_CHUNK_MAGIC:
363
{
364
track->endSample = Memory::Read_U32(addr + offset);
365
if (chunkSize >= 8) {
366
track->firstSampleOffset = Memory::Read_U32(addr + offset + 4);
367
}
368
if (chunkSize >= 12) {
369
u32 largerOffset = Memory::Read_U32(addr + offset + 8);
370
sampleOffsetAdjust = track->firstSampleOffset - largerOffset;
371
}
372
}
373
break;
374
case SMPL_CHUNK_MAGIC:
375
{
376
if (chunkSize < 32) {
377
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small (%d)", chunkSize);
378
}
379
int checkNumLoops = Memory::Read_U32(addr + offset + 28);
380
if (checkNumLoops != 0 && chunkSize < 36 + 20) {
381
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "smpl chunk too small for loop (%d, %d)", checkNumLoops, chunkSize);
382
}
383
if (checkNumLoops < 0) {
384
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "bad checkNumLoops (%d)", checkNumLoops);
385
}
386
387
track->loopinfo.resize(checkNumLoops);
388
u32 loopinfoAddr = addr + offset + 36;
389
// The PSP only cares about the first loop start and end, it seems.
390
// Most likely can skip the rest of this data, but it's not hurting anyone.
391
for (int i = 0; i < checkNumLoops && 36 + (u32)i < chunkSize; i++, loopinfoAddr += 24) {
392
track->loopinfo[i].cuePointID = Memory::Read_U32(loopinfoAddr);
393
track->loopinfo[i].type = Memory::Read_U32(loopinfoAddr + 4);
394
track->loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8);
395
track->loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12);
396
track->loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16);
397
track->loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20);
398
399
if (track->loopinfo[i].startSample >= track->loopinfo[i].endSample) {
400
return hleReportError(Log::ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop starts after it ends");
401
}
402
}
403
}
404
break;
405
case DATA_CHUNK_MAGIC:
406
{
407
bfoundData = true;
408
track->dataByteOffset = offset;
409
dataChunkSize = chunkSize;
410
if (track->fileSize < offset + chunkSize) {
411
WARN_LOG_REPORT(Log::ME, "Atrac data chunk extends beyond riff chunk");
412
track->fileSize = offset + chunkSize;
413
}
414
}
415
break;
416
}
417
offset += chunkSize;
418
}
419
420
if (track->codecType == 0) {
421
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "could not detect codec");
422
}
423
424
if (!bfoundData) {
425
return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "no data chunk");
426
}
427
428
// set the loopStartSample_ and loopEndSample_ by loopinfo_
429
if (track->loopinfo.size() > 0) {
430
track->loopStartSample = track->loopinfo[0].startSample + track->FirstOffsetExtra() + sampleOffsetAdjust;
431
track->loopEndSample = track->loopinfo[0].endSample + track->FirstOffsetExtra() + sampleOffsetAdjust;
432
} else {
433
track->loopStartSample = -1;
434
track->loopEndSample = -1;
435
}
436
437
// if there is no correct endsample, try to guess it
438
if (track->endSample <= 0 && track->bytesPerFrame != 0) {
439
track->endSample = (dataChunkSize / track->bytesPerFrame) * track->SamplesPerFrame();
440
track->endSample -= track->FirstSampleOffsetFull();
441
}
442
track->endSample -= 1;
443
444
if (track->loopEndSample != -1 && track->loopEndSample > track->endSample + track->FirstSampleOffsetFull()) {
445
return hleReportError(Log::ME, ATRAC_ERROR_BAD_CODEC_PARAMS, "loop after end of data");
446
}
447
448
return 0;
449
}
450
451
int Atrac::AnalyzeAA3(u32 addr, u32 size, u32 fileSize) {
452
first_.addr = addr;
453
first_.size = size;
454
first_._filesize_dontuse = fileSize;
455
456
AnalyzeReset();
457
458
return AnalyzeAA3Track(addr, size, fileSize, &track_);
459
}
460
461
int AnalyzeAA3Track(u32 addr, u32 size, u32 fileSize, Track *track) {
462
if (size < 10) {
463
return hleReportError(Log::ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "buffer too small");
464
}
465
// TODO: Make sure this validation is correct, more testing.
466
467
const u8 *buffer = Memory::GetPointer(addr);
468
if (buffer[0] != 'e' || buffer[1] != 'a' || buffer[2] != '3') {
469
return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid ea3 magic bytes");
470
}
471
472
// It starts with an id3 header (replaced with ea3.) This is the size.
473
u32 tagSize = buffer[9] | (buffer[8] << 7) | (buffer[7] << 14) | (buffer[6] << 21);
474
if (size < tagSize + 36) {
475
return hleReportError(Log::ME, ATRAC_ERROR_AA3_SIZE_TOO_SMALL, "truncated before id3 end");
476
}
477
478
// EA3 header starts at id3 header (10) + tagSize.
479
buffer = Memory::GetPointer(addr + 10 + tagSize);
480
if (buffer[0] != 'E' || buffer[1] != 'A' || buffer[2] != '3') {
481
return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid EA3 magic bytes");
482
}
483
484
track->fileSize = fileSize;
485
486
// Based on FFmpeg's code.
487
u32 codecParams = buffer[35] | (buffer[34] << 8) | (buffer[35] << 16);
488
const u32 at3SampleRates[8] = { 32000, 44100, 48000, 88200, 96000, 0 };
489
490
switch (buffer[32]) {
491
case 0:
492
track->codecType = PSP_MODE_AT_3;
493
track->bytesPerFrame = (codecParams & 0x03FF) * 8;
494
track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 1024;
495
track->channels = 2;
496
track->jointStereo = (codecParams >> 17) & 1;
497
break;
498
case 1:
499
track->codecType = PSP_MODE_AT_3_PLUS;
500
track->bytesPerFrame = ((codecParams & 0x03FF) * 8) + 8;
501
track->bitrate = at3SampleRates[(codecParams >> 13) & 7] * track->bytesPerFrame * 8 / 2048;
502
track->channels = (codecParams >> 10) & 7;
503
break;
504
case 3:
505
case 4:
506
case 5:
507
return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "unsupported codec type %d", buffer[32]);
508
default:
509
return hleReportError(Log::ME, ATRAC_ERROR_AA3_INVALID_DATA, "invalid codec type %d", buffer[32]);
510
}
511
512
track->dataByteOffset = 10 + tagSize + 96;
513
track->firstSampleOffset = 0;
514
if (track->endSample < 0 && track->bytesPerFrame != 0) {
515
track->endSample = ((track->fileSize - track->dataByteOffset) / track->bytesPerFrame) * track->SamplesPerFrame();
516
}
517
track->endSample -= 1;
518
return 0;
519
}
520
521
void Atrac::CalculateStreamInfo(u32 *outReadOffset) {
522
u32 readOffset = first_.fileoffset;
523
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
524
// Nothing to write.
525
readOffset = 0;
526
first_.offset = 0;
527
first_.writableBytes = 0;
528
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
529
// If we're buffering the entire file, just give the same as readOffset.
530
first_.offset = readOffset;
531
// In this case, the bytes writable are just the remaining bytes, always.
532
first_.writableBytes = track_.fileSize - readOffset;
533
} else {
534
u32 bufferEnd = StreamBufferEnd();
535
u32 bufferValidExtended = bufferPos_ + bufferValidBytes_;
536
if (bufferValidExtended < bufferEnd) {
537
first_.offset = bufferValidExtended;
538
first_.writableBytes = bufferEnd - bufferValidExtended;
539
} else {
540
u32 bufferStartUsed = bufferValidExtended - bufferEnd;
541
first_.offset = bufferStartUsed;
542
first_.writableBytes = bufferPos_ - bufferStartUsed;
543
}
544
545
if (readOffset >= track_.fileSize) {
546
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
547
// We don't need anything more, so all 0s.
548
readOffset = 0;
549
first_.offset = 0;
550
first_.writableBytes = 0;
551
} else {
552
readOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
553
}
554
}
555
556
if (readOffset + first_.writableBytes > track_.fileSize) {
557
// Never ask for past the end of file, even when the space is free.
558
first_.writableBytes = track_.fileSize - readOffset;
559
}
560
561
// If you don't think this should be here, remove it. It's just a temporary safety check.
562
if (first_.offset + first_.writableBytes > bufferMaxSize_) {
563
ERROR_LOG_REPORT(Log::ME, "Somehow calculated too many writable bytes: %d + %d > %d", first_.offset, first_.writableBytes, bufferMaxSize_);
564
first_.offset = 0;
565
first_.writableBytes = bufferMaxSize_;
566
}
567
}
568
569
if (outReadOffset) {
570
*outReadOffset = readOffset;
571
}
572
}
573
574
void AtracBase::CreateDecoder() {
575
if (decoder_) {
576
delete decoder_;
577
}
578
579
// First, init the standalone decoder. Only used for low-level-decode initially, but simple.
580
if (track_.codecType == PSP_MODE_AT_3) {
581
// We don't pull this from the RIFF so that we can support OMA also.
582
uint8_t extraData[14]{};
583
// The only thing that changes are the jointStereo_ values.
584
extraData[0] = 1;
585
extraData[3] = track_.channels << 3;
586
extraData[6] = track_.jointStereo;
587
extraData[8] = track_.jointStereo;
588
extraData[10] = 1;
589
decoder_ = CreateAtrac3Audio(track_.channels, track_.bytesPerFrame, extraData, sizeof(extraData));
590
} else {
591
decoder_ = CreateAtrac3PlusAudio(track_.channels, track_.bytesPerFrame);
592
}
593
}
594
595
void Atrac::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) {
596
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
597
bufferInfo->first.writePosPtr = first_.addr;
598
// Everything is loaded, so nothing needs to be read.
599
bufferInfo->first.writableBytes = 0;
600
bufferInfo->first.minWriteBytes = 0;
601
bufferInfo->first.filePos = 0;
602
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
603
// Here the message is: you need to read at least this many bytes to get to that position.
604
// This is because we're filling the buffer start to finish, not streaming.
605
bufferInfo->first.writePosPtr = first_.addr + first_.size;
606
bufferInfo->first.writableBytes = track_.fileSize - first_.size;
607
int minWriteBytes = track_.FileOffsetBySample(sample) - first_.size;
608
if (minWriteBytes > 0) {
609
bufferInfo->first.minWriteBytes = minWriteBytes;
610
} else {
611
bufferInfo->first.minWriteBytes = 0;
612
}
613
bufferInfo->first.filePos = first_.size;
614
} else {
615
// This is without the sample offset. The file offset also includes the previous batch of samples?
616
int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame());
617
618
// Update the writable bytes. When streaming, this is just the number of bytes until the end.
619
const u32 bufSizeAligned = (bufferMaxSize_ / track_.bytesPerFrame) * track_.bytesPerFrame;
620
const int needsMoreFrames = track_.FirstOffsetExtra(); // ?
621
622
bufferInfo->first.writePosPtr = first_.addr;
623
bufferInfo->first.writableBytes = std::min(track_.fileSize - sampleFileOffset, bufSizeAligned);
624
if (((sample + track_.firstSampleOffset) % (int)track_.SamplesPerFrame()) >= (int)track_.SamplesPerFrame() - needsMoreFrames) {
625
// Not clear why, but it seems it wants a bit extra in case the sample is late?
626
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 3;
627
} else {
628
bufferInfo->first.minWriteBytes = track_.bytesPerFrame * 2;
629
}
630
if ((u32)sample < (u32)track_.firstSampleOffset && sampleFileOffset != track_.dataByteOffset) {
631
sampleFileOffset -= track_.bytesPerFrame;
632
}
633
bufferInfo->first.filePos = sampleFileOffset;
634
635
if (second_.size != 0) {
636
// TODO: We have a second buffer. Within it, minWriteBytes should be zero.
637
// The filePos should be after the end of the second buffer (or zero.)
638
// We actually need to ensure we READ from the second buffer before implementing that.
639
}
640
}
641
642
// It seems like this is always the same as the first buffer's pos, weirdly.
643
bufferInfo->second.writePosPtr = first_.addr;
644
// Reset never needs a second buffer write, since the loop is in a fixed place.
645
bufferInfo->second.writableBytes = 0;
646
bufferInfo->second.minWriteBytes = 0;
647
bufferInfo->second.filePos = 0;
648
}
649
650
int Atrac::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) {
651
outputChannels_ = outputChannels;
652
653
first_.addr = buffer;
654
first_.size = readSize;
655
656
if (first_.size > track_.fileSize)
657
first_.size = track_.fileSize;
658
first_.fileoffset = first_.size;
659
660
// got the size of temp buf, and calculate offset
661
bufferMaxSize_ = bufferSize;
662
first_.offset = first_.size;
663
664
// some games may reuse an atracID for playing sound
665
ResetData();
666
UpdateBufferState();
667
668
if (track_.codecType != PSP_MODE_AT_3 && track_.codecType != PSP_MODE_AT_3_PLUS) {
669
// Shouldn't have gotten here, Analyze() checks this.
670
bufferState_ = ATRAC_STATUS_NO_DATA;
671
return hleReportError(Log::ME, ATRAC_ERROR_UNKNOWN_FORMAT, "unexpected codec type in set data");
672
}
673
674
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED || bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
675
// This says, don't use the dataBuf_ array, use the PSP RAM.
676
// This way, games can load data async into the buffer, and it still works.
677
// TODO: Support this always, even for streaming.
678
ignoreDataBuf_ = true;
679
}
680
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END || bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
681
bufferHeaderSize_ = track_.dataByteOffset;
682
bufferPos_ = track_.dataByteOffset + track_.bytesPerFrame;
683
bufferValidBytes_ = first_.size - bufferPos_;
684
}
685
686
const char *codecName = track_.codecType == PSP_MODE_AT_3 ? "atrac3" : "atrac3+";
687
const char *channelName = track_.channels == 1 ? "mono" : "stereo";
688
689
// Over-allocate databuf to prevent going off the end if the bitstream is bad or if there are
690
// bugs in the decoder. This happens, see issue #15788. Arbitrary, but let's make it a whole page on the popular
691
// architecture that has the largest pages (M1).
692
dataBuf_ = new u8[track_.fileSize + overAllocBytes];
693
memset(dataBuf_, 0, track_.fileSize + overAllocBytes);
694
if (!ignoreDataBuf_) {
695
u32 copybytes = std::min(bufferSize, track_.fileSize);
696
Memory::Memcpy(dataBuf_, buffer, copybytes, "AtracSetData");
697
}
698
CreateDecoder();
699
return hleLogSuccessInfoI(Log::ME, successCode, "%s %s audio", codecName, channelName);
700
}
701
702
u32 Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
703
u32 secondFileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
704
u32 desiredSize = track_.fileSize - secondFileOffset;
705
706
// 3 seems to be the number of frames required to handle a loop.
707
if (secondBufferSize < desiredSize && secondBufferSize < (u32)track_.BytesPerFrame() * 3) {
708
return hleReportError(Log::ME, ATRAC_ERROR_SIZE_TOO_SMALL, "too small");
709
}
710
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
711
return hleReportError(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed");
712
}
713
714
second_.addr = secondBuffer;
715
second_.size = secondBufferSize;
716
second_.fileoffset = secondFileOffset;
717
return hleLogSuccessI(Log::ME, 0);
718
}
719
720
int AtracBase::GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) {
721
if (BufferState() != ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
722
// Writes zeroes in this error case.
723
*fileOffset = 0;
724
*desiredSize = 0;
725
return hleLogWarning(Log::ME, ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED, "not needed");
726
}
727
728
*fileOffset = track_.FileOffsetBySample(track_.loopEndSample - track_.firstSampleOffset);
729
*desiredSize = track_.fileSize - *fileOffset;
730
return hleLogSuccessI(Log::ME, 0);
731
}
732
733
void Atrac::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) {
734
u32 calculatedReadOffset;
735
// TODO: Feels like this should already have been computed?
736
CalculateStreamInfo(&calculatedReadOffset);
737
738
*writePtr = first_.addr + first_.offset;
739
*writableBytes = first_.writableBytes;
740
*readOffset = calculatedReadOffset;
741
}
742
743
void Atrac::UpdateBufferState() {
744
if (bufferMaxSize_ >= track_.fileSize) {
745
if (first_.size < track_.fileSize) {
746
// The buffer is big enough, but we don't have all the data yet.
747
bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER;
748
} else {
749
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
750
}
751
} else {
752
if (track_.loopEndSample <= 0) {
753
// There's no looping, but we need to stream the data in our buffer.
754
bufferState_ = ATRAC_STATUS_STREAMED_WITHOUT_LOOP;
755
} else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) {
756
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_FROM_END;
757
} else {
758
bufferState_ = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER;
759
}
760
}
761
}
762
763
int Atrac::AddStreamData(u32 bytesToAdd) {
764
u32 readOffset;
765
CalculateStreamInfo(&readOffset);
766
if (bytesToAdd > first_.writableBytes)
767
return hleLogWarning(Log::ME, ATRAC_ERROR_ADD_DATA_IS_TOO_BIG, "too many bytes");
768
769
if (bytesToAdd > 0) {
770
first_.fileoffset = readOffset;
771
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset);
772
if (!ignoreDataBuf_) {
773
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr + first_.offset, addbytes, "AtracAddStreamData");
774
}
775
first_.fileoffset += addbytes;
776
}
777
first_.size += bytesToAdd;
778
if (first_.size >= track_.fileSize) {
779
first_.size = track_.fileSize;
780
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
781
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
782
WriteContextToPSPMem();
783
}
784
785
first_.offset += bytesToAdd;
786
bufferValidBytes_ += bytesToAdd;
787
788
if (PSP_CoreParameter().compat.flags().AtracLoopHack && bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && RemainingFrames() > 2) {
789
loopNum_++;
790
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
791
}
792
793
return 0;
794
}
795
796
u32 Atrac::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) {
797
int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra());
798
Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData");
799
first_.size += bytesToAdd;
800
if (first_.size >= track_.fileSize) {
801
first_.size = track_.fileSize;
802
if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER)
803
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
804
}
805
first_.fileoffset += addbytes;
806
// refresh context_
807
WriteContextToPSPMem();
808
return 0;
809
}
810
811
u32 Atrac::GetNextSamples() {
812
// It seems like the PSP aligns the sample position to 0x800...?
813
u32 skipSamples = track_.FirstSampleOffsetFull();
814
u32 firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame();
815
u32 numSamples = track_.endSample + 1 - currentSample_;
816
if (currentSample_ == 0 && firstSamples != 0) {
817
numSamples = firstSamples;
818
}
819
u32 unalignedSamples = (skipSamples + currentSample_) % track_.SamplesPerFrame();
820
if (unalignedSamples != 0) {
821
// We're off alignment, possibly due to a loop. Force it back on.
822
numSamples = track_.SamplesPerFrame() - unalignedSamples;
823
}
824
if (numSamples > track_.SamplesPerFrame())
825
numSamples = track_.SamplesPerFrame();
826
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_FROM_END && (int)numSamples + currentSample_ > track_.endSample) {
827
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
828
}
829
return numSamples;
830
}
831
832
void Atrac::ForceSeekToSample(int sample) {
833
if (decoder_) {
834
decoder_->FlushBuffers();
835
}
836
currentSample_ = sample;
837
}
838
839
void Atrac::SeekToSample(int sample) {
840
// It seems like the PSP aligns the sample position to 0x800...?
841
const u32 offsetSamples = track_.FirstSampleOffsetFull();
842
const u32 unalignedSamples = (offsetSamples + sample) % track_.SamplesPerFrame();
843
int seekFrame = sample + offsetSamples - unalignedSamples;
844
845
if ((sample != currentSample_ || sample == 0) && decoder_ != nullptr) {
846
// Prefill the decode buffer with packets before the first sample offset.
847
decoder_->FlushBuffers();
848
849
int adjust = 0;
850
if (sample == 0) {
851
int offsetSamples = track_.FirstSampleOffsetFull();
852
adjust = -(int)(offsetSamples % track_.SamplesPerFrame());
853
}
854
const u32 off = track_.FileOffsetBySample(sample + adjust);
855
const u32 backfill = track_.bytesPerFrame * 2;
856
const u32 start = off - track_.dataByteOffset < backfill ? track_.dataByteOffset : off - backfill;
857
858
for (u32 pos = start; pos < off; pos += track_.bytesPerFrame) {
859
decoder_->Decode(BufferStart() + pos, track_.bytesPerFrame, nullptr, 2, nullptr, nullptr);
860
}
861
}
862
863
currentSample_ = sample;
864
}
865
866
int Atrac::RemainingFrames() const {
867
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
868
// Meaning, infinite I guess? We've got it all.
869
return PSP_ATRAC_ALLDATA_IS_ON_MEMORY;
870
}
871
872
u32 currentFileOffset = track_.FileOffsetBySample(currentSample_ - track_.SamplesPerFrame() + track_.FirstOffsetExtra());
873
if (first_.fileoffset >= track_.fileSize) {
874
if (bufferState_ == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) {
875
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
876
}
877
int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset;
878
if (bufferState_ == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && currentSample_ > loopEndAdjusted) {
879
// No longer looping in this case, outside the loop.
880
return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY;
881
}
882
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK && loopNum_ == 0) {
883
return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY;
884
}
885
}
886
887
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
888
// Since we're streaming, the remaining frames are what's valid in the buffer.
889
return bufferValidBytes_ / track_.bytesPerFrame;
890
}
891
892
// Since the first frame is shorter by this offset, add to round up at this offset.
893
const int remainingBytes = first_.fileoffset - currentFileOffset;
894
if (remainingBytes < 0) {
895
// Just in case. Shouldn't happen, but once did by mistake.
896
return 0;
897
}
898
return remainingBytes / track_.bytesPerFrame;
899
}
900
901
void Atrac::ConsumeFrame() {
902
bufferPos_ += track_.bytesPerFrame;
903
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
904
if (bufferValidBytes_ > track_.bytesPerFrame) {
905
bufferValidBytes_ -= track_.bytesPerFrame;
906
} else {
907
bufferValidBytes_ = 0;
908
}
909
}
910
if (bufferPos_ >= StreamBufferEnd()) {
911
// Wrap around... theoretically, this should only happen at exactly StreamBufferEnd.
912
bufferPos_ -= StreamBufferEnd();
913
bufferHeaderSize_ = 0;
914
}
915
}
916
917
u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) {
918
int loopNum = loopNum_;
919
if (bufferState_ == ATRAC_STATUS_FOR_SCESAS) {
920
// TODO: Might need more testing.
921
loopNum = 0;
922
}
923
924
// We already passed the end - return an error (many games check for this.)
925
if (currentSample_ >= track_.endSample && loopNum == 0) {
926
*SamplesNum = 0;
927
*finish = 1;
928
// refresh context_
929
WriteContextToPSPMem();
930
return ATRAC_ERROR_ALL_DATA_DECODED;
931
}
932
933
// TODO: This isn't at all right, but at least it makes the music "last" some time.
934
u32 numSamples = 0;
935
936
// It seems like the PSP aligns the sample position to 0x800...?
937
int offsetSamples = track_.FirstSampleOffsetFull();
938
int skipSamples = 0;
939
u32 maxSamples = track_.endSample + 1 - currentSample_;
940
u32 unalignedSamples = (offsetSamples + currentSample_) % track_.SamplesPerFrame();
941
if (unalignedSamples != 0) {
942
// We're off alignment, possibly due to a loop. Force it back on.
943
maxSamples = track_.SamplesPerFrame() - unalignedSamples;
944
skipSamples = unalignedSamples;
945
}
946
947
if (skipSamples != 0 && bufferHeaderSize_ == 0) {
948
// Skip the initial frame used to load state for the looped frame.
949
// TODO: We will want to actually read this in.
950
// TODO again: This seems to happen on the first frame of playback regardless of loops.
951
// Can't be good.
952
ConsumeFrame();
953
}
954
955
SeekToSample(currentSample_);
956
957
bool gotFrame = false;
958
u32 off = track_.FileOffsetBySample(currentSample_ - skipSamples);
959
if (off < first_.size) {
960
uint8_t *indata = BufferStart() + off;
961
int bytesConsumed = 0;
962
int outSamples = track_.SamplesPerFrame();
963
int outBytes = outSamples * outputChannels_ * sizeof(int16_t);
964
gotFrame = true;
965
966
numSamples = outSamples;
967
uint32_t packetAddr = CurBufferAddress(-skipSamples);
968
// got a frame
969
int skipped = std::min((u32)skipSamples, numSamples);
970
skipSamples -= skipped;
971
numSamples = numSamples - skipped;
972
// If we're at the end, clamp to samples we want. It always returns a full chunk.
973
numSamples = std::min(maxSamples, numSamples);
974
975
outSamples = numSamples;
976
if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, (int16_t *)outbuf, &outSamples)) {
977
// Decode failed.
978
*SamplesNum = 0;
979
*finish = 1;
980
return ATRAC_ERROR_ALL_DATA_DECODED;
981
}
982
983
if (packetAddr != 0 && MemBlockInfoDetailed()) {
984
char tagData[128];
985
size_t tagSize = FormatMemWriteTagAt(tagData, sizeof(tagData), "AtracDecode/", packetAddr, track_.bytesPerFrame);
986
NotifyMemInfo(MemBlockFlags::READ, packetAddr, track_.bytesPerFrame, tagData, tagSize);
987
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, tagData, tagSize);
988
} else {
989
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
990
}
991
// We only want one frame per call, let's continue the next time.
992
}
993
994
if (!gotFrame && currentSample_ < track_.endSample) {
995
// Never got a frame. We may have dropped a GHA frame or otherwise have a bug.
996
// For now, let's try to provide an extra "frame" if possible so games don't infinite loop.
997
if (track_.FileOffsetBySample(currentSample_) < track_.fileSize) {
998
numSamples = std::min(maxSamples, track_.SamplesPerFrame());
999
u32 outBytes = numSamples * outputChannels_ * sizeof(s16);
1000
if (outbuf != nullptr) {
1001
memset(outbuf, 0, outBytes);
1002
NotifyMemInfo(MemBlockFlags::WRITE, outbufPtr, outBytes, "AtracDecode");
1003
}
1004
}
1005
}
1006
1007
*SamplesNum = numSamples;
1008
// update current sample and decodePos
1009
currentSample_ += numSamples;
1010
decodePos_ = track_.DecodePosBySample(currentSample_);
1011
1012
ConsumeFrame();
1013
1014
int finishFlag = 0;
1015
// TODO: Verify.
1016
bool hitEnd = currentSample_ >= track_.endSample || (numSamples == 0 && first_.size >= track_.fileSize);
1017
int loopEndAdjusted = track_.loopEndSample - track_.FirstSampleOffsetFull();
1018
if ((hitEnd || currentSample_ > loopEndAdjusted) && loopNum != 0) {
1019
SeekToSample(track_.loopStartSample - track_.FirstSampleOffsetFull());
1020
if (bufferState_ != ATRAC_STATUS_FOR_SCESAS) {
1021
if (loopNum_ > 0)
1022
loopNum_--;
1023
}
1024
if ((bufferState_ & ATRAC_STATUS_STREAMED_MASK) == ATRAC_STATUS_STREAMED_MASK) {
1025
// Whatever bytes we have left were added from the loop.
1026
u32 loopOffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
1027
// TODO: Hmm, need to manage the buffer better. But don't move fileoffset if we already have valid data.
1028
if (loopOffset > first_.fileoffset || loopOffset + bufferValidBytes_ < first_.fileoffset) {
1029
// Skip the initial frame at the start.
1030
first_.fileoffset = track_.FileOffsetBySample(track_.loopStartSample - track_.FirstSampleOffsetFull() - track_.SamplesPerFrame() * 2);
1031
}
1032
}
1033
} else if (hitEnd) {
1034
finishFlag = 1;
1035
1036
// Still move forward, so we know that we've read everything.
1037
// This seems to be reflected in the context as well.
1038
currentSample_ += track_.SamplesPerFrame() - numSamples;
1039
}
1040
1041
*finish = finishFlag;
1042
*remains = RemainingFrames();
1043
// refresh context_
1044
WriteContextToPSPMem();
1045
return 0;
1046
}
1047
1048
void AtracBase::SetLoopNum(int loopNum) {
1049
// Spammed in MHU
1050
loopNum_ = loopNum;
1051
if (loopNum != 0 && track_.loopinfo.size() == 0) {
1052
// Just loop the whole audio
1053
// This is a rare modification of track_ after the fact.
1054
// Maybe we can get away with setting these by default.
1055
track_.loopStartSample = track_.FirstSampleOffsetFull();
1056
track_.loopEndSample = track_.endSample + track_.FirstSampleOffsetFull();
1057
}
1058
WriteContextToPSPMem();
1059
}
1060
1061
u32 Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) {
1062
// Reuse the same calculation as before.
1063
AtracResetBufferInfo bufferInfo;
1064
GetResetBufferInfo(&bufferInfo, sample);
1065
1066
if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) {
1067
return hleLogError(Log::ME, ATRAC_ERROR_BAD_FIRST_RESET_SIZE, "first byte count not in valid range");
1068
}
1069
if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) {
1070
return hleLogError(Log::ME, ATRAC_ERROR_BAD_SECOND_RESET_SIZE, "second byte count not in valid range");
1071
}
1072
1073
if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) {
1074
// Always adds zero bytes.
1075
} else if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) {
1076
// Okay, it's a valid number of bytes. Let's set them up.
1077
if (bytesWrittenFirstBuf != 0) {
1078
if (!ignoreDataBuf_) {
1079
Memory::Memcpy(dataBuf_ + first_.size, first_.addr + first_.size, bytesWrittenFirstBuf, "AtracResetPlayPosition");
1080
}
1081
first_.fileoffset += bytesWrittenFirstBuf;
1082
first_.size += bytesWrittenFirstBuf;
1083
first_.offset += bytesWrittenFirstBuf;
1084
}
1085
1086
// Did we transition to a full buffer?
1087
if (first_.size >= track_.fileSize) {
1088
first_.size = track_.fileSize;
1089
bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED;
1090
}
1091
} else {
1092
if (bufferInfo.first.filePos > track_.fileSize) {
1093
return hleDelayResult(hleLogError(Log::ME, ATRAC_ERROR_API_FAIL, "invalid file position"), "reset play pos", 200);
1094
}
1095
1096
// Move the offset to the specified position.
1097
first_.fileoffset = bufferInfo.first.filePos;
1098
1099
if (bytesWrittenFirstBuf != 0) {
1100
if (!ignoreDataBuf_) {
1101
Memory::Memcpy(dataBuf_ + first_.fileoffset, first_.addr, bytesWrittenFirstBuf, "AtracResetPlayPosition");
1102
}
1103
first_.fileoffset += bytesWrittenFirstBuf;
1104
}
1105
first_.size = first_.fileoffset;
1106
first_.offset = bytesWrittenFirstBuf;
1107
1108
bufferHeaderSize_ = 0;
1109
bufferPos_ = track_.bytesPerFrame;
1110
bufferValidBytes_ = bytesWrittenFirstBuf - bufferPos_;
1111
}
1112
1113
if (track_.codecType == PSP_MODE_AT_3 || track_.codecType == PSP_MODE_AT_3_PLUS) {
1114
SeekToSample(sample);
1115
}
1116
1117
WriteContextToPSPMem();
1118
return 0;
1119
}
1120
1121
void Atrac::InitLowLevel(u32 paramsAddr, bool jointStereo) {
1122
track_.channels = Memory::Read_U32(paramsAddr);
1123
outputChannels_ = Memory::Read_U32(paramsAddr + 4);
1124
bufferMaxSize_ = Memory::Read_U32(paramsAddr + 8);
1125
track_.bytesPerFrame = bufferMaxSize_;
1126
first_.writableBytes = track_.bytesPerFrame;
1127
ResetData();
1128
1129
if (track_.codecType == PSP_MODE_AT_3) {
1130
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
1131
track_.bitrate = (track_.bitrate + 511) >> 10;
1132
track_.jointStereo = false;
1133
} else if (track_.codecType == PSP_MODE_AT_3_PLUS) {
1134
track_.bitrate = (track_.bytesPerFrame * 352800) / 1000;
1135
track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0;
1136
track_.jointStereo = false;
1137
}
1138
1139
track_.dataByteOffset = 0;
1140
first_.size = 0;
1141
track_.fileSize = track_.bytesPerFrame; // not really meaningful
1142
bufferState_ = ATRAC_STATUS_LOW_LEVEL;
1143
currentSample_ = 0;
1144
CreateDecoder();
1145
WriteContextToPSPMem();
1146
}
1147
1148