2018-05-04 22:47:48 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// 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-2018 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.
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
#include "EmulationTiming.hxx"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
constexpr uInt32 AUDIO_HALF_FRAMES_PER_FRAGMENT = 1;
|
|
|
|
constexpr uInt32 QUEUE_CAPACITY_SAFETY_FACTOR = 2;
|
2018-05-11 22:18:09 +00:00
|
|
|
constexpr uInt32 PREBUFFER_FRAGMENT_COUNT = 2;
|
2018-05-04 22:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
EmulationTiming::EmulationTiming(FrameLayout frameLayout) :
|
|
|
|
myFrameLayout(frameLayout),
|
|
|
|
myPlaybackRate(44100),
|
|
|
|
myPlaybackPeriod(512)
|
|
|
|
{}
|
2018-05-04 22:47:48 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
void EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
|
|
|
|
{
|
|
|
|
myFrameLayout = frameLayout;
|
2018-05-04 22:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
void EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
|
|
|
|
{
|
|
|
|
myPlaybackRate = playbackRate;
|
2018-05-04 22:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
void EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
|
|
|
|
{
|
|
|
|
myPlaybackPeriod = playbackPeriod;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
uInt32 EmulationTiming::maxCyclesPerTimeslice() const
|
|
|
|
{
|
|
|
|
return 2 * cyclesPerFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
uInt32 EmulationTiming::minCyclesPerTimeslice() const
|
|
|
|
{
|
2018-05-04 22:47:48 +00:00
|
|
|
return cyclesPerFrame() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::linesPerFrame() const
|
|
|
|
{
|
|
|
|
switch (myFrameLayout) {
|
2018-05-04 22:47:48 +00:00
|
|
|
case FrameLayout::ntsc:
|
|
|
|
return 262;
|
|
|
|
|
|
|
|
case FrameLayout::pal:
|
|
|
|
return 312;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw runtime_error("invalid frame layout");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::cyclesPerFrame() const
|
|
|
|
{
|
2018-05-04 22:47:48 +00:00
|
|
|
return 76 * linesPerFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::framesPerSecond() const
|
|
|
|
{
|
|
|
|
switch (myFrameLayout) {
|
2018-05-04 22:47:48 +00:00
|
|
|
case FrameLayout::ntsc:
|
|
|
|
return 60;
|
|
|
|
|
|
|
|
case FrameLayout::pal:
|
|
|
|
return 50;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw runtime_error("invalid frame layout");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::cyclesPerSecond() const
|
|
|
|
{
|
2018-05-04 22:47:48 +00:00
|
|
|
return cyclesPerFrame() * framesPerSecond();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::audioFragmentSize() const
|
|
|
|
{
|
2018-05-04 22:47:48 +00:00
|
|
|
return AUDIO_HALF_FRAMES_PER_FRAGMENT * linesPerFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::audioSampleRate() const
|
|
|
|
{
|
2018-05-04 22:47:48 +00:00
|
|
|
return 2 * linesPerFrame() * framesPerSecond();
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::audioQueueCapacity() const
|
|
|
|
{
|
|
|
|
uInt32 capacity = (myPlaybackPeriod * audioSampleRate()) / (audioFragmentSize() * myPlaybackRate) + 1;
|
2018-05-04 22:47:48 +00:00
|
|
|
uInt32 minCapacity = (maxCyclesPerTimeslice() * audioSampleRate()) / (audioFragmentSize() * cyclesPerSecond()) + 1;
|
|
|
|
|
|
|
|
return std::max(prebufferFragmentCount() + 1, QUEUE_CAPACITY_SAFETY_FACTOR * std::max(capacity, minCapacity));
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-05-06 21:45:21 +00:00
|
|
|
uInt32 EmulationTiming::prebufferFragmentCount() const
|
|
|
|
{
|
|
|
|
return (myPlaybackPeriod * audioSampleRate()) / (audioFragmentSize() * myPlaybackRate) + PREBUFFER_FRAGMENT_COUNT;
|
2018-05-04 22:47:48 +00:00
|
|
|
}
|