~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/HLE/sceMp3.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/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"
 
29
 
 
30
 
 
31
struct Mp3Context {
 
32
public:
 
33
 
 
34
        int mp3StreamStart;
 
35
        int mp3StreamEnd;
 
36
        u32 mp3Buf;
 
37
        int mp3BufSize;
 
38
        u32 mp3PcmBuf;
 
39
        int mp3PcmBufSize;
 
40
 
 
41
        int readPosition;
 
42
 
 
43
        int bufferRead;
 
44
        int bufferWrite;
 
45
        int bufferAvailable;
 
46
 
 
47
        int mp3DecodedBytes;
 
48
        int mp3LoopNum;
 
49
        int mp3MaxSamples;
 
50
        int mp3SumDecodedSamples;
 
51
 
 
52
        int mp3Channels;
 
53
        int mp3Bitrate;
 
54
        int mp3SamplingRate;
 
55
        int mp3Version;
 
56
 
 
57
        void DoState(PointerWrap &p) {
 
58
                auto s = p.Section("Mp3Context", 1);
 
59
                if (!s)
 
60
                        return;
 
61
 
 
62
                p.Do(mp3StreamStart);
 
63
                p.Do(mp3StreamEnd);
 
64
                p.Do(mp3Buf);
 
65
                p.Do(mp3BufSize);
 
66
                p.Do(mp3PcmBuf);
 
67
                p.Do(mp3PcmBufSize);
 
68
                p.Do(readPosition);
 
69
                p.Do(bufferRead);
 
70
                p.Do(bufferWrite);
 
71
                p.Do(bufferAvailable);
 
72
                p.Do(mp3DecodedBytes);
 
73
                p.Do(mp3LoopNum);
 
74
                p.Do(mp3MaxSamples);
 
75
                p.Do(mp3SumDecodedSamples);
 
76
                p.Do(mp3Channels);
 
77
                p.Do(mp3Bitrate);
 
78
                p.Do(mp3SamplingRate);
 
79
                p.Do(mp3Version);
 
80
        };
 
81
};
 
82
 
 
83
static std::map<u32, Mp3Context *> mp3Map_old;
 
84
static std::map<u32, AuCtx *> mp3Map;
 
85
static const int mp3DecodeDelay = 4000;
 
86
 
 
87
static AuCtx *getMp3Ctx(u32 mp3) {
 
88
        if (mp3Map.find(mp3) == mp3Map.end())
 
89
                return NULL;
 
90
        return mp3Map[mp3];
 
91
}
 
92
 
 
93
void __Mp3Shutdown() {
 
94
        for (auto it = mp3Map.begin(), end = mp3Map.end(); it != end; ++it) {
 
95
                delete it->second;
 
96
        }
 
97
        mp3Map.clear();
 
98
}
 
99
 
 
100
void __Mp3DoState(PointerWrap &p) {
 
101
        auto s = p.Section("sceMp3", 0, 2);
 
102
        if (!s)
 
103
                return;
 
104
 
 
105
        if (s >= 2){
 
106
                p.Do(mp3Map);
 
107
        }
 
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;
 
112
                        u32 id = it->first;
 
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;
 
132
 
 
133
                        mp3->audioType = PSP_CODEC_MP3;
 
134
                        mp3->decoder = new SimpleAudio(mp3->audioType);
 
135
                        mp3Map[id] = mp3;
 
136
                }
 
137
        }
 
138
}
 
139
 
 
140
static int sceMp3Decode(u32 mp3, u32 outPcmPtr) {
 
141
        DEBUG_LOG(ME, "sceMp3Decode(%08x,%08x)", mp3, outPcmPtr);
 
142
 
 
143
        AuCtx *ctx = getMp3Ctx(mp3);
 
144
        if (!ctx) {
 
145
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
146
                return -1;
 
147
        }
 
148
                
 
149
        int pcmBytes = ctx->AuDecode(outPcmPtr);
 
150
        if (!pcmBytes) {
 
151
                // decode data successfully, delay thread
 
152
                hleDelayResult(pcmBytes, "mp3 decode", mp3DecodeDelay);
 
153
        }
 
154
        return pcmBytes;
 
155
}
 
