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);