1 // Copyright (c) 2012- PPSSPP Project.
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.
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.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
21 #include "Core/Config.h"
22 #include "Core/HLE/HLE.h"
23 #include "Core/HLE/FunctionWrappers.h"
24 #include "Core/HLE/sceMp3.h"
25 #include "Core/HW/MediaEngine.h"
26 #include "Core/MemMap.h"
27 #include "Core/Reporting.h"
28 #include "Core/HW/SimpleAudioDec.h"
50 int mp3SumDecodedSamples
;
57 void DoState(PointerWrap
&p
) {
58 auto s
= p
.Section("Mp3Context", 1);
71 p
.Do(bufferAvailable
);
72 p
.Do(mp3DecodedBytes
);
75 p
.Do(mp3SumDecodedSamples
);
78 p
.Do(mp3SamplingRate
);
83 static std::map
<u32
, Mp3Context
*> mp3Map_old
;
84 static std::map
<u32
, AuCtx
*> mp3Map
;
85 static const int mp3DecodeDelay
= 4000;
87 static AuCtx
*getMp3Ctx(u32 mp3
) {
88 if (mp3Map
.find(mp3
) == mp3Map
.end())
93 void __Mp3Shutdown() {
94 for (auto it
= mp3Map
.begin(), end
= mp3Map
.end(); it
!= end
; ++it
) {
100 void __Mp3DoState(PointerWrap
&p
) {
101 auto s
= p
.Section("sceMp3", 0, 2);
108 if (s
<= 1 && p
.mode
== p
.MODE_READ
){
109 p
.Do(mp3Map_old
); // read old map
110 for (auto it
= mp3Map_old
.begin(), end
= mp3Map_old
.end(); it
!= end
; ++it
) {
111 auto mp3
= new AuCtx
;
113 auto mp3_old
= it
->second
;
114 mp3
->AuBuf
= mp3_old
->mp3Buf
;
115 mp3
->AuBufSize
= mp3_old
->mp3BufSize
;
116 mp3
->PCMBuf
= mp3_old
->mp3PcmBuf
;
117 mp3
->PCMBufSize
= mp3_old
->mp3PcmBufSize
;
118 mp3
->BitRate
= mp3_old
->mp3Bitrate
;
119 mp3
->Channels
= mp3_old
->mp3Channels
;
120 mp3
->endPos
= mp3_old
->mp3StreamEnd
;
121 mp3
->startPos
= mp3_old
->mp3StreamStart
;
122 mp3
->LoopNum
= mp3_old
->mp3LoopNum
;
123 mp3
->SamplingRate
= mp3_old
->mp3SamplingRate
;
124 mp3
->freq
= mp3
->SamplingRate
;
125 mp3
->SumDecodedSamples
= mp3_old
->mp3SumDecodedSamples
;
126 mp3
->Version
= mp3_old
->mp3Version
;
127 mp3
->MaxOutputSample
= mp3_old
->mp3MaxSamples
;
128 mp3
->readPos
= mp3_old
->readPosition
;
129 mp3
->AuBufAvailable
= 0; // reset to read from file
130 mp3
->askedReadSize
= 0;
131 mp3
->realReadSize
= 0;
133 mp3
->audioType
= PSP_CODEC_MP3
;
134 mp3
->decoder
= new SimpleAudio(mp3
->audioType
);
140 static int sceMp3Decode(u32 mp3
, u32 outPcmPtr
) {
141 DEBUG_LOG(ME
, "sceMp3Decode(%08x,%08x)", mp3
, outPcmPtr
);
143 AuCtx
*ctx
= getMp3Ctx(mp3
);
145 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
149 int pcmBytes
= ctx
->AuDecode(outPcmPtr
);
151 // decode data successfully, delay thread
152 hleDelayResult(pcmBytes
, "mp3 decode", mp3DecodeDelay
);
157 static int sceMp3ResetPlayPosition(u32 mp3
) {
158 DEBUG_LOG(ME
, "SceMp3ResetPlayPosition(%08x)", mp3
);
160 AuCtx
*ctx
= getMp3Ctx(mp3
);
162 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
166 return ctx
->AuResetPlayPosition();
169 static int sceMp3CheckStreamDataNeeded(u32 mp3
) {
170 DEBUG_LOG(ME
, "sceMp3CheckStreamDataNeeded(%08x)", mp3
);
172 AuCtx
*ctx
= getMp3Ctx(mp3
);
174 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
178 return ctx
->AuCheckStreamDataNeeded();
181 static u32
sceMp3ReserveMp3Handle(u32 mp3Addr
) {
182 INFO_LOG(ME
, "sceMp3ReserveMp3Handle(%08x)", mp3Addr
);
183 if (!Memory::IsValidAddress(mp3Addr
)){
184 ERROR_LOG(ME
, "sceMp3ReserveMp3Handle(%08x) invalid address %08x", mp3Addr
, mp3Addr
);
188 AuCtx
*Au
= new AuCtx
;
189 Au
->startPos
= Memory::Read_U64(mp3Addr
); // Audio stream start position.
190 Au
->endPos
= Memory::Read_U32(mp3Addr
+ 8); // Audio stream end position.
191 Au
->AuBuf
= Memory::Read_U32(mp3Addr
+ 16); // Input Au data buffer.
192 Au
->AuBufSize
= Memory::Read_U32(mp3Addr
+ 20); // Input Au data buffer size.
193 Au
->PCMBuf
= Memory::Read_U32(mp3Addr
+ 24); // Output PCM data buffer.
194 Au
->PCMBufSize
= Memory::Read_U32(mp3Addr
+ 28); // Output PCM data buffer size.
196 DEBUG_LOG(ME
, "startPos %llx endPos %llx mp3buf %08x mp3bufSize %08x PCMbuf %08x PCMbufSize %08x",
197 Au
->startPos
, Au
->endPos
, Au
->AuBuf
, Au
->AuBufSize
, Au
->PCMBuf
, Au
->PCMBufSize
);
199 Au
->audioType
= PSP_CODEC_MP3
;
201 Au
->SumDecodedSamples
= 0;
202 Au
->MaxOutputSample
= Au
->PCMBufSize
/ 4;
204 Au
->AuBufAvailable
= 0;
205 Au
->readPos
= Au
->startPos
;
208 Au
->decoder
= new SimpleAudio(Au
->audioType
);
210 // close the audio if mp3Addr already exist.
211 if (mp3Map
.find(mp3Addr
) != mp3Map
.end()) {
212 delete mp3Map
[mp3Addr
];
213 mp3Map
.erase(mp3Addr
);
216 mp3Map
[mp3Addr
] = Au
;
221 static int sceMp3InitResource() {
222 WARN_LOG(ME
, "UNIMPL: sceMp3InitResource");
227 static int sceMp3TermResource() {
228 WARN_LOG(ME
, "UNIMPL: sceMp3TermResource");
233 static int __CalculateMp3Channels(int bitval
) {
234 if (bitval
== 0 || bitval
== 1 || bitval
== 2) { // Stereo / Joint Stereo / Dual Channel.
237 else if (bitval
== 3) { // Mono.
245 static int __CalculateMp3SampleRates(int bitval
, int mp3version
) {
246 if (mp3version
== 3) { // MPEG Version 1
247 int valuemapping
[] = { 44100, 48000, 32000, -1 };
248 return valuemapping
[bitval
];
250 else if (mp3version
== 2) { // MPEG Version 2
251 int valuemapping
[] = { 22050, 24000, 16000, -1 };
252 return valuemapping
[bitval
];
254 else if (mp3version
== 0) { // MPEG Version 2.5
255 int valuemapping
[] = { 11025, 12000, 8000, -1 };
256 return valuemapping
[bitval
];
263 static int __CalculateMp3Bitrates(int bitval
, int mp3version
, int mp3layer
) {
264 if (mp3version
== 3) { // MPEG Version 1
265 if (mp3layer
== 3) { // Layer I
266 int valuemapping
[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 };
267 return valuemapping
[bitval
];
269 else if (mp3layer
== 2) { // Layer II
270 int valuemapping
[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 };
271 return valuemapping
[bitval
];
273 else if (mp3layer
== 1) { // Layer III
274 int valuemapping
[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 };
275 return valuemapping
[bitval
];
281 else if (mp3version
== 2 || mp3version
== 0) { // MPEG Version 2 or 2.5
282 if (mp3layer
== 3) { // Layer I
283 int valuemapping
[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 };
284 return valuemapping
[bitval
];
286 else if (mp3layer
== 1 || mp3layer
== 2) { // Layer II or III
287 int valuemapping
[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 };
288 return valuemapping
[bitval
];
299 static int __ParseMp3Header(AuCtx
*ctx
, bool *isID3
) {
300 int header
= bswap32(Memory::Read_U32(ctx
->AuBuf
));
301 // ID3 tag , can be seen in Hanayaka Nari Wa ga Ichizoku.
302 static const int ID3
= 0x49443300;
303 if ((header
& 0xFFFFFF00) == ID3
) {
305 int size
= bswap32(Memory::Read_U32(ctx
->AuBuf
+ ctx
->startPos
+ 6));
306 // Highest bit of each byte has to be ignored (format: 0x7F7F7F7F)
307 size
= (size
& 0x7F) | ((size
& 0x7F00) >> 1) | ((size
& 0x7F0000) >> 2) | ((size
& 0x7F000000) >> 3);
308 header
= bswap32(Memory::Read_U32(ctx
->AuBuf
+ ctx
->startPos
+ 10 + size
));
313 static int sceMp3Init(u32 mp3
) {
314 INFO_LOG(ME
, "sceMp3Init(%08x)", mp3
);
316 AuCtx
*ctx
= getMp3Ctx(mp3
);
318 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
322 // Parse the Mp3 header
323 bool hasID3Tag
= false;
324 int header
= __ParseMp3Header(ctx
, &hasID3Tag
);
325 int layer
= (header
>> 17) & 0x3;
326 ctx
->Version
= ((header
>> 19) & 0x3);
327 ctx
->SamplingRate
= __CalculateMp3SampleRates((header
>> 10) & 0x3, ctx
->Version
);
328 ctx
->Channels
= __CalculateMp3Channels((header
>> 6) & 0x3);
329 ctx
->BitRate
= __CalculateMp3Bitrates((header
>> 12) & 0xF, ctx
->Version
, layer
);
330 ctx
->freq
= ctx
->SamplingRate
;
332 INFO_LOG(ME
, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps", ctx
->Channels
, ctx
->SamplingRate
, ctx
->BitRate
);
334 // for mp3, if required freq is 48000, reset resampling Frequency to 48000 seems get better sound quality (e.g. Miku Custom BGM)
335 if (ctx
->freq
== 48000) {
336 ctx
->decoder
->SetResampleFrequency(ctx
->freq
);
339 // For mp3 file, if ID3 tag is detected, we must move startPos to 0x400 (stream start position), remove 0x400 bytes of the sourcebuff, and reduce the available buffer size by 0x400
340 // this is very important for ID3 tag mp3, since our universal audio decoder is for decoding stream part only.
342 // if get ID3 tage, we will decode from 0x400
343 ctx
->startPos
= 0x400;
344 ctx
->EatSourceBuff(0x400);
346 // if no ID3 tag, we will decode from the begining of the file
353 static int sceMp3GetLoopNum(u32 mp3
) {
354 DEBUG_LOG(ME
, "sceMp3GetLoopNum(%08x)", mp3
);
356 AuCtx
*ctx
= getMp3Ctx(mp3
);
358 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
362 return ctx
->AuGetLoopNum();
365 static int sceMp3GetMaxOutputSample(u32 mp3
) {
366 DEBUG_LOG(ME
, "sceMp3GetMaxOutputSample(%08x)", mp3
);
367 AuCtx
*ctx
= getMp3Ctx(mp3
);
369 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
373 return ctx
->AuGetMaxOutputSample();
376 static int sceMp3GetSumDecodedSample(u32 mp3
) {
377 INFO_LOG(ME
, "sceMp3GetSumDecodedSample(%08X)", mp3
);
379 AuCtx
*ctx
= getMp3Ctx(mp3
);
381 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
385 return ctx
->AuGetSumDecodedSample();
388 static int sceMp3SetLoopNum(u32 mp3
, int loop
) {
389 INFO_LOG(ME
, "sceMp3SetLoopNum(%08X, %i)", mp3
, loop
);
391 AuCtx
*ctx
= getMp3Ctx(mp3
);
393 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
397 return ctx
->AuSetLoopNum(loop
);
400 static int sceMp3GetMp3ChannelNum(u32 mp3
) {
401 INFO_LOG(ME
, "sceMp3GetMp3ChannelNum(%08X)", mp3
);
403 AuCtx
*ctx
= getMp3Ctx(mp3
);
405 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
409 return ctx
->AuGetChannelNum();
412 static int sceMp3GetBitRate(u32 mp3
) {
413 INFO_LOG(ME
, "sceMp3GetBitRate(%08X)", mp3
);
415 AuCtx
*ctx
= getMp3Ctx(mp3
);
417 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
421 return ctx
->AuGetBitRate();
424 static int sceMp3GetSamplingRate(u32 mp3
) {
425 INFO_LOG(ME
, "sceMp3GetSamplingRate(%08X)", mp3
);
427 AuCtx
*ctx
= getMp3Ctx(mp3
);
429 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
433 return ctx
->AuGetSamplingRate();
436 static int sceMp3GetInfoToAddStreamData(u32 mp3
, u32 dstPtr
, u32 towritePtr
, u32 srcposPtr
) {
437 DEBUG_LOG(ME
, "sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3
, dstPtr
, towritePtr
, srcposPtr
);
439 AuCtx
*ctx
= getMp3Ctx(mp3
);
441 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
445 return ctx
->AuGetInfoToAddStreamData(dstPtr
, towritePtr
, srcposPtr
);
448 static int sceMp3NotifyAddStreamData(u32 mp3
, int size
) {
449 DEBUG_LOG(ME
, "sceMp3NotifyAddStreamData(%08X, %i)", mp3
, size
);
451 AuCtx
*ctx
= getMp3Ctx(mp3
);
453 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
457 return ctx
->AuNotifyAddStreamData(size
);
460 static int sceMp3ReleaseMp3Handle(u32 mp3
) {
461 INFO_LOG(ME
, "sceMp3ReleaseMp3Handle(%08X)", mp3
);
463 AuCtx
*ctx
= getMp3Ctx(mp3
);
465 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
475 static u32
sceMp3EndEntry() {
476 ERROR_LOG_REPORT(ME
, "UNIMPL sceMp3EndEntry(...)");
480 static u32
sceMp3StartEntry() {
481 ERROR_LOG_REPORT(ME
, "UNIMPL sceMp3StartEntry(...)");
485 static u32
sceMp3GetFrameNum(u32 mp3
) {
486 INFO_LOG(ME
, "sceMp3GetFrameNum(%08x)", mp3
);
487 AuCtx
*ctx
= getMp3Ctx(mp3
);
489 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
492 return ctx
->AuGetFrameNum();
495 static u32
sceMp3GetMPEGVersion(u32 mp3
) {
496 INFO_LOG(ME
, "sceMp3GetMPEGVersion(%08x)", mp3
);
497 AuCtx
*ctx
= getMp3Ctx(mp3
);
499 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
503 return ctx
->AuGetVersion();
506 static u32
sceMp3ResetPlayPositionByFrame(u32 mp3
, int position
) {
507 DEBUG_LOG(ME
, "sceMp3ResetPlayPositionByFrame(%08x, %i)", mp3
, position
);
508 AuCtx
*ctx
= getMp3Ctx(mp3
);
510 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
514 return ctx
->AuResetPlayPositionByFrame(position
);
517 static u32
sceMp3LowLevelInit(u32 mp3
) {
518 INFO_LOG(ME
, "sceMp3LowLevelInit(%i)", mp3
);
519 auto ctx
= new AuCtx
;
521 ctx
->audioType
= PSP_CODEC_MP3
;
522 // create mp3 decoder
523 ctx
->decoder
= new SimpleAudio(ctx
->audioType
);
525 // close the audio if mp3 already exists.
526 if (mp3Map
.find(mp3
) != mp3Map
.end()) {
535 static u32
sceMp3LowLevelDecode(u32 mp3
, u32 sourceAddr
, u32 sourceBytesConsumedAddr
, u32 samplesAddr
, u32 sampleBytesAddr
) {
536 // sourceAddr: input mp3 stream buffer
537 // sourceBytesConsumedAddr: consumed bytes decoded in source
538 // samplesAddr: output pcm buffer
539 // sampleBytesAddr: output pcm size
540 DEBUG_LOG(ME
, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x)", mp3
, sourceAddr
, sourceBytesConsumedAddr
, samplesAddr
, sampleBytesAddr
);
542 AuCtx
*ctx
= getMp3Ctx(mp3
);
544 ERROR_LOG(ME
, "%s: bad mp3 handle %08x", __FUNCTION__
, mp3
);
548 if (!Memory::IsValidAddress(sourceAddr
) || !Memory::IsValidAddress(sourceBytesConsumedAddr
) ||
549 !Memory::IsValidAddress(samplesAddr
) || !Memory::IsValidAddress(sampleBytesAddr
)) {
550 ERROR_LOG(ME
, "sceMp3LowLevelDecode(%08x, %08x, %08x, %08x, %08x) : invalid address in args", mp3
, sourceAddr
, sourceBytesConsumedAddr
, samplesAddr
, sampleBytesAddr
);
554 auto inbuff
= Memory::GetPointer(sourceAddr
);
555 auto outbuff
= Memory::GetPointer(samplesAddr
);
558 ctx
->decoder
->Decode((void*)inbuff
, 4096, outbuff
, &outpcmbytes
);
560 Memory::Write_U32(ctx
->decoder
->GetSourcePos(), sourceBytesConsumedAddr
);
561 Memory::Write_U32(outpcmbytes
, sampleBytesAddr
);
565 const HLEFunction sceMp3
[] = {
566 {0X07EC321A, &WrapU_U
<sceMp3ReserveMp3Handle
>, "sceMp3ReserveMp3Handle", 'x', "x" },
567 {0X0DB149F4, &WrapI_UI
<sceMp3NotifyAddStreamData
>, "sceMp3NotifyAddStreamData", 'i', "xi" },
568 {0X2A368661, &WrapI_U
<sceMp3ResetPlayPosition
>, "sceMp3ResetPlayPosition", 'i', "x" },
569 {0X354D27EA, &WrapI_U
<sceMp3GetSumDecodedSample
>, "sceMp3GetSumDecodedSample", 'i', "x" },
570 {0X35750070, &WrapI_V
<sceMp3InitResource
>, "sceMp3InitResource", 'i', "" },
571 {0X3C2FA058, &WrapI_V
<sceMp3TermResource
>, "sceMp3TermResource", 'i', "" },
572 {0X3CEF484F, &WrapI_UI
<sceMp3SetLoopNum
>, "sceMp3SetLoopNum", 'i', "xi" },
573 {0X44E07129, &WrapI_U
<sceMp3Init
>, "sceMp3Init", 'i', "x" },
574 {0X732B042A, &WrapU_V
<sceMp3EndEntry
>, "sceMp3EndEntry", 'x', "" },
575 {0X7F696782, &WrapI_U
<sceMp3GetMp3ChannelNum
>, "sceMp3GetMp3ChannelNum", 'i', "x" },
576 {0X87677E40, &WrapI_U
<sceMp3GetBitRate
>, "sceMp3GetBitRate", 'i', "x" },
577 {0X87C263D1, &WrapI_U
<sceMp3GetMaxOutputSample
>, "sceMp3GetMaxOutputSample", 'i', "x" },
578 {0X8AB81558, &WrapU_V
<sceMp3StartEntry
>, "sceMp3StartEntry", 'x', "" },
579 {0X8F450998, &WrapI_U
<sceMp3GetSamplingRate
>, "sceMp3GetSamplingRate", 'i', "x" },
580 {0XA703FE0F, &WrapI_UUUU
<sceMp3GetInfoToAddStreamData
>, "sceMp3GetInfoToAddStreamData", 'i', "xxxx" },
581 {0XD021C0FB, &WrapI_UU
<sceMp3Decode
>, "sceMp3Decode", 'i', "xx" },
582 {0XD0A56296, &WrapI_U
<sceMp3CheckStreamDataNeeded
>, "sceMp3CheckStreamDataNeeded", 'i', "x" },
583 {0XD8F54A51, &WrapI_U
<sceMp3GetLoopNum
>, "sceMp3GetLoopNum", 'i', "x" },
584 {0XF5478233, &WrapI_U
<sceMp3ReleaseMp3Handle
>, "sceMp3ReleaseMp3Handle", 'i', "x" },
585 {0XAE6D2027, &WrapU_U
<sceMp3GetMPEGVersion
>, "sceMp3GetMPEGVersion", 'x', "x" },
586 {0X3548AEC8, &WrapU_U
<sceMp3GetFrameNum
>, "sceMp3GetFrameNum", 'x', "x" },
587 {0X0840E808, &WrapU_UI
<sceMp3ResetPlayPositionByFrame
>, "sceMp3ResetPlayPositionByFrame", 'x', "xi" },
588 {0X1B839B83, &WrapU_U
<sceMp3LowLevelInit
>, "sceMp3LowLevelInit", 'x', "x" },
589 {0XE3EE2C81, &WrapU_UUUUU
<sceMp3LowLevelDecode
>, "sceMp3LowLevelDecode", 'x', "xxxxx"}
592 void Register_sceMp3() {
593 RegisterModule("sceMp3", ARRAY_SIZE(sceMp3
), sceMp3
);