stella/src/emucore/EmulationTiming.cxx

203 lines
5.6 KiB
C++
Raw Normal View History

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
2018-06-27 21:12:50 +00:00
#include <cmath>
#include "EmulationTiming.hxx"
namespace {
constexpr uInt32 AUDIO_HALF_FRAMES_PER_FRAGMENT = 1;
2018-05-12 14:21:58 +00:00
uInt32 discreteDivCeil(uInt32 n, uInt32 d)
{
return n / d + ((n % d == 0) ? 0 : 1);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-07-01 22:58:32 +00:00
EmulationTiming::EmulationTiming(FrameLayout frameLayout, ConsoleTiming consoleTiming) :
2018-05-06 21:45:21 +00:00
myFrameLayout(frameLayout),
myConsoleTiming(consoleTiming)
2018-06-27 21:12:50 +00:00
{
recalculate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-06-22 22:58:28 +00:00
EmulationTiming& EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
2018-05-06 21:45:21 +00:00
{
myFrameLayout = frameLayout;
2018-06-27 21:12:50 +00:00
recalculate();
2018-06-22 22:58:28 +00:00
return *this;
}
2018-07-01 22:58:32 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EmulationTiming& EmulationTiming::updateConsoleTiming(ConsoleTiming consoleTiming)
{
myConsoleTiming = consoleTiming;
recalculate();
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-06-22 22:58:28 +00:00
EmulationTiming& EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
2018-05-06 21:45:21 +00:00
{
myPlaybackRate = playbackRate;
2018-06-27 21:12:50 +00:00
recalculate();
2018-06-22 22:58:28 +00:00
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-06-22 22:58:28 +00:00
EmulationTiming& EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
2018-05-06 21:45:21 +00:00
{
myPlaybackPeriod = playbackPeriod;
2018-06-27 21:12:50 +00:00
recalculate();
2018-06-22 22:58:28 +00:00
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EmulationTiming& EmulationTiming::updateAudioQueueExtraFragments(uInt32 audioQueueExtraFragments)
{
myAudioQueueExtraFragments = audioQueueExtraFragments;
2018-06-27 21:12:50 +00:00
recalculate();
2018-06-22 22:58:28 +00:00
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EmulationTiming& EmulationTiming::updateAudioQueueHeadroom(uInt32 audioQueueHeadroom)
{
myAudioQueueHeadroom = audioQueueHeadroom;
2018-06-27 21:12:50 +00:00
recalculate();
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EmulationTiming& EmulationTiming::updateSpeedFactor(float speedFactor)
{
mySpeedFactor = static_cast<double>(speedFactor);
2018-06-27 21:12:50 +00:00
recalculate();
2018-06-22 22:58:28 +00:00
return *this;
2018-05-06 21:45:21 +00:00
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 EmulationTiming::maxCyclesPerTimeslice() const
{
2018-06-27 21:12:50 +00:00
return myMaxCyclesPerTimeslice;
2018-05-06 21:45:21 +00:00
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 EmulationTiming::minCyclesPerTimeslice() const
{
2018-06-27 21:12:50 +00:00
return myMinCyclesPerTimeslice;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::linesPerFrame() const
{
2018-06-27 21:12:50 +00:00
return myLinesPerFrame;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::cyclesPerFrame() const
{
2018-06-27 21:12:50 +00:00
return myCyclesPerFrame;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::cyclesPerSecond() const
{
2018-06-27 21:12:50 +00:00
return myCyclesPerSecond;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::audioFragmentSize() const
{
2018-06-27 21:12:50 +00:00
return myAudioFragmentSize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::audioSampleRate() const
{
2018-06-27 21:12:50 +00:00
return myAudioSampleRate;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::audioQueueCapacity() const
{
2018-06-27 21:12:50 +00:00
return myAudioQueueCapacity;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-05-06 21:45:21 +00:00
uInt32 EmulationTiming::prebufferFragmentCount() const
{
2018-06-27 21:12:50 +00:00
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");
}
2018-07-01 22:58:32 +00:00
switch (myConsoleTiming) {
case ConsoleTiming::ntsc:
myAudioSampleRate = uInt32(round(mySpeedFactor * 262 * 76 * 60) / 38);
2018-06-27 21:12:50 +00:00
break;
2018-07-01 22:58:32 +00:00
case ConsoleTiming::pal:
case ConsoleTiming::secam:
myAudioSampleRate = uInt32(round(mySpeedFactor * 312 * 76 * 50) / 38);
2018-06-27 21:12:50 +00:00
break;
default:
2018-07-01 22:58:32 +00:00
throw runtime_error("invalid console timing");
2018-06-27 21:12:50 +00:00
}
2018-07-01 22:58:32 +00:00
myCyclesPerSecond = myAudioSampleRate * 38;
2018-06-27 21:12:50 +00:00
myCyclesPerFrame = 76 * myLinesPerFrame;
myMaxCyclesPerTimeslice = uInt32(round(mySpeedFactor * myCyclesPerFrame * 2));
myMinCyclesPerTimeslice = uInt32(round(mySpeedFactor * myCyclesPerFrame / 2));
myAudioFragmentSize = uInt32(round(mySpeedFactor * AUDIO_HALF_FRAMES_PER_FRAGMENT * myLinesPerFrame));
2018-06-27 21:12:50 +00:00
myPrebufferFragmentCount = discreteDivCeil(
myPlaybackPeriod * myAudioSampleRate,
myAudioFragmentSize * myPlaybackRate
) + myAudioQueueHeadroom;
myAudioQueueCapacity = std::max(
myPrebufferFragmentCount,
discreteDivCeil(myMaxCyclesPerTimeslice * myAudioSampleRate, myAudioFragmentSize * myCyclesPerSecond)
) + myAudioQueueExtraFragments;
}