Fix nonsmooth sound issue and incomplete frame at the end of source and pcm buffers.

using a std::string to save the source buffer, and changing the loading strategy so as we will not get any incomplete frame.
This commit is contained in:
kaienfr 2014-04-12 23:16:38 +02:00
parent d5c1d58506
commit e25bc6908a
5 changed files with 42 additions and 52 deletions

View File

@ -90,4 +90,3 @@ extern AudioChannel chans[PSP_AUDIO_CHANNEL_MAX + 1];
void Register_sceAudio();
u32 sceAudioSetFrequency(u32 freq);

View File

@ -127,7 +127,8 @@ void __Mp3DoState(PointerWrap &p) {
mp3->MaxOutputSample = mp3_old->mp3MaxSamples;
mp3->readPos = mp3_old->readPosition;
mp3->AuBufAvailable = 0; // reset to read from file
mp3->writePos = 0; // reset to read from buffer
mp3->askedReadSize = 0;
mp3->realReadSize = 0;
mp3->audioType = PSP_CODEC_MP3;
mp3->decoder = new SimpleAudio(mp3->audioType);
@ -331,18 +332,17 @@ int sceMp3Init(u32 mp3) {
ctx->decoder->setResampleFrequency(ctx->freq);
}
// For mp3 file, if ID3 tag is detected, we must move startPos and writePos to 0x400 (stream start position), and reduce the available buffer size by 0x400
// 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
// this is very important for ID3 tag mp3, since our universal audio decoder is for decoding stream part only.
if (isID3){
// if get ID3 tage, we will decode from 0x400
ctx->startPos = 0x400;
ctx->writePos = 0x400;
ctx->sourcebuff.erase(0, 0x400);
ctx->AuBufAvailable -= 0x400;
}
else{
// if no ID3 tag, we will decode from the begining of the file
ctx->startPos = 0;
ctx->writePos = 0;
}
return 0;
@ -350,6 +350,8 @@ int sceMp3Init(u32 mp3) {
int sceMp3GetLoopNum(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetLoopNum(%08x)", mp3);
INFO_LOG(ME, "sceMp3GetLoopNum(%08x)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
@ -372,7 +374,7 @@ int sceMp3GetMaxOutputSample(u32 mp3)
}
int sceMp3GetSumDecodedSample(u32 mp3) {
DEBUG_LOG_REPORT(ME, "sceMp3GetSumDecodedSample(%08X)", mp3);
INFO_LOG_REPORT(ME, "sceMp3GetSumDecodedSample(%08X)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -395,7 +397,7 @@ int sceMp3SetLoopNum(u32 mp3, int loop) {
return ctx->AuSetLoopNum(loop);
}
int sceMp3GetMp3ChannelNum(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetMp3ChannelNum(%08X)", mp3);
INFO_LOG(ME, "sceMp3GetMp3ChannelNum(%08X)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -406,7 +408,7 @@ int sceMp3GetMp3ChannelNum(u32 mp3) {
return ctx->AuGetChannelNum();
}
int sceMp3GetBitRate(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetBitRate(%08X)", mp3);
INFO_LOG(ME, "sceMp3GetBitRate(%08X)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -417,7 +419,7 @@ int sceMp3GetBitRate(u32 mp3) {
return ctx->AuGetBitRate();
}
int sceMp3GetSamplingRate(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetSamplingRate(%08X)", mp3);
INFO_LOG(ME, "sceMp3GetSamplingRate(%08X)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -429,7 +431,7 @@ int sceMp3GetSamplingRate(u32 mp3) {
}
int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) {
DEBUG_LOG(ME, "sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3, dstPtr, towritePtr, srcposPtr);
INFO_LOG(ME, "sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3, dstPtr, towritePtr, srcposPtr);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -441,7 +443,7 @@ int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcpos
}
int sceMp3NotifyAddStreamData(u32 mp3, int size) {
DEBUG_LOG(ME, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size);
INFO_LOG(ME, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
@ -453,7 +455,7 @@ int sceMp3NotifyAddStreamData(u32 mp3, int size) {
}
int sceMp3ReleaseMp3Handle(u32 mp3) {
DEBUG_LOG(ME, "sceMp3ReleaseMp3Handle(%08X)", mp3);
INFO_LOG(ME, "sceMp3ReleaseMp3Handle(%08X)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {

View File

@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include "Core/Config.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HW/SimpleAudioDec.h"
@ -302,57 +303,40 @@ u32 AuCtx::AuDecode(u32 pcmAddr)
return -1;
}
auto inbuff = Memory::GetPointer(AuBuf);
auto outbuf = Memory::GetPointer(PCMBuf);
u32 outpcmbufsize = 0;
// move inbuff to writePos of buffer
inbuff += writePos;
// decode frames in AuBuf and output into PCMBuf if it is not exceed
while (AuBufAvailable > 0 && outpcmbufsize < PCMBufSize){
int repeat = 1;
if (g_Config.bSoundSpeedHack){
repeat = 2;
}
int i = 0;
// decode frames in sourcebuff and output into PCMBuf (each time, we decode one or two frames)
// some games as Miku like one frame each time, some games like DOA like two frames each time
while (sourcebuff.size() > 0 && outpcmbufsize < PCMBufSize && i < repeat){
i++;
int pcmframesize;
// decode
decoder->Decode(inbuff, AuBufAvailable, outbuf, &pcmframesize);
decoder->Decode((void*)sourcebuff.c_str(), (int)sourcebuff.size(), outbuf, &pcmframesize);
if (pcmframesize == 0){
// no output pcm, we have either no data or no enough data to decode
// move back audio source readPos to the begin of the last incomplete frame if we not start looping and reset available AuBuf
if (readPos > startPos) { // this means we are not begin to loop yet
readPos -= AuBufAvailable;
}
AuBufAvailable = 0;
// no output pcm, we are at the end of the stream
break;
}
// count total output pcm size
outpcmbufsize += pcmframesize;
// count total output samples
SumDecodedSamples += decoder->getOutSamples();
// move inbuff position to next frame
// get consumed source length
int srcPos = decoder->getSourcePos();
inbuff += srcPos;
// decrease available AuBuf
// remove the consumed source
sourcebuff.erase(0, srcPos);
// reduce the available Aubuff size
AuBufAvailable -= srcPos;
// modify the writePos value
writePos += srcPos;
// move outbuff position to the current end of output
outbuf += pcmframesize;
// audio hack, default we will not do while and break here
if (!g_Config.bSoundSpeedHack){
break;
}
}
Memory::Write_U32(PCMBuf, pcmAddr);
// if we got zero pcm, and we still haven't reach endPos.
// some game like "Miku" will stop playing if we return 0, but some others will recharge buffer.
// so we did a hack here, clear output buff and just return a nonzero value to continue
if (outpcmbufsize == 0 && readPos < endPos){
// clear output buffer will avoid noise
memset(outbuf, 0, PCMBufSize);
return FF_INPUT_BUFFER_PADDING_SIZE; // return a padding size seems very good and almost unsensible latency.
}
return outpcmbufsize;
}
@ -371,7 +355,7 @@ u32 AuCtx::AuSetLoopNum(int loop)
int AuCtx::AuCheckStreamDataNeeded()
{
// if we have no available Au buffer, and the current read position in source file is not the end of stream, then we can read
if (AuBufAvailable == 0 && readPos < endPos){
if (AuBufAvailable < AuBufSize && readPos < endPos){
return 1;
}
return 0;
@ -387,6 +371,9 @@ u32 AuCtx::AuNotifyAddStreamData(int size)
AuBufAvailable += diffszie;
}
// append AuBuf into sourcebuff
sourcebuff.append((const char*)Memory::GetPointer(AuBuf), size);
if (readPos >= endPos && LoopNum != 0){
// if we need loop, reset readPos
readPos = startPos;
@ -403,18 +390,19 @@ u32 AuCtx::AuNotifyAddStreamData(int size)
// buff, size and srcPos are all pointers
u32 AuCtx::AuGetInfoToAddStreamData(u32 buff, u32 size, u32 srcPos)
{
int readsize = std::min((int)AuBufSize - AuBufAvailable, (int)endPos - readPos);
// we can recharge AuBuf from its begining
if (Memory::IsValidAddress(buff))
Memory::Write_U32(AuBuf, buff);
if (Memory::IsValidAddress(size))
Memory::Write_U32(AuBufSize, size);
Memory::Write_U32(readsize, size);
if (Memory::IsValidAddress(srcPos))
Memory::Write_U32(readPos, srcPos);
askedReadSize = AuBufSize;
askedReadSize = readsize;
readPos += askedReadSize;
AuBufAvailable += askedReadSize;
writePos = 0;
return 0;
}

View File

@ -128,9 +128,9 @@ public:
// buffers informations
int AuBufAvailable; // the available buffer of AuBuf to be able to recharge data
int readPos; // read position in audio source file
int writePos; // write position in AuBuf, i.e. the size of bytes decoded in AuBuf.
int askedReadSize; // the size of data requied to be read from file by the game
int realReadSize; // the really read size from file
std::string sourcebuff; // source buffer
AuCtx() :decoder(NULL){};
~AuCtx(){
@ -172,15 +172,16 @@ public:
p.Do(LoopNum);
p.Do(Channels);
p.Do(MaxOutputSample);
p.Do(AuBufAvailable);
p.Do(readPos);
p.Do(writePos);
p.Do(audioType);
p.Do(BitRate);
p.Do(SamplingRate);
p.Do(askedReadSize);
p.Do(realReadSize);
if (p.mode == p.MODE_READ){
decoder = new SimpleAudio(audioType);
AuBufAvailable = 0; // reset to read from file at position readPos
}
};
};

View File

@ -249,7 +249,7 @@ void GameSettingsScreen::CreateViews() {
lowAudio->SetEnabledPtr(&g_Config.bEnableSound);
audioSettings->Add(new ItemHeader(ms->T("Audio hacks")));
audioSettings->Add(new CheckBox(&g_Config.bSoundSpeedHack, a->T("Sound speed hack (fill pcm buffer)")));
audioSettings->Add(new CheckBox(&g_Config.bSoundSpeedHack, a->T("Sound speed hack (DOA etc.)")));
// Control
ViewGroup *controlsSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));