mirror of https://github.com/stella-emu/stella.git
Support variable emulation speed.
This commit is contained in:
parent
674e5f01c0
commit
2b23c81126
|
@ -58,6 +58,7 @@
|
|||
"cstring": "cpp",
|
||||
"iostream": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"ostream": "cpp"
|
||||
"ostream": "cpp",
|
||||
"__memory": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -563,7 +563,8 @@ void Console::initializeAudio()
|
|||
.updatePlaybackRate(myOSystem.sound().getSampleRate())
|
||||
.updatePlaybackPeriod(myOSystem.sound().getFragmentSize())
|
||||
.updateAudioQueueExtraFragments(myAudioSettings.bufferSize())
|
||||
.updateAudioQueueHeadroom(myAudioSettings.headroom());
|
||||
.updateAudioQueueHeadroom(myAudioSettings.headroom())
|
||||
.updateSpeedFactor(myOSystem.settings().getFloat("speed"));
|
||||
|
||||
(cout << "sample rate: " << myOSystem.sound().getSampleRate() << std::endl).flush();
|
||||
(cout << "fragment size: " << myOSystem.sound().getFragmentSize() << std::endl).flush();
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "EmulationTiming.hxx"
|
||||
|
||||
namespace {
|
||||
|
@ -32,13 +34,18 @@ EmulationTiming::EmulationTiming(FrameLayout frameLayout) :
|
|||
myPlaybackRate(44100),
|
||||
myPlaybackPeriod(512),
|
||||
myAudioQueueExtraFragments(1),
|
||||
myAudioQueueHeadroom(2)
|
||||
{}
|
||||
myAudioQueueHeadroom(2),
|
||||
mySpeedFactor(1)
|
||||
{
|
||||
recalculate();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EmulationTiming& EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
|
||||
{
|
||||
myFrameLayout = frameLayout;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -46,6 +53,8 @@ EmulationTiming& EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
|
|||
EmulationTiming& EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
|
||||
{
|
||||
myPlaybackRate = playbackRate;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -53,6 +62,8 @@ EmulationTiming& EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
|
|||
EmulationTiming& EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
|
||||
{
|
||||
myPlaybackPeriod = playbackPeriod;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -60,6 +71,8 @@ EmulationTiming& EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
|
|||
EmulationTiming& EmulationTiming::updateAudioQueueExtraFragments(uInt32 audioQueueExtraFragments)
|
||||
{
|
||||
myAudioQueueExtraFragments = audioQueueExtraFragments;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -67,85 +80,123 @@ EmulationTiming& EmulationTiming::updateAudioQueueExtraFragments(uInt32 audioQue
|
|||
EmulationTiming& EmulationTiming::updateAudioQueueHeadroom(uInt32 audioQueueHeadroom)
|
||||
{
|
||||
myAudioQueueHeadroom = audioQueueHeadroom;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EmulationTiming& EmulationTiming::updateSpeedFactor(float speedFactor)
|
||||
{
|
||||
mySpeedFactor = speedFactor;
|
||||
recalculate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::maxCyclesPerTimeslice() const
|
||||
{
|
||||
return 2 * cyclesPerFrame();
|
||||
return myMaxCyclesPerTimeslice;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::minCyclesPerTimeslice() const
|
||||
{
|
||||
return cyclesPerFrame() / 2;
|
||||
return myMinCyclesPerTimeslice;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::linesPerFrame() const
|
||||
{
|
||||
switch (myFrameLayout) {
|
||||
case FrameLayout::ntsc:
|
||||
return 262;
|
||||
|
||||
case FrameLayout::pal:
|
||||
return 312;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid frame layout");
|
||||
}
|
||||
return myLinesPerFrame;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::cyclesPerFrame() const
|
||||
{
|
||||
return 76 * linesPerFrame();
|
||||
return myCyclesPerFrame;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::framesPerSecond() const
|
||||
{
|
||||
switch (myFrameLayout) {
|
||||
case FrameLayout::ntsc:
|
||||
return 60;
|
||||
|
||||
case FrameLayout::pal:
|
||||
return 50;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid frame layout");
|
||||
}
|
||||
return myFramesPerSecond;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::cyclesPerSecond() const
|
||||
{
|
||||
return cyclesPerFrame() * framesPerSecond();
|
||||
return myCyclesPerSecond;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::audioFragmentSize() const
|
||||
{
|
||||
return AUDIO_HALF_FRAMES_PER_FRAGMENT * linesPerFrame();
|
||||
return myAudioFragmentSize;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::audioSampleRate() const
|
||||
{
|
||||
return 2 * linesPerFrame() * framesPerSecond();
|
||||
return myAudioSampleRate;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::audioQueueCapacity() const
|
||||
{
|
||||
uInt32 minCapacity = discreteDivCeil(maxCyclesPerTimeslice() * audioSampleRate(), audioFragmentSize() * cyclesPerSecond());
|
||||
|
||||
return std::max(prebufferFragmentCount(), minCapacity) + myAudioQueueExtraFragments;
|
||||
return myAudioQueueCapacity;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::prebufferFragmentCount() const
|
||||
{
|
||||
return discreteDivCeil(myPlaybackPeriod * audioSampleRate(), audioFragmentSize() * myPlaybackRate) + myAudioQueueHeadroom;
|
||||
return myPrebufferFragmentCount;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EmulationTiming::recalculate()
|
||||
{
|
||||
switch (myFrameLayout) {
|
||||
case FrameLayout::ntsc:
|
||||
myLinesPerFrame = 262;
|
||||
break;
|
||||
|
||||
case FrameLayout::pal:
|
||||
myLinesPerFrame = 312;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid frame layout");
|
||||
}
|
||||
|
||||
switch (myFrameLayout) {
|
||||
case FrameLayout::ntsc:
|
||||
myFramesPerSecond = round(mySpeedFactor * 60);
|
||||
break;
|
||||
|
||||
case FrameLayout::pal:
|
||||
myFramesPerSecond = round(mySpeedFactor * 50);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid frame layout");
|
||||
}
|
||||
|
||||
myCyclesPerFrame = 76 * myLinesPerFrame;
|
||||
myMaxCyclesPerTimeslice = round(mySpeedFactor * myCyclesPerFrame * 2);
|
||||
myMinCyclesPerTimeslice = round(mySpeedFactor * myCyclesPerFrame / 2);
|
||||
myCyclesPerSecond = myCyclesPerFrame * myFramesPerSecond;
|
||||
myAudioFragmentSize = round(mySpeedFactor * AUDIO_HALF_FRAMES_PER_FRAGMENT * myLinesPerFrame);
|
||||
myAudioSampleRate = 2 * myLinesPerFrame * myFramesPerSecond;
|
||||
|
||||
myPrebufferFragmentCount = discreteDivCeil(
|
||||
myPlaybackPeriod * myAudioSampleRate,
|
||||
myAudioFragmentSize * myPlaybackRate
|
||||
) + myAudioQueueHeadroom;
|
||||
|
||||
myAudioQueueCapacity = std::max(
|
||||
myPrebufferFragmentCount,
|
||||
discreteDivCeil(myMaxCyclesPerTimeslice * myAudioSampleRate, myAudioFragmentSize * myCyclesPerSecond)
|
||||
) + myAudioQueueExtraFragments;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ class EmulationTiming {
|
|||
|
||||
EmulationTiming& updateAudioQueueHeadroom(uInt32 audioQueueHeadroom);
|
||||
|
||||
EmulationTiming& updateSpeedFactor(float speedFactor);
|
||||
|
||||
uInt32 maxCyclesPerTimeslice() const;
|
||||
|
||||
uInt32 minCyclesPerTimeslice() const;
|
||||
|
@ -56,17 +58,32 @@ class EmulationTiming {
|
|||
|
||||
uInt32 prebufferFragmentCount() const;
|
||||
|
||||
private:
|
||||
|
||||
void recalculate();
|
||||
|
||||
private:
|
||||
|
||||
FrameLayout myFrameLayout;
|
||||
|
||||
uInt32 myPlaybackRate;
|
||||
|
||||
uInt32 myPlaybackPeriod;
|
||||
|
||||
uInt32 myAudioQueueExtraFragments;
|
||||
uInt32 myAudioQueueHeadroom;
|
||||
|
||||
uInt32 myMaxCyclesPerTimeslice;
|
||||
uInt32 myMinCyclesPerTimeslice;
|
||||
uInt32 myLinesPerFrame;
|
||||
uInt32 myCyclesPerFrame;
|
||||
uInt32 myFramesPerSecond;
|
||||
uInt32 myCyclesPerSecond;
|
||||
uInt32 myAudioFragmentSize;
|
||||
uInt32 myAudioSampleRate;
|
||||
uInt32 myAudioQueueCapacity;
|
||||
uInt32 myPrebufferFragmentCount;
|
||||
|
||||
float mySpeedFactor;
|
||||
|
||||
private:
|
||||
|
||||
EmulationTiming(const EmulationTiming&) = delete;
|
||||
|
|
|
@ -35,7 +35,7 @@ Settings::Settings(OSystem& osystem)
|
|||
{
|
||||
// Video-related options
|
||||
setInternal("video", "");
|
||||
setInternal("framerate", "0");
|
||||
setInternal("speed", "1.0");
|
||||
setInternal("vsync", "true");
|
||||
setInternal("fullscreen", "false");
|
||||
setInternal("center", "false");
|
||||
|
@ -303,6 +303,10 @@ void Settings::validate()
|
|||
{
|
||||
string s;
|
||||
int i;
|
||||
float f;
|
||||
|
||||
f = getFloat("speed");
|
||||
if (f <= 0) setInternal("speed", "1.0");
|
||||
|
||||
s = getString("timing");
|
||||
if(s != "sleep" && s != "busy") setInternal("timing", "sleep");
|
||||
|
@ -439,7 +443,7 @@ void Settings::usage() const
|
|||
<< " -palette <standard| Use the specified color palette\n"
|
||||
<< " z26|\n"
|
||||
<< " user>\n"
|
||||
<< " -framerate <number> Display the given number of frames per second (0 to auto-calculate)\n"
|
||||
<< " -speed <number> Run emulation at the given speed\n"
|
||||
<< " -timing <sleep|busy> Use the given type of wait between frames\n"
|
||||
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
|
||||
<< endl
|
||||
|
|
Loading…
Reference in New Issue