allow dynamically setting samples per frame

git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@175 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
sinamas 2008-10-16 16:57:44 +00:00
parent 5e596dcfa3
commit 248dee24a5
6 changed files with 43 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aamås *
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
@ -174,6 +174,7 @@ mw(mw), source(source), frameTime(4389, 262144) {
mw->addAction(hideMenuAct);
mw->setFrameTime(frameTime.get().num, frameTime.get().denom);
mw->setSamplesPerFrame(35112);
connect(source, SIGNAL(blit()), mw, SLOT(blit()));
connect(source, SIGNAL(setTurbo(bool)), mw, SLOT(setTurbo(bool)));
connect(source, SIGNAL(togglePause()), pauseAction, SLOT(trigger()));
@ -294,7 +295,7 @@ void GambatteMenuHandler::about() {
mw,
tr("About Gambatte"),
tr("<h3>Gambatte Qt svn</h3>\
<p><b>Author:</b> Sindre Aamås (<a href=\"mailto:aamas@stud.ntnu.no\">aamas@stud.ntnu.no</a>).<br>\
<p><b>Author:</b> Sindre Aam<EFBFBD>s (<a href=\"mailto:aamas@stud.ntnu.no\">aamas@stud.ntnu.no</a>).<br>\
<b>Homepage:</b> <a href=\"http://sourceforge.net/projects/gambatte\">http://sourceforge.net/projects/gambatte</a>.</p>\
<p>Gambatte is an accuracy-focused, open-source, cross-platform Game Boy / Game Boy Color emulator written in C++. It is based on hundreds of corner case hardware tests, as well as previous documentation and reverse engineering efforts.</p>")
);

View File

@ -19,7 +19,7 @@
#include "gambattesource.h"
GambatteSource::GambatteSource() :
MediaSource(Rational(35112), 2064),
MediaSource(2064),
blitter(*this) {
gb.setInputStateGetter(&inputGetter);
gb.setVideoBlitter(&blitter);

View File

@ -98,12 +98,17 @@ MainWindow::JoystickIniter::~JoystickIniter() {
SDL_JoystickQuit();
}
MainWindow::SampleBuffer::SampleBuffer(const std::size_t maxInSamples) : sndInBuffer(maxInSamples * 2), spfnum(0), samplesBuffered(0) {}
void MainWindow::SampleBuffer::reset(const Rational &spf, const unsigned overupdate) {
sndInBuffer.reset((spf.ceil() + overupdate) * 2);
this->spf = spf;
num = 0;
samplesBuffered = 0;
}
std::size_t MainWindow::SampleBuffer::update(qint16 *const out, MediaSource *const source, Resampler *const resampler) {
spfnum += source->samplesPerFrame.num;
const long insamples = spfnum / source->samplesPerFrame.denom;
spfnum -= insamples * source->samplesPerFrame.denom;
num += spf.num;
const long insamples = num / spf.denom;
num -= insamples * spf.denom;
samplesBuffered += source->update(sndInBuffer + samplesBuffered * 2, insamples - samplesBuffered);
samplesBuffered -= insamples;
@ -133,7 +138,7 @@ MainWindow::MainWindow(MediaSource *source,
buttonHandlers(buttonInfos.size(), ButtonHandler(0, 0)),
blitter(NULL),
fullModeToggler(getFullModeToggler(winId())),
sampleBuffer((source->samplesPerFrame.num - 1) / source->samplesPerFrame.denom + 1 + source->overupdate),
sampleBuffer(Rational(735, 1), source->overupdate),
sndOutBuffer(0),
ae(NULL),
cursorTimer(NULL),
@ -471,10 +476,6 @@ void MainWindow::setFrameTime(unsigned num, unsigned denom) {
setSampleRate();
}
static long maxSamplesPerFrame(const MediaSource *const source) {
return (source->samplesPerFrame.num - 1) / source->samplesPerFrame.denom + 1;
}
static void adjustResamplerRate(Array<qint16> &sndOutBuf, Resampler *const resampler, const long maxspf, const long outRate) {
resampler->adjustRate(resampler->inRate(), outRate);
@ -487,8 +488,8 @@ static void adjustResamplerRate(Array<qint16> &sndOutBuf, Resampler *const resam
void MainWindow::setSampleRate() {
if (ae) {
const Rational fr(ftDenom, ftNum);
const long insrate = fr.toDouble() * source->samplesPerFrame.toDouble() + 0.5;
const long maxspf = maxSamplesPerFrame(source);
const long insrate = fr.toDouble() * sampleBuffer.samplesPerFrame().toDouble() + 0.5;
const long maxspf = sampleBuffer.samplesPerFrame().ceil();
resampler.reset();
resampler.reset(ResamplerInfo::get(soundDialog->getResamplerNum()).create(insrate, ae->rate(), maxspf));
@ -496,6 +497,11 @@ void MainWindow::setSampleRate() {
}
}
void MainWindow::setSamplesPerFrame(const long num, const long denom) {
sampleBuffer.reset(Rational(num, denom), source->overupdate);
setSampleRate();
}
void MainWindow::initAudio() {
if (ae)
ae->uninit();
@ -550,9 +556,9 @@ void MainWindow::timerEvent(QTimerEvent */*event*/) {
est += var;
if (std::fabs(est - resampler->outRate() * static_cast<float>(usecft - (usecft >> 11))) > var * 2)
adjustResamplerRate(sndOutBuffer, resampler.get(), maxSamplesPerFrame(source), est / (usecft - (usecft >> 11)));
adjustResamplerRate(sndOutBuffer, resampler.get(), sampleBuffer.samplesPerFrame().ceil(), est / (usecft - (usecft >> 11)));
} else if (resampler->outRate() != ae->rate())
adjustResamplerRate(sndOutBuffer, resampler.get(), maxSamplesPerFrame(source), ae->rate());
adjustResamplerRate(sndOutBuffer, resampler.get(), sampleBuffer.samplesPerFrame().ceil(), ae->rate());
}
if (blitter->sync(syncft) < 0) {

View File

@ -70,11 +70,14 @@ private:
class SampleBuffer {
Array<qint16> sndInBuffer;
unsigned spfnum;
Rational spf;
unsigned num;
unsigned samplesBuffered;
public:
SampleBuffer(std::size_t maxInSamples);
SampleBuffer(const Rational &spf, unsigned overupdate) { reset(spf, overupdate); }
const Rational& samplesPerFrame() const { return spf; }
void reset(const Rational &spf, unsigned overupdate);
std::size_t update(qint16 *out, MediaSource *source, Resampler *resampler);
};
@ -190,10 +193,17 @@ public:
/**
* Sets time period in seconds between calls to source->update(). Eg. for 60 Hz updates
* use setFrameTime(1, 60). Too high values of numerator or denominator _may_ lead to overflows.
* use setFrameTime(1, 60).
*/
void setFrameTime(unsigned numerator, unsigned denominator);
/**
* Sets the number of audio stereo source samples per video frame.
* Eg. for a source sample rate of 44100 Hz at a frame rate of 60 fps use setSamplesPerFrame(44100, 60)
* or setSamplesPerFrame(735).
*/
void setSamplesPerFrame(long num, long denom = 1);
/**
* When pauseOnDialogExec is set, source->update()s will be paused when a dialog is launched
* from MainWindow, and unpaused when the dialog is closed. pauseOnDialogExec is on by default.

View File

@ -33,6 +33,8 @@
// (note that the source may support formats of higher details than it needs)
class MediaSource {
protected:
MediaSource(const unsigned overupdate = 0) : overupdate(overupdate) {}
public:
/**
* Formats that you'll have to deal with if a BlitterWidget decides to give you a buffer with such a format.
@ -90,11 +92,8 @@ public:
int maxCustomRate;
};
const Rational samplesPerFrame;
const unsigned overupdate;
MediaSource(const Rational &samplesPerFrame, const unsigned overupdate = 0) : samplesPerFrame(samplesPerFrame), overupdate(overupdate) {}
/**
* Reimplement to get buttonPress events for buttons of corresponding index to the
* buttonInfos given to MainWindow.

View File

@ -26,6 +26,11 @@ struct Rational {
Rational(const long num = 1, const long denom = 1) : num(num), denom(denom) {}
float toFloat() const { return static_cast<float>(num) / denom; }
double toDouble() const { return static_cast<double>(num) / denom; }
// assumes positive num and denom
long ceil() const { return (num - 1) / denom + 1; }
long floor() const { return num / denom; }
long round() const { return (num + (denom >> 1)) / denom; }
};
#endif