Remove audio rate throttling, it's better to frame rate throttle. Gets rid of the slowdown that audio caused.

This commit is contained in:
Henrik Rydgard 2012-11-23 10:33:19 +01:00
parent a385ec6056
commit f3aeadedfa
4 changed files with 70 additions and 47 deletions

View File

@ -46,10 +46,9 @@ const int audioIntervalUs = (int)(1000000ULL * hwBlockSize / hwSampleRate);
const int audioHostIntervalUs = (int)(1000000ULL * hostAttemptBlockSize / hwSampleRate);
// High and low watermarks, basically.
const int chanQueueMaxSizeFactor = 4;
const int chanQueueMinSizeFactor = 2;
const int chanQueueMaxSizeFactor = 2;
const int chanQueueMinSizeFactor = 1;
// A whole second, should be enough for anything.
FixedSizeQueue<s16, hwBlockSize * 8> outAudioQueue;
@ -131,25 +130,9 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking)
// just sleep the main emulator thread a little.
void __AudioUpdate()
{
#ifdef _WIN32
// HACK - TODO: Remove
bool noThrottle = GetAsyncKeyState(VK_TAB) != 0;
#else
bool noThrottle = false;
#endif
// Sleep here until the host audio hardware is ready to receive samples.
// This will effectively throttle the frame rate.
if (!noThrottle && g_Config.bEnableSound) {
while (true)
{
if (outAudioQueue.size() < hwBlockSize * 4)
break; // room can only increase without us pushing, so there's no race condition between here and section.lock()
Common::SleepCurrentThread(0);
}
}
section.lock();
// Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied
// to the CPU. Much better to throttle the frame rate on frame display and just throw away audio
// if the buffer somehow gets full.
s32 mixBuffer[hwBlockSize * 2];
memset(mixBuffer, 0, sizeof(mixBuffer));
@ -193,7 +176,9 @@ void __AudioUpdate()
}
}
if (!noThrottle && g_Config.bEnableSound) {
section.lock();
if (g_Config.bEnableSound && outAudioQueue.room() >= hwBlockSize * 2) {
// Push the mixed samples onto the output audio queue.
for (int i = 0; i < hwBlockSize; i++) {
s32 sampleL = mixBuffer[i * 2] >> 2; // TODO - what factor?
@ -233,7 +218,7 @@ int __AudioMix(short *outstereo, int numFrames)
outstereo[i * 2 + 1] = sampleR;
anythingToPlay = true;
} else {
underrun = i;
if (underrun == -1) underrun = i;
outstereo[i * 2] = sampleL; // repeat last sample, can reduce clicking
outstereo[i * 2 + 1] = sampleR; // repeat last sample, can reduce clicking
}

View File

@ -307,14 +307,17 @@ void sceAudioOutput2OutputBlocking()
chans[0].leftVolume = vol;
chans[0].rightVolume = vol;
chans[0].sampleAddress = dataPtr;
RETURN(chans[0].sampleCount);
__AudioEnqueue(chans[0], 0, true);
RETURN(0);
u32 retval = __AudioEnqueue(chans[0], 0, true);
if (retval < 0)
RETURN(retval);
}
void sceAudioOutput2ChangeLength()
u32 sceAudioOutput2ChangeLength(u32 sampleCount)
{
ERROR_LOG(HLE,"UNIMPL sceAudioOutput2ChangeLength");
RETURN(0);
WARN_LOG(HLE,"sceAudioOutput2ChangeLength(%i)");
chans[0].sampleCount = sampleCount;
return 0;
}
u32 sceAudioOutput2GetRestSample()
@ -343,20 +346,22 @@ u32 sceAudioSetFrequency(u32 freq) {
const HLEFunction sceAudio[] =
{
{0x01562ba3, sceAudioOutput2Reserve, "sceAudioOutput2Reserve"}, // N+, Super Stardust Portable uses these
// Newer simplified single channel audio output. Presumably for games that use Atrac3
// directly from Sas instead of playing it on a separate audio channel.
{0x01562ba3, sceAudioOutput2Reserve, "sceAudioOutput2Reserve"},
{0x2d53f36e, sceAudioOutput2OutputBlocking, "sceAudioOutput2OutputBlocking"},
{0x63f2889c, sceAudioOutput2ChangeLength, "sceAudioOutput2ChangeLength"},
{0x63f2889c, WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength"},
{0x647cef33, WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample"},
{0x43196845, sceAudioOutput2Release, "sceAudioOutput2Release"},
{0x38553111, 0, "sceAudioSRCChReserve"},
{0x5C37C0AE, 0, "sceAudioSRCChRelease"},
{0x80F1F7E0, sceAudioInit, "sceAudioInit"},
{0x80F1F7E0, sceAudioInit, "sceAudioInit"},
{0x210567F7, sceAudioEnd, "sceAudioEnd"},
{0x927AC32B, 0, "sceAudioSetVolumeOffset"},
{0xA2BEAA6C, WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency"},
{0xE0727056, 0, "sceAudioSRCOutputBlocking"},
{0x8c1009b2, WrapU_UUU<sceAudioOutput>, "sceAudioOutput"},
{0x927AC32B, 0, "sceAudioSetVolumeOffset"},
// The oldest and standard audio interface. Supports 8 channels, most games use 1-2.
{0x8c1009b2, WrapU_UUU<sceAudioOutput>, "sceAudioOutput"},
{0x136CAF51, WrapV_UUU<sceAudioOutputBlocking>, "sceAudioOutputBlocking"},
{0xE2D56B2D, WrapU_UUUU<sceAudioOutputPanned>, "sceAudioOutputPanned"},
{0x13F592BC, WrapV_UUUU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking
@ -367,8 +372,17 @@ const HLEFunction sceAudio[] =
{0xCB2E439E, WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen"}, //(u32, u32)
{0x95FD0C2D, WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig"},
{0xB7E1D8E7, WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume"},
// I guess these are like the others but do sample rate conversion?
{0x38553111, 0, "sceAudioSRCChReserve"},
{0x5C37C0AE, 0, "sceAudioSRCChRelease"},
{0xE0727056, 0, "sceAudioSRCOutputBlocking"},
// Never seen these used
{0x41efade7, 0, "sceAudioOneshotOutput"},
{0xB61595C0, 0, "sceAudioLoopbackTest"},
// Microphone interface
{0x7de61688, 0, "sceAudioInputInit"},
{0xE926D3FB, 0, "sceAudioInputInitEx"},
{0x6d4bec68, 0, "sceAudioInput"},

View File

@ -17,8 +17,12 @@
#include <vector>
//#include "base/timeutil.h"
// TODO: Move the relevant parts into common. Don't want the core
// to be dependent on "native", I think. Or maybe should get rid of common
// and move everything into native...
#include "base/timeutil.h"
#include "Thread.h"
#include "../Core/CoreTiming.h"
#include "../MIPS/MIPS.h"
#include "../HLE/HLE.h"
@ -63,6 +67,7 @@ static int hCountTotal = 0; //unused
static int vCount = 0;
static int isVblank = 0;
static bool hasSetMode = false;
double lastFrameTime = 0;
// STATE END
@ -165,15 +170,29 @@ void hleEnterVblank(u64 userdata, int cyclesLate)
// anything to draw here.
gpu->CopyDisplayToOutput();
{
host->EndFrame();
host->EndFrame();
host->BeginFrame();
gpu->BeginFrame();
shaderManager.DirtyShader();
shaderManager.DirtyUniform(DIRTY_ALL);
#ifdef _WIN32
static double lastFrameTime = 0.0;
// Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it.
time_update();
if (lastFrameTime == 0.0)
lastFrameTime = time_now_d();
if (!GetAsyncKeyState(VK_TAB)) {
while (time_now_d() < lastFrameTime + 1.0 / 60.0f) {
Common::SleepCurrentThread(1);
time_update();
}
lastFrameTime = time_now_d();
}
#endif
host->BeginFrame();
gpu->BeginFrame();
shaderManager.DirtyShader();
shaderManager.DirtyUniform(DIRTY_ALL);
// Tell the emu core that it's time to stop emulating
// Win32 doesn't need this.

View File

@ -47,7 +47,12 @@ u32 sceWlanGetEtherAddr(u32 addrAddr)
u32 sceWlanDevIsPowerOn()
{
DEBUG_LOG(HLE, "0=sceWlanDevIsPowerOn()");
DEBUG_LOG(HLE, "UNTESTED 0=sceWlanDevIsPowerOn()");
return 0;
}
u32 sceWlanGetSwitchState() {
DEBUG_LOG(HLE, "UNTESTED sceWlanGetSwitchState()");
return 0;
}
@ -179,7 +184,7 @@ const HLEFunction sceNetApctl[] =
const HLEFunction sceWlanDrv[] =
{
{0xd7763699, 0, "sceWlanGetSwitchState"},
{0xd7763699, WrapU_V<sceWlanGetSwitchState>, "sceWlanGetSwitchState"},
{0x0c622081, WrapU_U<sceWlanGetEtherAddr>, "sceWlanGetEtherAddr"},
{0x93440B11, WrapU_V<sceWlanDevIsPowerOn>, "sceWlanDevIsPowerOn"},
};