mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2025-02-11 11:25:16 +00:00
Adjust estimated frame time each frame.
Use half frame time if audio buffer is close to underrun. Provide combined audioengine write and status get, to avoid doing potentially expensive operations twice. Utilized in OSS and ALSA engines. Saner vsync estimate variance protection. git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@174 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
efd990ffff
commit
3a39b8fce2
@ -49,6 +49,13 @@ public:
|
||||
virtual QWidget* settingsWidget() { return NULL; }
|
||||
virtual void acceptSettings() {}
|
||||
virtual void rejectSettings() {}
|
||||
|
||||
virtual int write(void *buffer, unsigned samples, BufferState &preBufState_out, RateEst::Result &rate_out) {
|
||||
preBufState_out = bufferState();
|
||||
const int ret = write(buffer, samples);
|
||||
rate_out = rateEstimate();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -133,9 +133,8 @@ void AlsaEngine::uninit() {
|
||||
pcm_handle = NULL;
|
||||
}
|
||||
|
||||
int AlsaEngine::write(void *const buffer, const unsigned samples) {
|
||||
int AlsaEngine::write(void *const buffer, const unsigned samples, const BufferState &bstate) {
|
||||
bool underrun = false;
|
||||
const BufferState &bstate = bufferState();
|
||||
|
||||
if (prevfur > bstate.fromUnderrun && bstate.fromUnderrun != BufferState::NOT_SUPPORTED) {
|
||||
est.feed(prevfur - bstate.fromUnderrun);
|
||||
@ -155,6 +154,16 @@ int AlsaEngine::write(void *const buffer, const unsigned samples) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlsaEngine::write(void *const buffer, const unsigned samples) {
|
||||
return write(buffer, samples, bufferState());
|
||||
}
|
||||
|
||||
int AlsaEngine::write(void *const buffer, const unsigned samples, BufferState &preBufState, RateEst::Result &rate) {
|
||||
const int ret = write(buffer, samples, preBufState = bufferState());
|
||||
rate = est.result();
|
||||
return ret;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState AlsaEngine::bufferState() const {
|
||||
BufferState s;
|
||||
snd_pcm_sframes_t avail;
|
||||
|
@ -31,12 +31,14 @@ class AlsaEngine : public AudioEngine {
|
||||
unsigned prevfur;
|
||||
|
||||
int doInit(int rate, unsigned latency);
|
||||
int write(void *buffer, unsigned samples, const BufferState &bstate);
|
||||
|
||||
public:
|
||||
AlsaEngine();
|
||||
~AlsaEngine();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned samples);
|
||||
int write(void *buffer, unsigned samples, BufferState &preBufState_out, RateEst::Result &rate_out);
|
||||
const RateEst::Result rateEstimate() const { return est.result(); }
|
||||
const BufferState bufferState() const;
|
||||
void pause() { prevfur = 0; est.init(est.result().est); }
|
||||
|
@ -117,9 +117,7 @@ void OssEngine::uninit() {
|
||||
audio_fd = -1;
|
||||
}
|
||||
|
||||
int OssEngine::write(void *const buffer, const unsigned samples) {
|
||||
const BufferState &bstate = bufferState();
|
||||
|
||||
int OssEngine::write(void *const buffer, const unsigned samples, const BufferState &bstate) {
|
||||
if (prevfur > bstate.fromUnderrun && bstate.fromUnderrun != BufferState::NOT_SUPPORTED) {
|
||||
if (bstate.fromUnderrun)
|
||||
est.feed(prevfur - bstate.fromUnderrun);
|
||||
@ -135,6 +133,16 @@ int OssEngine::write(void *const buffer, const unsigned samples) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OssEngine::write(void *const buffer, const unsigned samples) {
|
||||
return write(buffer, samples, bufferState());
|
||||
}
|
||||
|
||||
int OssEngine::write(void *const buffer, const unsigned samples, BufferState &preBufState, RateEst::Result &rate) {
|
||||
const int ret = write(buffer, samples, preBufState = bufferState());
|
||||
rate = est.result();
|
||||
return ret;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState OssEngine::bufferState() const {
|
||||
BufferState s;
|
||||
audio_buf_info info;
|
||||
|
@ -30,12 +30,14 @@ class OssEngine : public AudioEngine {
|
||||
unsigned prevfur;
|
||||
|
||||
int doInit(int rate, unsigned latency);
|
||||
int write(void *buffer, unsigned samples, const BufferState &bstate);
|
||||
|
||||
public:
|
||||
OssEngine();
|
||||
~OssEngine();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned samples);
|
||||
int write(void *buffer, unsigned samples, BufferState &preBufState_out, RateEst::Result &rate_out);
|
||||
const RateEst::Result rateEstimate() const { return est.result(); }
|
||||
const BufferState bufferState() const;
|
||||
void pause() { prevfur = 0; est.init(est.result().est); }
|
||||
|
@ -18,14 +18,13 @@
|
||||
***************************************************************************/
|
||||
#include "mainwindow.h"
|
||||
|
||||
// #include <iostream>
|
||||
|
||||
#include <QtGui>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <QtGui>
|
||||
#include <QApplication>
|
||||
#include <QTimer>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <resample/resamplerinfo.h>
|
||||
|
||||
@ -143,7 +142,6 @@ MainWindow::MainWindow(MediaSource *source,
|
||||
ftDenom(60),
|
||||
paused(0),
|
||||
timerId(0),
|
||||
estSrate(0),
|
||||
running(false),
|
||||
turbo(false),
|
||||
pauseOnDialogExec(true),
|
||||
@ -477,16 +475,13 @@ static long maxSamplesPerFrame(const MediaSource *const source) {
|
||||
return (source->samplesPerFrame.num - 1) / source->samplesPerFrame.denom + 1;
|
||||
}
|
||||
|
||||
static void resetSndOutBuf(Array<qint16> &sndOutBuf, const Resampler *const resampler, const long maxspf) {
|
||||
const std::size_t sz = resampler->maxOut(maxspf) * 2;
|
||||
|
||||
if (sz != sndOutBuf.size())
|
||||
sndOutBuf.reset(sz);
|
||||
}
|
||||
|
||||
static void adjustResamplerRate(Array<qint16> &sndOutBuf, Resampler *const resampler, const long maxspf, const long outRate) {
|
||||
resampler->adjustRate(resampler->inRate(), outRate);
|
||||
resetSndOutBuf(sndOutBuf, resampler, maxspf);
|
||||
|
||||
const std::size_t sz = resampler->maxOut(maxspf) * 2;
|
||||
|
||||
if (sz > sndOutBuf.size())
|
||||
sndOutBuf.reset(sz);
|
||||
}
|
||||
|
||||
void MainWindow::setSampleRate() {
|
||||
@ -497,8 +492,7 @@ void MainWindow::setSampleRate() {
|
||||
|
||||
resampler.reset();
|
||||
resampler.reset(ResamplerInfo::get(soundDialog->getResamplerNum()).create(insrate, ae->rate(), maxspf));
|
||||
|
||||
resetSndOutBuf(sndOutBuffer, resampler.get(), maxspf);
|
||||
sndOutBuffer.reset(resampler->maxOut(maxspf) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,10 +502,8 @@ void MainWindow::initAudio() {
|
||||
|
||||
ae = audioEngines[soundDialog->getEngineIndex()];
|
||||
|
||||
if (ae->init(soundDialog->getRate(), soundDialog->getLatency()) < 0) {
|
||||
if (ae->init(soundDialog->getRate(), soundDialog->getLatency()) < 0)
|
||||
ae = NULL;
|
||||
} else
|
||||
estSrate = ae->rate();
|
||||
|
||||
setSampleRate();
|
||||
}
|
||||
@ -534,30 +526,31 @@ void MainWindow::timerEvent(QTimerEvent */*event*/) {
|
||||
long syncft = 0;
|
||||
|
||||
if (!turbo) {
|
||||
if (ae->write(sndOutBuffer, outsamples) < 0) {
|
||||
RateEst::Result rsrate;
|
||||
AudioEngine::BufferState bstate;
|
||||
|
||||
if (ae->write(sndOutBuffer, outsamples, bstate, rsrate) < 0) {
|
||||
ae->pause();
|
||||
soundEngineFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const RateEst::Result &rsrate = ae->rateEstimate();
|
||||
const long newEstSrate = rsrate.est + (rsrate.var * 2);
|
||||
|
||||
if (std::abs(newEstSrate - estSrate) > rsrate.var * 2)
|
||||
estSrate = newEstSrate;
|
||||
}
|
||||
|
||||
const long usecft = blitter->frameTime();
|
||||
syncft = static_cast<float>(usecft - (usecft >> 11)) * ae->rate() / estSrate;
|
||||
syncft = static_cast<float>(usecft - (usecft >> 10)) * ae->rate() / rsrate.est;
|
||||
|
||||
if (bstate.fromUnderrun != AudioEngine::BufferState::NOT_SUPPORTED &&
|
||||
bstate.fromUnderrun + outsamples * 2 < bstate.fromOverflow)
|
||||
syncft >>= 1;
|
||||
|
||||
const BlitterWidget::Estimate &estft = blitter->frameTimeEst();
|
||||
|
||||
if (estft.est) {
|
||||
long resorate = estSrate * static_cast<float>(estft.est + (estft.est >> 11) + estft.var * 2) / usecft;
|
||||
float est = static_cast<float>(rsrate.est) * estft.est;
|
||||
const float var = static_cast<float>(rsrate.est + rsrate.var) * (estft.est + estft.var) - est;
|
||||
est += var;
|
||||
|
||||
if (static_cast<float>(std::abs(resorate - resampler->outRate())) * usecft > static_cast<float>(estft.var * 2) * estSrate)
|
||||
adjustResamplerRate(sndOutBuffer, resampler.get(), maxSamplesPerFrame(source), resorate);
|
||||
if (std::fabs(est - resampler->outRate() * static_cast<float>(usecft - (usecft >> 11))) > var * 2)
|
||||
adjustResamplerRate(sndOutBuffer, resampler.get(), maxSamplesPerFrame(source), est / (usecft - (usecft >> 11)));
|
||||
} else if (resampler->outRate() != ae->rate())
|
||||
adjustResamplerRate(sndOutBuffer, resampler.get(), maxSamplesPerFrame(source), ae->rate());
|
||||
}
|
||||
|
@ -105,7 +105,6 @@ private:
|
||||
unsigned ftDenom;
|
||||
unsigned paused;
|
||||
int timerId;
|
||||
int estSrate;
|
||||
|
||||
JoystickIniter joyIniter;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user