156
 
 
157
static int sceMp3ResetPlayPosition(u32 mp3) {
 
158
        DEBUG_LOG(ME, "SceMp3ResetPlayPosition(%08x)", mp3);
 
159
 
 
160
        AuCtx *ctx = getMp3Ctx(mp3);
 
161
        if (!ctx) {
 
162
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
163
                return -1;
 
164
        }
 
165
 
 
166
        return ctx->AuResetPlayPosition();
 
167
}
 
168
 
 
169
static int sceMp3CheckStreamDataNeeded(u32 mp3) {
 
170
        DEBUG_LOG(ME, "sceMp3CheckStreamDataNeeded(%08x)", mp3);
 
171
 
 
172
        AuCtx *ctx = getMp3Ctx(mp3);
 
173
        if (!ctx) {
 
174
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
175
                return -1;
 
176
        }
 
177
 
 
178
        return ctx->AuCheckStreamDataNeeded();
 
179
}
 
180
 
 
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);
 
185
                return -1;
 
186
        }
 
187
 
 
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.
 
195
 
 
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);
 
198
 
 
199
        Au->audioType = PSP_CODEC_MP3;
 
200
        Au->Channels = 2;
 
201
        Au->SumDecodedSamples = 0;
 
202
        Au->MaxOutputSample = Au->PCMBufSize / 4;
 
203
        Au->LoopNum = -1;
 
204
        Au->AuBufAvailable = 0;
 
205
        Au->readPos = Au->startPos;
 
206
 
 
207
        // create Au decoder
 
208
        Au->decoder = new SimpleAudio(Au->audioType);
 
209
 
 
210
        // close the audio if mp3Addr already exist.
 
211
        if (mp3Map.find(mp3Addr) != mp3Map.end()) {
 
212
                delete mp3Map[mp3Addr];
 
213
                mp3Map.erase(mp3Addr);
 
214
        }
 
215
 
 
216
        mp3Map[mp3Addr] = Au;
 
217
 
 
218
        return mp3Addr;
 
219
}
 
220
 
 
221
static int sceMp3InitResource() {
 
222
        WARN_LOG(ME, "UNIMPL: sceMp3InitResource");
 
223
        // Do nothing here 
 
224
        return 0;
 
225
}
 
226
 
 
227
static int sceMp3TermResource() {
 
228
        WARN_LOG(ME, "UNIMPL: sceMp3TermResource");
 
229
        // Do nothing here 
 
230
        return 0;
 
231
}
 
232
 
 
233
static int __CalculateMp3Channels(int bitval) {
 
234
        if (bitval == 0 || bitval == 1 || bitval == 2) { // Stereo / Joint Stereo / Dual Channel.
 
235
                return 2;
 
236
        }
 
237
        else if (bitval == 3) { // Mono.
 
238
                return 1;
 
239
        }
 
240
        else {
 
241
                return -1;
 
242
        }
 
243
}
 
244
 
 
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];
 
249
        }
 
250
        else if (mp3version == 2) { // MPEG Version 2
 
251
                int valuemapping[] = { 22050, 24000, 16000, -1 };
 
252
                return valuemapping[bitval];
 
253
        }
 
254
        else if (mp3version == 0) { // MPEG Version 2.5
 
255
                int valuemapping[] = { 11025, 12000, 8000, -1 };
 
256
                return valuemapping[bitval];
 
257
        }
 
258
        else {
 
259
                return -1;
 
260
        }
 
261
}
 
262
 
 
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];
 
268
                }
 
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];
 
272
                }
 
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];
 
276
                }
 
277
                else {
 
278
                        return -1;
 
279
                }
 
280
        }
 
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];
 
285
                }
 
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];
 
289
                }
 
290
                else {
 
291
                        return -1;
 
292
                }
 
293
        }
 
294
        else {
 
295
                return -1;
 
296
        }
 
297
}
 
298
 
 
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) {
 
304
                *isID3 = true;
 
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));
 
309
        }
 
310
        return header;
 
311
}
 
312
 
 
313
static int sceMp3Init(u32 mp3) {
 
314
        INFO_LOG(ME, "sceMp3Init(%08x)", mp3);
 
315
 
 
316
        AuCtx *ctx = getMp3Ctx(mp3);
 
317
        if (!ctx) {
 
318
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
319
                return -1;
 
320
        }
 
321
 
 
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;
 
331
 
 
332
        INFO_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps", ctx->Channels, ctx->SamplingRate, ctx->BitRate);
 
333
 
 
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);
 
