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 <map>
19 #include <algorithm>
20
21 #include "Core/Config.h"
22 #include "Core/Debugger/MemBlockInfo.h"
23 #include "Core/HLE/HLE.h"
24 #include "Core/HLE/FunctionWrappers.h"
25 #include "Core/HLE/sceKernelMemory.h"
26 #include "Core/HLE/sceMp3.h"
27 #include "Core/HW/MediaEngine.h"
28 #include "Core/HW/SimpleAudioDec.h"
29 #include "Core/MemMap.h"
30 #include "Core/Reporting.h"
31 #include "Common/Serialize/SerializeFuncs.h"
32 #include "Common/Serialize/SerializeMap.h"
33
34 static const u32 ERROR_MP3_INVALID_HANDLE = 0x80671001;
35 static const u32 ERROR_MP3_UNRESERVED_HANDLE = 0x80671102;
36 static const u32 ERROR_MP3_NOT_YET_INIT_HANDLE = 0x80671103;
37 static const u32 ERROR_MP3_NO_RESOURCE_AVAIL = 0x80671201;
38 static const u32 ERROR_MP3_BAD_SAMPLE_RATE = 0x80671302;
39 static const u32 ERROR_MP3_BAD_RESET_FRAME = 0x80671501;
40 static const u32 ERROR_MP3_BAD_ADDR = 0x80671002;
41 static const u32 ERROR_MP3_BAD_SIZE = 0x80671003;
42 static const u32 ERROR_AVCODEC_INVALID_DATA = 0x807f00fd;
43 static const int AU_BUF_MIN_SIZE = 8192;
44 static const int PCM_BUF_MIN_SIZE = 9216;
45 static const size_t MP3_MAX_HANDLES = 2;
46
47 struct Mp3Context {
48 public:
49
50 int mp3StreamStart;
51 int mp3StreamEnd;
52 u32 mp3Buf;
53 int mp3BufSize;
54 u32 mp3PcmBuf;
55 int mp3PcmBufSize;
56
57 int readPosition;
58
59 int bufferRead;
60 int bufferWrite;
61 int bufferAvailable;
62
63 int mp3DecodedBytes;
64 int mp3LoopNum;
65 int mp3MaxSamples;
66 int mp3SumDecodedSamples;
67
68 int mp3Channels;
69 int mp3Bitrate;
70 int mp3SamplingRate;
71 int mp3Version;
72
DoStateMp3Context73 void DoState(PointerWrap &p) {
74 auto s = p.Section("Mp3Context", 1);
75 if (!s)
76 return;
77
78 Do(p, mp3StreamStart);
79 Do(p, mp3StreamEnd);
80 Do(p, mp3Buf);
81 Do(p, mp3BufSize);
82 Do(p, mp3PcmBuf);
83 Do(p, mp3PcmBufSize);
84 Do(p, readPosition);
85 Do(p, bufferRead);
86 Do(p, bufferWrite);
87 Do(p, bufferAvailable);
88 Do(p, mp3DecodedBytes);
89 Do(p, mp3LoopNum);
90 Do(p, mp3MaxSamples);
91 Do(p, mp3SumDecodedSamples);
92 Do(p, mp3Channels);
93 Do(p, mp3Bitrate);
94 Do(p, mp3SamplingRate);
95 Do(p, mp3Version);
96 };
97 };
98
99 static std::map<u32, AuCtx *> mp3Map;
100 static const int mp3DecodeDelay = 2400;
101 static bool resourceInited = false;
102
getMp3Ctx(u32 mp3)103 static AuCtx *getMp3Ctx(u32 mp3) {
104 if (mp3Map.find(mp3) == mp3Map.end())
105 return NULL;
106 return mp3Map[mp3];
107 }
108
__Mp3Shutdown()109 void __Mp3Shutdown() {
110 for (auto it = mp3Map.begin(), end = mp3Map.end(); it != end; ++it) {
111 delete it->second;
112 }
113 mp3Map.clear();
114 }
115
__Mp3DoState(PointerWrap & p)116 void __Mp3DoState(PointerWrap &p) {
117 auto s = p.Section("sceMp3", 0, 3);
118 if (!s)
119 return;
120
121 if (s >= 2) {
122 Do(p, mp3Map);
123 } else {
124 std::map<u32, Mp3Context *> mp3Map_old;
125 Do(p, mp3Map_old); // read old map
126 for (auto it = mp3Map_old.begin(), end = mp3Map_old.end(); it != end; ++it) {
127 auto mp3 = new AuCtx;
128 u32 id = it->first;
129 auto mp3_old = it->second;
130 mp3->AuBuf = mp3_old->mp3Buf;
131 mp3->AuBufSize = mp3_old->mp3BufSize;
132 mp3->PCMBuf = mp3_old->mp3PcmBuf;
133 mp3->PCMBufSize = mp3_old->mp3PcmBufSize;
134 mp3->BitRate = mp3_old->mp3Bitrate;
135 mp3->Channels = mp3_old->mp3Channels;
136 mp3->endPos = mp3_old->mp3StreamEnd;
137 mp3->startPos = mp3_old->mp3StreamStart;
138 mp3->LoopNum = mp3_old->mp3LoopNum;
139 mp3->SamplingRate = mp3_old->mp3SamplingRate;
140 mp3->freq = mp3->SamplingRate;
141 mp3->SumDecodedSamples = mp3_old->mp3SumDecodedSamples;
142 mp3->Version = mp3_old->mp3Version;
143 mp3->MaxOutputSample = mp3_old->mp3MaxSamples;
144 mp3->readPos = mp3_old->readPosition;
145 mp3->AuBufAvailable = 0; // reset to read from file
146 mp3->askedReadSize = 0;
147
148 mp3->audioType = PSP_CODEC_MP3;
149 mp3->decoder = new SimpleAudio(mp3->audioType);
150 mp3Map[id] = mp3;
151 }
152 }
153
154 if (s >= 3) {
155 Do(p, resourceInited);
156 } else {
157 // Previous behavior acted as if it was already inited.
158 resourceInited = true;
159 }
160 }
161
sceMp3Decode(u32 mp3,u32 outPcmPtr)162 static int sceMp3Decode(u32 mp3, u32 outPcmPtr) {
163 AuCtx *ctx = getMp3Ctx(mp3);
164 if (!ctx) {
165 if (mp3 >= MP3_MAX_HANDLES)
166 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
167 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
168 } else if (ctx->Version < 0 || ctx->AuBuf == 0) {
169 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
170 }
171
172 int pcmBytes = ctx->AuDecode(outPcmPtr);
173 if (pcmBytes > 0) {
174 // decode data successfully, delay thread
175 return hleDelayResult(hleLogSuccessI(ME, pcmBytes), "mp3 decode", mp3DecodeDelay);
176 }
177 // Should already have logged.
178 return pcmBytes;
179 }
180
sceMp3ResetPlayPosition(u32 mp3)181 static int sceMp3ResetPlayPosition(u32 mp3) {
182 AuCtx *ctx = getMp3Ctx(mp3);
183 if (!ctx) {
184 if (mp3 >= MP3_MAX_HANDLES)
185 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
186 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
187 } else if (ctx->Version < 0 || ctx->AuBuf == 0) {
188 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
189 }
190
191 return hleLogSuccessI(ME, ctx->AuResetPlayPosition());
192 }
193
sceMp3CheckStreamDataNeeded(u32 mp3)194 static int sceMp3CheckStreamDataNeeded(u32 mp3) {
195 AuCtx *ctx = getMp3Ctx(mp3);
196 if (!ctx) {
197 if (mp3 >= MP3_MAX_HANDLES)
198 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
199 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
200 } else if (ctx->AuBuf == 0) {
201 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
202 }
203
204 return hleLogSuccessI(ME, ctx->AuCheckStreamDataNeeded());
205 }
206
sceMp3ReserveMp3Handle(u32 mp3Addr)207 static u32 sceMp3ReserveMp3Handle(u32 mp3Addr) {
208 if (!resourceInited) {
209 return hleLogError(ME, ERROR_MP3_NO_RESOURCE_AVAIL, "sceMp3InitResource must be called first");
210 }
211 if (mp3Map.size() >= MP3_MAX_HANDLES) {
212 return hleLogError(ME, ERROR_MP3_NO_RESOURCE_AVAIL, "no free handles");
213 }
214 if (mp3Addr != 0 && !Memory::IsValidRange(mp3Addr, 32)) {
215 // The PSP would crash, but might as well return a proper error.
216 return hleLogError(ME, SCE_KERNEL_ERROR_INVALID_POINTER, "bad mp3 pointer");
217 }
218
219 AuCtx *Au = new AuCtx;
220 if (mp3Addr) {
221 Au->startPos = Memory::Read_U64(mp3Addr); // Audio stream start position.
222 Au->endPos = Memory::Read_U64(mp3Addr + 8); // Audio stream end position.
223 Au->AuBuf = Memory::Read_U32(mp3Addr + 16); // Input Au data buffer.
224 Au->AuBufSize = Memory::Read_U32(mp3Addr + 20); // Input Au data buffer size.
225 Au->PCMBuf = Memory::Read_U32(mp3Addr + 24); // Output PCM data buffer.
226 Au->PCMBufSize = Memory::Read_U32(mp3Addr + 28); // Output PCM data buffer size.
227
228 if (Au->startPos >= Au->endPos) {
229 delete Au;
230 return hleLogError(ME, ERROR_MP3_BAD_SIZE, "start must be before end");
231 }
232 if (!Au->AuBuf || !Au->PCMBuf) {
233 delete Au;
234 return hleLogError(ME, ERROR_MP3_BAD_ADDR, "invalid buffer addresses");
235 }
236 if ((int)Au->AuBufSize < AU_BUF_MIN_SIZE || (int)Au->PCMBufSize < PCM_BUF_MIN_SIZE) {
237 delete Au;
238 return hleLogError(ME, ERROR_MP3_BAD_SIZE, "buffers too small");
239 }
240
241 DEBUG_LOG(ME, "startPos %llx endPos %llx mp3buf %08x mp3bufSize %08x PCMbuf %08x PCMbufSize %08x",
242 Au->startPos, Au->endPos, Au->AuBuf, Au->AuBufSize, Au->PCMBuf, Au->PCMBufSize);
243 } else {
244 Au->startPos = 0;
245 Au->endPos = 0;
246 Au->AuBuf = 0;
247 Au->AuBufSize = 0;
248 Au->PCMBuf = 0;
249 Au->PCMBufSize = 0;
250 }
251
252 Au->SumDecodedSamples = 0;
253 Au->LoopNum = -1;
254 Au->AuBufAvailable = 0;
255 Au->readPos = Au->startPos;
256
257 Au->audioType = PSP_CODEC_MP3;
258 Au->decoder = new SimpleAudio(Au->audioType);
259
260 int handle = (int)mp3Map.size();
261 mp3Map[handle] = Au;
262
263 return hleLogSuccessI(ME, handle);
264 }
265
sceMp3InitResource()266 static int sceMp3InitResource() {
267 // TODO: Could validate the utility modules have been loaded?
268 if (resourceInited) {
269 return hleLogSuccessI(ME, 0);
270 }
271 resourceInited = true;
272 return hleLogSuccessI(ME, hleDelayResult(0, "mp3 resource init", 200));
273 }
274
sceMp3TermResource()275 static int sceMp3TermResource() {
276 if (!resourceInited) {
277 return hleLogSuccessI(ME, 0);
278 }
279
280 // Free any handles that are still open.
281 for (auto au : mp3Map) {
282 delete au.second;
283 }
284 mp3Map.clear();
285
286 resourceInited = false;
287 return hleLogSuccessI(ME, hleDelayResult(0, "mp3 resource term", 100));
288 }
289
__CalculateMp3Channels(int bitval)290 static int __CalculateMp3Channels(int bitval) {
291 if (bitval == 0 || bitval == 1 || bitval == 2) { // Stereo / Joint Stereo / Dual Channel.
292 return 2;
293 }
294 else if (bitval == 3) { // Mono.
295 return 1;
296 }
297 else {
298 return -1;
299 }
300 }
301
__CalculateMp3SampleRates(int bitval,int mp3version)302 static int __CalculateMp3SampleRates(int bitval, int mp3version) {
303 if (mp3version == 3) { // MPEG Version 1
304 int valuemapping[] = { 44100, 48000, 32000, -1 };
305 return valuemapping[bitval];
306 }
307 else if (mp3version == 2) { // MPEG Version 2
308 int valuemapping[] = { 22050, 24000, 16000, -1 };
309 return valuemapping[bitval];
310 }
311 else if (mp3version == 0) { // MPEG Version 2.5
312 int valuemapping[] = { 11025, 12000, 8000, -1 };
313 return valuemapping[bitval];
314 }
315 else {
316 return -1;
317 }
318 }
319
__CalculateMp3Bitrates(int bitval,int mp3version,int mp3layer)320 static int __CalculateMp3Bitrates(int bitval, int mp3version, int mp3layer) {
321 if (mp3version == 3) { // MPEG Version 1
322 if (mp3layer == 3) { // Layer I
323 int valuemapping[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 };
324 return valuemapping[bitval];
325 }
326 else if (mp3layer == 2) { // Layer II
327 int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 };
328 return valuemapping[bitval];
329 }
330 else if (mp3layer == 1) { // Layer III
331 int valuemapping[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 };
332 return valuemapping[bitval];
333 }
334 else {
335 return -1;
336 }
337 }
338 else if (mp3version == 2 || mp3version == 0) { // MPEG Version 2 or 2.5
339 if (mp3layer == 3) { // Layer I
340 int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 };
341 return valuemapping[bitval];
342 }
343 else if (mp3layer == 1 || mp3layer == 2) { // Layer II or III
344 int valuemapping[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 };
345 return valuemapping[bitval];
346 }
347 else {
348 return -1;
349 }
350 }
351 else {
352 return -1;
353 }
354 }
355
CalculateMp3SamplesPerFrame(int versionBits,int layerBits)356 static int CalculateMp3SamplesPerFrame(int versionBits, int layerBits) {
357 if (versionBits == 1 || layerBits == 0) {
358 return -1;
359 } else if (layerBits == 3) {
360 return 384;
361 } else if (layerBits == 2 || versionBits == 3) {
362 return 1152;
363 } else {
364 return 576;
365 }
366 }
367
FindMp3Header(AuCtx * ctx,int & header,int end)368 static int FindMp3Header(AuCtx *ctx, int &header, int end) {
369 u32 addr = ctx->AuBuf + ctx->AuStreamWorkareaSize();
370 if (Memory::IsValidRange(addr, end)) {
371 u8 *ptr = Memory::GetPointerUnchecked(addr);
372 for (int offset = 0; offset < end; ++offset) {
373 // If we hit valid sync bits, then we've found a header.
374 if (ptr[offset] == 0xFF && (ptr[offset + 1] & 0xC0) == 0xC0) {
375 header = bswap32(Memory::Read_U32(addr + offset));
376 return offset;
377 }
378 }
379 }
380
381 return -1;
382 }
383
sceMp3Init(u32 mp3)384 static int sceMp3Init(u32 mp3) {
385 int sdkver = sceKernelGetCompiledSdkVersion();
386 AuCtx *ctx = getMp3Ctx(mp3);
387 if (!ctx) {
388 if (mp3 >= MP3_MAX_HANDLES)
389 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
390 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
391 } else if (ctx->AuBuf == 0) {
392 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
393 }
394
395 static const int PARSE_DELAY_MS = 500;
396
397 // First, let's search for the MP3 header. It can be offset by at most 1439 bytes.
398 // If we have an ID3 tag, we'll get past it based on frame sync. Don't modify startPos.
399 int header = 0;
400 if (FindMp3Header(ctx, header, 1440) < 0)
401 return hleDelayResult(hleLogWarning(ME, ERROR_AVCODEC_INVALID_DATA, "no header found"), "mp3 init", PARSE_DELAY_MS);
402
403 // Parse the Mp3 header
404 int layerBits = (header >> 17) & 0x3;
405 int versionBits = (header >> 19) & 0x3;
406 int bitrate = __CalculateMp3Bitrates((header >> 12) & 0xF, versionBits, layerBits);
407 int samplerate = __CalculateMp3SampleRates((header >> 10) & 0x3, versionBits);;
408 int channels = __CalculateMp3Channels((header >> 6) & 0x3);
409
410 DEBUG_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps, layerBits=%d ,versionBits=%d,HEADER: %08x", channels, samplerate, bitrate, layerBits, versionBits, header);
411
412 if (layerBits != 1) {
413 // TODO: Should return ERROR_AVCODEC_INVALID_DATA.
414 WARN_LOG_REPORT(ME, "sceMp3Init: invalid data: not layer 3");
415 }
416 if (bitrate == 0 || bitrate == -1) {
417 return hleDelayResult(hleReportError(ME, ERROR_AVCODEC_INVALID_DATA, "invalid bitrate v%d l%d rate %04x", versionBits, layerBits, (header >> 12) & 0xF), "mp3 init", PARSE_DELAY_MS);
418 }
419 if (samplerate == -1) {
420 return hleDelayResult(hleReportError(ME, ERROR_AVCODEC_INVALID_DATA, "invalid sample rate v%d l%d rate %02x", versionBits, layerBits, (header >> 10) & 0x3), "mp3 init", PARSE_DELAY_MS);
421 }
422
423 // Before we allow init, newer SDK versions next require at least 156 bytes.
424 // That happens to be the size of the first frame header for VBR.
425 if (sdkver >= 0x06000000 && ctx->readPos < 156) {
426 return hleDelayResult(hleLogError(ME, SCE_KERNEL_ERROR_INVALID_VALUE, "insufficient mp3 data for init"), "mp3 init", PARSE_DELAY_MS);
427 }
428
429 ctx->SamplingRate = samplerate;
430 ctx->Channels = channels;
431 ctx->BitRate = bitrate;
432 ctx->MaxOutputSample = CalculateMp3SamplesPerFrame(versionBits, layerBits);
433 ctx->freq = ctx->SamplingRate;
434
435 if (versionBits != 3) {
436 // TODO: Should return 0x80671301 (unsupported version?)
437 WARN_LOG_REPORT(ME, "sceMp3Init: invalid data: not MPEG v1");
438 }
439 if (samplerate != 44100 && sdkver < 3090500) {
440 return hleDelayResult(hleLogError(ME, ERROR_MP3_BAD_SAMPLE_RATE, "invalid data: not 44.1kHz"), "mp3 init", PARSE_DELAY_MS);
441 }
442
443 // Based on bitrate, we can calculate the frame size in bytes.
444 // Note: this doesn't correctly handle padding or slot size, but the PSP doesn't either.
445 uint32_t bytesPerSecond = (ctx->MaxOutputSample / 8) * ctx->BitRate * 1000;
446 // The frame count ignores the upper bits of these sizes, although they are used in cases.
447 uint64_t totalBytes = (ctx->endPos & 0xFFFFFFFF) - (ctx->startPos & 0xFFFFFFFF);
448 ctx->FrameNum = (int)((totalBytes * ctx->SamplingRate) / bytesPerSecond);
449
450 ctx->Version = versionBits;
451
452 // This tells us to resample to the same frequency it decodes to.
453 ctx->decoder->SetResampleFrequency(ctx->freq);
454
455 return hleDelayResult(hleLogSuccessI(ME, 0), "mp3 init", PARSE_DELAY_MS);
456 }
457
sceMp3GetLoopNum(u32 mp3)458 static int sceMp3GetLoopNum(u32 mp3) {
459 AuCtx *ctx = getMp3Ctx(mp3);
460 if (!ctx) {
461 if (mp3 >= MP3_MAX_HANDLES)
462 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
463 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
464 } else if (ctx->AuBuf == 0) {
465 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
466 }
467
468 return hleLogSuccessI(ME, ctx->AuGetLoopNum());
469 }
470
sceMp3GetMaxOutputSample(u32 mp3)471 static int sceMp3GetMaxOutputSample(u32 mp3) {
472 AuCtx *ctx = getMp3Ctx(mp3);
473 if (!ctx) {
474 if (mp3 >= MP3_MAX_HANDLES)
475 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
476 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
477 } else if (ctx->Version < 0) {
478 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
479 } else if (ctx->AuBuf == 0) {
480 return hleLogWarning(ME, 0, "no channel available for low level");
481 }
482
483 return hleLogSuccessI(ME, ctx->AuGetMaxOutputSample());
484 }
485
sceMp3GetSumDecodedSample(u32 mp3)486 static int sceMp3GetSumDecodedSample(u32 mp3) {
487 AuCtx *ctx = getMp3Ctx(mp3);
488 if (!ctx) {
489 if (mp3 >= MP3_MAX_HANDLES)
490 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
491 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
492 } else if (ctx->AuBuf == 0) {
493 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
494 }
495
496 return hleLogSuccessI(ME, ctx->AuGetSumDecodedSample());
497 }
498
sceMp3SetLoopNum(u32 mp3,int loop)499 static int sceMp3SetLoopNum(u32 mp3, int loop) {
500 AuCtx *ctx = getMp3Ctx(mp3);
501 if (!ctx) {
502 if (mp3 >= MP3_MAX_HANDLES)
503 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
504 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
505 } else if (ctx->AuBuf == 0) {
506 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
507 }
508
509 if (loop < 0)
510 loop = -1;
511
512 return hleLogSuccessI(ME, ctx->AuSetLoopNum(loop));
513 }
514
sceMp3GetMp3ChannelNum(u32 mp3)515 static int sceMp3GetMp3ChannelNum(u32 mp3) {
516 AuCtx *ctx = getMp3Ctx(mp3);
517 if (!ctx) {
518 if (mp3 >= MP3_MAX_HANDLES)
519 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
520 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
521 } else if (ctx->Version < 0) {
522 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
523 } else if (ctx->AuBuf == 0) {
524 return hleLogWarning(ME, 0, "no channel available for low level");
525 }
526
527 return hleLogSuccessI(ME, ctx->AuGetChannelNum());
528 }
529
sceMp3GetBitRate(u32 mp3)530 static int sceMp3GetBitRate(u32 mp3) {
531 AuCtx *ctx = getMp3Ctx(mp3);
532 if (!ctx) {
533 if (mp3 >= MP3_MAX_HANDLES)
534 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
535 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
536 } else if (ctx->Version < 0) {
537 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
538 } else if (ctx->AuBuf == 0) {
539 return hleLogWarning(ME, 0, "no bitrate available for low level");
540 }
541
542 return hleLogSuccessI(ME, ctx->AuGetBitRate());
543 }
544
sceMp3GetSamplingRate(u32 mp3)545 static int sceMp3GetSamplingRate(u32 mp3) {
546 AuCtx *ctx = getMp3Ctx(mp3);
547 if (!ctx) {
548 if (mp3 >= MP3_MAX_HANDLES)
549 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
550 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
551 } else if (ctx->Version < 0) {
552 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
553 } else if (ctx->AuBuf == 0) {
554 return hleLogWarning(ME, 0, "no sample rate available for low level");
555 }
556
557 return hleLogSuccessI(ME, ctx->AuGetSamplingRate());
558 }
559
sceMp3GetInfoToAddStreamData(u32 mp3,u32 dstPtr,u32 towritePtr,u32 srcposPtr)560 static int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) {
561 AuCtx *ctx = getMp3Ctx(mp3);
562 if (!ctx) {
563 if (mp3 >= MP3_MAX_HANDLES)
564 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
565 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
566 } else if (ctx->AuBuf == 0) {
567 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
568 }
569
570 return hleLogSuccessI(ME, ctx->AuGetInfoToAddStreamData(dstPtr, towritePtr, srcposPtr));
571 }
572
sceMp3NotifyAddStreamData(u32 mp3,int size)573 static int sceMp3NotifyAddStreamData(u32 mp3, int size) {
574 AuCtx *ctx = getMp3Ctx(mp3);
575 if (!ctx) {
576 if (mp3 >= MP3_MAX_HANDLES)
577 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
578 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
579 } else if (ctx->AuBuf == 0) {
580 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
581 }
582
583 return hleLogSuccessI(ME, ctx->AuNotifyAddStreamData(size));
584 }
585
sceMp3ReleaseMp3Handle(u32 mp3)586 static int sceMp3ReleaseMp3Handle(u32 mp3) {
587 AuCtx *ctx = getMp3Ctx(mp3);
588 if (ctx) {
589 delete ctx;
590 mp3Map.erase(mp3);
591 return hleLogSuccessI(ME, 0);
592 } else if (mp3 >= MP3_MAX_HANDLES) {
593 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
594 }
595
596 // Intentionally a zero result.
597 return hleLogDebug(ME, 0, "double free ignored");
598 }
599
sceMp3EndEntry()600 static u32 sceMp3EndEntry() {
601 ERROR_LOG_REPORT(ME, "UNIMPL sceMp3EndEntry(...)");
602 return 0;
603 }
604
sceMp3StartEntry()605 static u32 sceMp3StartEntry() {
606 ERROR_LOG_REPORT(ME, "UNIMPL sceMp3StartEntry(...)");
607 return 0;
608 }
609
sceMp3GetFrameNum(u32 mp3)610 static u32 sceMp3GetFrameNum(u32 mp3) {
611 AuCtx *ctx = getMp3Ctx(mp3);
612 if (!ctx) {
613 if (mp3 >= MP3_MAX_HANDLES)
614 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
615 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
616 } else if (ctx->Version < 0 || ctx->AuBuf == 0) {
617 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
618 }
619
620 return hleLogSuccessI(ME, ctx->AuGetFrameNum());
621 }
622
sceMp3GetMPEGVersion(u32 mp3)623 static u32 sceMp3GetMPEGVersion(u32 mp3) {
624 AuCtx *ctx = getMp3Ctx(mp3);
625 if (!ctx) {
626 if (mp3 >= MP3_MAX_HANDLES)
627 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
628 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "unreserved handle");
629 } else if (ctx->Version < 0) {
630 // Seems to be the wrong error code.
631 return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "not yet init");
632 } else if (ctx->AuBuf == 0) {
633 return hleLogWarning(ME, 0, "no MPEG version available for low level");
634 }
635
636 // Tests have not revealed how to expose more than "3" here as a result.
637 return hleReportDebug(ME, ctx->AuGetVersion());
638 }
639
sceMp3ResetPlayPositionByFrame(u32 mp3,u32 frame)640 static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, u32 frame) {
641 AuCtx *ctx = getMp3Ctx(mp3);
642 if (!ctx) {
643 if (mp3 >= MP3_MAX_HANDLES)
644 return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
645 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
646 } else if (ctx->Version < 0 || ctx->AuBuf == 0) {
647 return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
648 }
649
650 if ((int)frame >= ctx->AuGetFrameNum()) {
651 return hleLogError(ME, ERROR_MP3_BAD_RESET_FRAME, "bad frame position");
652 }
653
654 return hleLogSuccessI(ME, ctx->AuResetPlayPositionByFrame(frame));
655 }
656
sceMp3LowLevelInit(u32 mp3,u32 unk)657 static u32 sceMp3LowLevelInit(u32 mp3, u32 unk) {
658 INFO_LOG(ME, "sceMp3LowLevelInit(%i, %i)", mp3, unk);
659 auto ctx = new AuCtx;
660
661 ctx->audioType = PSP_CODEC_MP3;
662 // create mp3 decoder
663 ctx->decoder = new SimpleAudio(ctx->audioType);
664
665 // close the audio if mp3 already exists.
666 if (mp3Map.find(mp3) != mp3Map.end()) {
667 delete mp3Map[mp3];
668 mp3Map.erase(mp3);
669 }
670 mp3Map[mp3] = ctx;
671
672 // Indicate that we've run low level init by setting version to 1.
673 ctx->Version = 1;
674
675 return 0;
676 }
677
sceMp3LowLevelDecode(u32 mp3,u32 sourceAddr,u32 sourceBytesConsumedAddr,u32 samplesAddr,u32 sampleBytesAddr)678 static u32 sceMp3LowLevelDecode(u32 mp3, u32 sourceAddr, u32 sourceBytesConsumedAddr, u32 samplesAddr, u32 sampleBytesAddr) {
679 // sourceAddr: input mp3 stream buffer
680 // sourceBytesConsumedAddr: consumed bytes decoded in source
681 // samplesAddr: output pcm buffer
682 // sampleBytesAddr: output pcm size
683 DEBUG_LOG(ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x)", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr);
684
685 AuCtx *ctx = getMp3Ctx(mp3);
686 if (!ctx) {
687 ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
688 return -1;
689 }
690
691 if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(sourceBytesConsumedAddr) ||
692 !Memory::IsValidAddress(samplesAddr) || !Memory::IsValidAddress(sampleBytesAddr)) {
693 ERROR_LOG(ME, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x) : invalid address in args", mp3, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr);
694 return -1;
695 }
696
697 auto inbuff = Memory::GetPointer(sourceAddr);
698 auto outbuff = Memory::GetPointer(samplesAddr);
699
700 int outpcmbytes = 0;
701 ctx->decoder->Decode((void*)inbuff, 4096, outbuff, &outpcmbytes);
702 NotifyMemInfo(MemBlockFlags::WRITE, samplesAddr, outpcmbytes, "Mp3LowLevelDecode");
703
704 Memory::Write_U32(ctx->decoder->GetSourcePos(), sourceBytesConsumedAddr);
705 Memory::Write_U32(outpcmbytes, sampleBytesAddr);
706 return 0;
707 }
708
709 const HLEFunction sceMp3[] = {
710 {0X07EC321A, &WrapU_U<sceMp3ReserveMp3Handle>, "sceMp3ReserveMp3Handle", 'x', "x" },
711 {0X0DB149F4, &WrapI_UI<sceMp3NotifyAddStreamData>, "sceMp3NotifyAddStreamData", 'i', "xi" },
712 {0X2A368661, &WrapI_U<sceMp3ResetPlayPosition>, "sceMp3ResetPlayPosition", 'i', "x" },
713 {0X354D27EA, &WrapI_U<sceMp3GetSumDecodedSample>, "sceMp3GetSumDecodedSample", 'i', "x" },
714 {0X35750070, &WrapI_V<sceMp3InitResource>, "sceMp3InitResource", 'i', "" },
715 {0X3C2FA058, &WrapI_V<sceMp3TermResource>, "sceMp3TermResource", 'i', "" },
716 {0X3CEF484F, &WrapI_UI<sceMp3SetLoopNum>, "sceMp3SetLoopNum", 'i', "xi" },
717 {0X44E07129, &WrapI_U<sceMp3Init>, "sceMp3Init", 'i', "x" },
718 {0X732B042A, &WrapU_V<sceMp3EndEntry>, "sceMp3EndEntry", 'x', "" },
719 {0X7F696782, &WrapI_U<sceMp3GetMp3ChannelNum>, "sceMp3GetMp3ChannelNum", 'i', "x" },
720 {0X87677E40, &WrapI_U<sceMp3GetBitRate>, "sceMp3GetBitRate", 'i', "x" },
721 {0X87C263D1, &WrapI_U<sceMp3GetMaxOutputSample>, "sceMp3GetMaxOutputSample", 'i', "x" },
722 {0X8AB81558, &WrapU_V<sceMp3StartEntry>, "sceMp3StartEntry", 'x', "" },
723 {0X8F450998, &WrapI_U<sceMp3GetSamplingRate>, "sceMp3GetSamplingRate", 'i', "x" },
724 {0XA703FE0F, &WrapI_UUUU<sceMp3GetInfoToAddStreamData>, "sceMp3GetInfoToAddStreamData", 'i', "xppp" },
725 {0XD021C0FB, &WrapI_UU<sceMp3Decode>, "sceMp3Decode", 'i', "xp" },
726 {0XD0A56296, &WrapI_U<sceMp3CheckStreamDataNeeded>, "sceMp3CheckStreamDataNeeded", 'i', "x" },
727 {0XD8F54A51, &WrapI_U<sceMp3GetLoopNum>, "sceMp3GetLoopNum", 'i', "x" },
728 {0XF5478233, &WrapI_U<sceMp3ReleaseMp3Handle>, "sceMp3ReleaseMp3Handle", 'i', "x" },
729 {0XAE6D2027, &WrapU_U<sceMp3GetMPEGVersion>, "sceMp3GetMPEGVersion", 'x', "x" },
730 {0X3548AEC8, &WrapU_U<sceMp3GetFrameNum>, "sceMp3GetFrameNum", 'i', "x" },
731 {0X0840E808, &WrapU_UU<sceMp3ResetPlayPositionByFrame>, "sceMp3ResetPlayPositionByFrame", 'i', "xi" },
732 {0X1B839B83, &WrapU_UU<sceMp3LowLevelInit>, "sceMp3LowLevelInit", 'x', "xx" },
733 {0XE3EE2C81, &WrapU_UUUUU<sceMp3LowLevelDecode>, "sceMp3LowLevelDecode", 'x', "xxxxx"}
734 };
735
Register_sceMp3()736 void Register_sceMp3() {
737 RegisterModule("sceMp3", ARRAY_SIZE(sceMp3), sceMp3);
738 }
739