337
        }
 
338
 
 
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.
 
341
        if (hasID3Tag) {
 
342
                // if get ID3 tage, we will decode from 0x400
 
343
                ctx->startPos = 0x400;
 
344
                ctx->EatSourceBuff(0x400);
 
345
        } else {
 
346
                // if no ID3 tag, we will decode from the begining of the file
 
347
                ctx->startPos = 0;
 
348
        }
 
349
 
 
350
        return 0;
 
351
}
 
352
 
 
353
static int sceMp3GetLoopNum(u32 mp3) {
 
354
        DEBUG_LOG(ME, "sceMp3GetLoopNum(%08x)", mp3);
 
355
 
 
356
        AuCtx *ctx = getMp3Ctx(mp3);
 
357
        if (!ctx) {
 
358
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
359
                return -1;
 
360
        }
 
361
 
 
362
        return ctx->AuGetLoopNum();
 
363
}
 
364
 
 
365
static int sceMp3GetMaxOutputSample(u32 mp3) {
 
366
        DEBUG_LOG(ME, "sceMp3GetMaxOutputSample(%08x)", mp3);
 
367
        AuCtx *ctx = getMp3Ctx(mp3);
 
368
        if (!ctx) {
 
369
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
370
                return -1;
 
371
        }
 
372
 
 
373
        return ctx->AuGetMaxOutputSample();
 
374
}
 
375
 
 
376
static int sceMp3GetSumDecodedSample(u32 mp3) {
 
377
        INFO_LOG(ME, "sceMp3GetSumDecodedSample(%08X)", mp3);
 
378
 
 
379
        AuCtx *ctx = getMp3Ctx(mp3);
 
380
        if (!ctx) {
 
381
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
382
                return -1;
 
383
        }
 
384
 
 
385
        return ctx->AuGetSumDecodedSample();
 
386
}
 
387
 
 
388
static int sceMp3SetLoopNum(u32 mp3, int loop) {
 
389
        INFO_LOG(ME, "sceMp3SetLoopNum(%08X, %i)", mp3, loop);
 
390
 
 
391
        AuCtx *ctx = getMp3Ctx(mp3);
 
392
        if (!ctx) {
 
393
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
394
                return -1;
 
395
        }
 
396
 
 
397
        return ctx->AuSetLoopNum(loop);
 
398
}
 
399
 
 
400
static int sceMp3GetMp3ChannelNum(u32 mp3) {
 
401
        INFO_LOG(ME, "sceMp3GetMp3ChannelNum(%08X)", mp3);
 
402
 
 
403
        AuCtx *ctx = getMp3Ctx(mp3);
 
404
        if (!ctx) {
 
405
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
406
                return -1;
 
407
        }
 
408
 
 
409
        return ctx->AuGetChannelNum();
 
410
}
 
411
 
 
412
static int sceMp3GetBitRate(u32 mp3) {
 
413
        INFO_LOG(ME, "sceMp3GetBitRate(%08X)", mp3);
 
414
 
 
415
        AuCtx *ctx = getMp3Ctx(mp3);
 
416
        if (!ctx) {
 
417
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
418
                return -1;
 
419
        }
 
420
 
 
421
        return ctx->AuGetBitRate();
 
422
}
 
423
 
 
424
static int sceMp3GetSamplingRate(u32 mp3) {
 
425
        INFO_LOG(ME, "sceMp3GetSamplingRate(%08X)", mp3);
 
426
 
 
427
        AuCtx *ctx = getMp3Ctx(mp3);
 
428
        if (!ctx) {
 
429
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
430
                return -1;
 
431
        }
 
432
 
 
433
        return ctx->AuGetSamplingRate();
 
434
}
 
435
 
 
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);
 
438
 
 
439
        AuCtx *ctx = getMp3Ctx(mp3);
 
440
        if (!ctx) {
 
441
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
442
                return -1;
 
443
        }
 
444
 
 
445
        return ctx->AuGetInfoToAddStreamData(dstPtr, towritePtr, srcposPtr);
 
446
}
 
447
 
 
448
static int sceMp3NotifyAddStreamData(u32 mp3, int size) {
 
449
        DEBUG_LOG(ME, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size);
 
450
 
 
451
        AuCtx *ctx = getMp3Ctx(mp3);
 
452
        if (!ctx) {
 
453
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
454
                return -1;
 
455
        }
 
456
 
 
457
        return ctx->AuNotifyAddStreamData(size);
 
458
}
 
459
 
 
460
static int sceMp3ReleaseMp3Handle(u32 mp3) {
 
461
        INFO_LOG(ME, "sceMp3ReleaseMp3Handle(%08X)", mp3);
 
462
 
 
463
        AuCtx *ctx = getMp3Ctx(mp3);
 
464
        if (!ctx) {
 
465
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
466
                return -1;
 
467
        }
 
468
 
 
469
        delete ctx;
 
470
        mp3Map.erase(mp3);
 
471
 
 
472
        return 0;
 
473
}
 
474
 
 
475
static u32 sceMp3EndEntry() {
 
476
        ERROR_LOG_REPORT(ME, "UNIMPL sceMp3EndEntry(...)");
 
477
        return 0;
 
478
}
 
479
 
 
480
static u32 sceMp3StartEntry() {
 
481
        ERROR_LOG_REPORT(ME, "UNIMPL sceMp3StartEntry(...)");
 
482
        return 0;
 
483
}
 
484
 
 
485
static u32 sceMp3GetFrameNum(u32 mp3) {
 
486
        INFO_LOG(ME, "sceMp3GetFrameNum(%08x)", mp3);
 
487
        AuCtx *ctx = getMp3Ctx(mp3);
 
488
        if (!ctx) {
 
489
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
490
                return -1;
 
491
        }
 
492
        return ctx->AuGetFrameNum();
 
493
}
 
494
 
 
495
static u32 sceMp3GetMPEGVersion(u32 mp3) {
 
496
        INFO_LOG(ME, "sceMp3GetMPEGVersion(%08x)", mp3);
 
497
        AuCtx *ctx = getMp3Ctx(mp3);
 
498
        if (!ctx) {
 
499
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
500
                return -1;
 
501
        }
 
502
 
 
503
        return ctx->AuGetVersion();
 
504
}
 
505
 
 
506
static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, int position) {
 
507
        DEBUG_LOG(ME, "sceMp3ResetPlayPositionByFrame(%08x, %i)", mp3, position);
 
508
        AuCtx *ctx = getMp3Ctx(mp3);
 
509
        if (!ctx) {
 
510
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
511
                return -1;
 
512
        }
 
513
 
 
514
        return ctx->AuResetPlayPositionByFrame(position);
 
515
}
 
516
 
 
517
static u32 sceMp3LowLevelInit(u32 mp3) {
 
518
        INFO_LOG(ME, "sceMp3LowLevelInit(%i)", mp3);
 
519
        auto ctx = new AuCtx;
 
520
 
 
521
        ctx->audioType = PSP_CODEC_MP3;
 
522
        // create mp3 decoder
 
523
        ctx->decoder = new SimpleAudio(ctx->audioType);
 
524
 
 
525
        // close the audio if mp3 already exists.
 
526
        if (mp3Map.find(mp3) != mp3Map.end()) {
 
527
                delete mp3Map[mp3];
 
528
                mp3Map.erase(mp3);
 
529
        }
 
530
 
 
531
        mp3Map[mp3] = ctx;
 
532
        return 0;
 
533
}
 
534
 
 
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);
 
541
 
 
542
        AuCtx *ctx = getMp3Ctx(mp3);
 
543
        if (!ctx) {
 
544
                ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
 
545
                return -1;
 
546
        }
 
547
 
 
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);
 
551
                return -1;
 
552
        }
 
553
 
 
554
        auto inbuff = Memory::GetPointer(sourceAddr);
 
555
        auto outbuff = Memory::GetPointer(samplesAddr);
 
556
        
 
557
        int outpcmbytes = 0;
 
558
        ctx->decoder->Decode((void*)inbuff, 4096, outbuff, &outpcmbytes);
 
559
        
 
560
        Memory::Write_U32(ctx->decoder->GetSourcePos(), sourceBytesConsumedAddr);
 
561
        Memory::Write_U32(outpcmbytes, sampleBytesAddr);
 
562
        return 0;
 
563
}
 
564
 
 
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"}
 
590
};
 
591
 
 
592
void Register_sceMp3() {
 
593
        RegisterModule("sceMp3", ARRAY_SIZE(sceMp3), sceMp3);
 
594
}