mirror of https://github.com/stella-emu/stella.git
added optional autodetection of PAL-60 & NTSC-50
This commit is contained in:
parent
a80798e281
commit
1a8971e6d1
Binary file not shown.
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.6 KiB |
|
@ -2608,6 +2608,16 @@
|
|||
<td>Adjust gamma of current palette (range -1.0 to 1.0).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-detectpal60 <1|0></pre></td>
|
||||
<td>Enable autodetection of PAL-60 based on colors used..</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-detectntsc50 <1|0></pre></td>
|
||||
<td>Enable autodetection of NTSC-50 based on colors used..</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-speed <number></pre></td>
|
||||
<td>Control the emulation speed (as a percentage, 10 - 1000).</td>
|
||||
|
@ -3642,15 +3652,17 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">Command Line</a></th></tr>
|
||||
<tr><td>Palette</td><td>Palette used for emulation mode</td><td>-palette</td></tr>
|
||||
<tr><td>NTSC/PAL phase</td><td>Adjust phase shift of 'Custom' NTSC or PAL (depends on game) palette. </td><td>-pal.phase_ntsc, -pal.phase_pal</td></tr>
|
||||
<tr><td>R</td><td>Adjust red scale and shift of 'Custom' palette</td><td>-pal.red_scale, -pal.red_shift</td></tr>
|
||||
<tr><td>G</td><td>Adjust green scale and shift of 'Custom' palette</td><td>-pal.green_scale, -pal.green_shift</td></tr>
|
||||
<tr><td>B</td><td>Adjust blue scale and shift of 'Custom' palette</td><td>-pal.blue_scale, -pal.blue_shift</td></tr>
|
||||
<tr><td>NTSC/PAL phase</td><td>Adjust phase shift of 'Custom' NTSC or PAL (depends on game) palette.</td><td>-pal.phase_ntsc<br/>-pal.phase_pal</td></tr>
|
||||
<tr><td>R</td><td>Adjust red scale and shift of 'Custom' palette</td><td>-pal.red_scale<br/>-pal.red_shift</td></tr>
|
||||
<tr><td>G</td><td>Adjust green scale and shift of 'Custom' palette</td><td>-pal.green_scale<br/>-pal.green_shift</td></tr>
|
||||
<tr><td>B</td><td>Adjust blue scale and shift of 'Custom' palette</td><td>-pal.blue_scale<br/>-pal.blue_shift</td></tr>
|
||||
<tr><td>Hue</td><td>Adjust hue of currently selected palette</td><td>-pal.hue</td></tr>
|
||||
<tr><td>Saturation</td><td>Adjust saturation of currently selected palette</td><td>-pal.saturation</td></tr>
|
||||
<tr><td>Contrast</td><td>Adjust contrast of currently selected palette</td><td>-pal.contrast</td></tr>
|
||||
<tr><td>Brightness</td><td>Adjust brightness of currently selected palette</td><td>-pal.brightness</td></tr>
|
||||
<tr><td>Gamma</td><td>Adjust gamma of currently selected palette</td><td>-pal.gamma</td></tr>
|
||||
<tr><td>Autodetection</td><td>Enable autodetection of PAL-60/NTSC-50 based on colors used.</br>
|
||||
Note: The detection is not very reliable and therefore uses very conservative parameters to avoid false positives.</td><td>-detectpal60<br/>-detectntsc50</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -3666,7 +3678,7 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">Command Line</a></th></tr>
|
||||
<tr><td>TV mode</td><td>Disable TV effects, or select TV preset</td><td>-tv.filter</td></tr>
|
||||
<tr><td>Adjustable sliders</td><td>Set specific attribute in 'Custom' TV mode</td><td>-tv.sharpness, -tv.resolution, etc.</td></tr>
|
||||
<tr><td>Adjustable sliders</td><td>Set specific attribute in 'Custom' TV mode</td><td>-tv.sharpness<br/>-tv.resolution, etc.</td></tr>
|
||||
<tr><td>Phosphor for all ROMs</td><td>Enable phosphor mode for all ROMs</td><td>-tv.phosphor</td></tr>
|
||||
<tr><td>Blend (phosphor)</td><td>Blend level to use in phosphor mode for all ROMs
|
||||
(needs to be manually adjusted for your particular hardware)</td><td>-tv.phosblend</td></tr>
|
||||
|
|
|
@ -280,25 +280,54 @@ void Console::autodetectFrameLayout(bool reset)
|
|||
// We turn off the SuperCharger progress bars, otherwise the SC BIOS
|
||||
// will take over 250 frames!
|
||||
// The 'fastscbios' option must be changed before the system is reset
|
||||
bool fastscbios = myOSystem.settings().getBool("fastscbios");
|
||||
myOSystem.settings().setValue("fastscbios", true);
|
||||
Settings& settings = myOSystem.settings();
|
||||
bool fastscbios = settings.getBool("fastscbios");
|
||||
settings.setValue("fastscbios", true);
|
||||
|
||||
FrameLayoutDetector frameLayoutDetector;
|
||||
myTIA->setFrameManager(&frameLayoutDetector);
|
||||
myTIA->setFrameManager(&frameLayoutDetector, true);
|
||||
|
||||
if (reset) {
|
||||
mySystem->reset(true);
|
||||
myRiot->update();
|
||||
}
|
||||
|
||||
for(int i = 0; i < 60; ++i) myTIA->update();
|
||||
// Sample colors, ratio is 1/5 title (if existing), 4/5 game screen.
|
||||
for(int i = 0; i < 20; ++i)
|
||||
myTIA->update();
|
||||
|
||||
frameLayoutDetector.simulateInput(*myRiot, myOSystem.eventHandler(), true);
|
||||
myTIA->update();
|
||||
frameLayoutDetector.simulateInput(*myRiot, myOSystem.eventHandler(), false);
|
||||
|
||||
for(int i = 0; i < 40; ++i)
|
||||
myTIA->update();
|
||||
|
||||
switch(frameLayoutDetector.detectedLayout(
|
||||
settings.getBool("detectpal60"), settings.getBool("detectntsc50"),
|
||||
myProperties.get(PropType::Cart_Name)))
|
||||
{
|
||||
case FrameLayout::pal:
|
||||
myDisplayFormat = "PAL";
|
||||
break;
|
||||
|
||||
case FrameLayout::pal60:
|
||||
myDisplayFormat = "PAL60";
|
||||
break;
|
||||
|
||||
case FrameLayout::ntsc50:
|
||||
myDisplayFormat = "NTSC50";
|
||||
break;
|
||||
|
||||
default:
|
||||
myDisplayFormat = "NTSC";
|
||||
break;
|
||||
}
|
||||
|
||||
myTIA->setFrameManager(myFrameManager.get());
|
||||
|
||||
myDisplayFormat = frameLayoutDetector.detectedLayout() == FrameLayout::pal ? "PAL" : "NTSC";
|
||||
|
||||
// Don't forget to reset the SC progress bars again
|
||||
myOSystem.settings().setValue("fastscbios", fastscbios);
|
||||
settings.setValue("fastscbios", fastscbios);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -92,6 +92,9 @@ Settings::Settings()
|
|||
setPermanent("tv.fringing", "0.0");
|
||||
setPermanent("tv.bleed", "0.0");
|
||||
|
||||
setPermanent("detectpal60", "false");
|
||||
setPermanent("detectntsc50", "false");
|
||||
|
||||
// Sound options
|
||||
setPermanent(AudioSettings::SETTING_ENABLED, AudioSettings::DEFAULT_ENABLED);
|
||||
setPermanent(AudioSettings::SETTING_VOLUME, AudioSettings::DEFAULT_VOLUME);
|
||||
|
@ -516,6 +519,9 @@ void Settings::usage() const
|
|||
<< " -pal.brightness <-1.0 - 1.0> Adjust brightness of current palette\n"
|
||||
<< " -pal.gamma <-1.0 - 1.0> Adjust gamma of current palette\n"
|
||||
<< endl
|
||||
<< " -detectpal60 <1|0> Enable PAL-60 autodetection\n"
|
||||
<< " -detectntsc50 <1|0> Enable NTSC-50 autodetection\n"
|
||||
<< endl
|
||||
<< " -speed <number> Run emulation at the given speed\n"
|
||||
<< " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n"
|
||||
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
#define FRAME_LAYOUT
|
||||
|
||||
enum class FrameLayout {
|
||||
ntsc, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc)
|
||||
pal // ROM display has PAL timings (~50Hz, ~312 scanlines, etc)
|
||||
ntsc, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc)
|
||||
pal, // ROM display has PAL timings (~50Hz, ~312 scanlines, etc)
|
||||
pal60, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc), but uses PAL colors
|
||||
ntsc50 // ROM display has PAL timings (~50Hz, ~312 scanlines, etc), but uses NTSC colors
|
||||
};
|
||||
|
||||
#endif // FRAME_LAYOUT
|
||||
|
|
|
@ -88,11 +88,12 @@ TIA::TIA(ConsoleIO& console, const ConsoleTimingProvider& timingProvider,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::setFrameManager(AbstractFrameManager* frameManager)
|
||||
void TIA::setFrameManager(AbstractFrameManager* frameManager, bool layoutDetector)
|
||||
{
|
||||
clearFrameManager();
|
||||
|
||||
myFrameManager = frameManager;
|
||||
myIsLayoutDetector = layoutDetector;
|
||||
|
||||
myFrameManager->setHandlers(
|
||||
[this] () {
|
||||
|
@ -1559,12 +1560,21 @@ void TIA::nextLine()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::cloneLastLine()
|
||||
{
|
||||
const auto y = myFrameManager->getY();
|
||||
if(myIsLayoutDetector)
|
||||
{
|
||||
// y is always 0 in FrameLayoutDetector
|
||||
for(uInt32 i = 0 ; i < TIAConstants::H_PIXEL; ++i)
|
||||
myFrameManager->pixelColor(myBackBuffer[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto y = myFrameManager->getY();
|
||||
|
||||
if (!myFrameManager->isRendering() || y == 0) return;
|
||||
if(!myFrameManager->isRendering() || y == 0) return;
|
||||
|
||||
std::copy_n(myBackBuffer.begin() + (y-1) * TIAConstants::H_PIXEL, TIAConstants::H_PIXEL,
|
||||
myBackBuffer.begin() + y * TIAConstants::H_PIXEL);
|
||||
std::copy_n(myBackBuffer.begin() + (y - 1) * TIAConstants::H_PIXEL, TIAConstants::H_PIXEL,
|
||||
myBackBuffer.begin() + y * TIAConstants::H_PIXEL);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1642,6 +1652,8 @@ void TIA::renderPixel(uInt32 x, uInt32 y)
|
|||
}
|
||||
|
||||
myBackBuffer[y * TIAConstants::H_PIXEL + x] = color;
|
||||
if (myIsLayoutDetector)
|
||||
myFrameManager->pixelColor(color);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -123,7 +123,7 @@ class TIA : public Device
|
|||
/**
|
||||
Configure the frame manager.
|
||||
*/
|
||||
void setFrameManager(AbstractFrameManager* frameManager);
|
||||
void setFrameManager(AbstractFrameManager* frameManager, bool layoutDetector = false);
|
||||
|
||||
/**
|
||||
Set the audio queue. This needs to be dynamic as the queue is created after
|
||||
|
@ -794,6 +794,11 @@ class TIA : public Device
|
|||
*/
|
||||
AbstractFrameManager* myFrameManager{nullptr};
|
||||
|
||||
/**
|
||||
* The frame manager type.
|
||||
*/
|
||||
bool myIsLayoutDetector{false};
|
||||
|
||||
/**
|
||||
* The various TIA objects.
|
||||
*/
|
||||
|
|
|
@ -69,6 +69,11 @@ class AbstractFrameManager : public Serializable
|
|||
*/
|
||||
void setVsync(bool vsync, uInt64 cycles);
|
||||
|
||||
/**
|
||||
* Called when a pixel is rendered.
|
||||
*/
|
||||
virtual void pixelColor(uInt8 color) {};
|
||||
|
||||
/**
|
||||
* Should the TIA render its frame? This is buffered in a flag for
|
||||
* performance reasons; descendants must update the flag.
|
||||
|
|
|
@ -15,13 +15,122 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "EventHandler.hxx"
|
||||
#include "Logger.hxx"
|
||||
#include "M6532.hxx"
|
||||
|
||||
#include "FrameLayoutDetector.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameLayout FrameLayoutDetector::detectedLayout() const
|
||||
void FrameLayoutDetector::simulateInput(M6532& riot, EventHandler& eventHandler, bool pressed) const
|
||||
{
|
||||
// We choose the mode that was detected for the majority of frames.
|
||||
return myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc;
|
||||
// Console
|
||||
eventHandler.handleEvent(Event::ConsoleSelect, pressed);
|
||||
eventHandler.handleEvent(Event::ConsoleReset, pressed);
|
||||
// Various controller types
|
||||
eventHandler.handleEvent(Event::LeftJoystickFire, pressed);
|
||||
eventHandler.handleEvent(Event::RightJoystickFire, pressed);
|
||||
// Required for Console::redetectFrameLayout
|
||||
eventHandler.handleEvent(Event::LeftPaddleAFire, pressed);
|
||||
eventHandler.handleEvent(Event::LeftPaddleBFire, pressed);
|
||||
eventHandler.handleEvent(Event::RightPaddleAFire, pressed);
|
||||
eventHandler.handleEvent(Event::RightPaddleBFire, pressed);
|
||||
eventHandler.handleEvent(Event::LeftDrivingFire, pressed);
|
||||
eventHandler.handleEvent(Event::RightDrivingFire, pressed);
|
||||
riot.update();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameLayout FrameLayoutDetector::detectedLayout(bool detectPal60, bool detectNtsc50, const string& name) const
|
||||
{
|
||||
#if 0 // debug
|
||||
cerr << endl << name << endl;
|
||||
int i = 0;
|
||||
for(auto count : myColorCount)
|
||||
{
|
||||
if(i % 8 == 0)
|
||||
cerr << std::uppercase << std::setw(2) << std::hex << (i >> 3) << "x: ";
|
||||
cerr << std::setw(6) << std::dec << count;
|
||||
if(++i % 8 == 0)
|
||||
cerr << endl;
|
||||
else
|
||||
cerr << ", ";
|
||||
}
|
||||
cerr << endl;
|
||||
#endif
|
||||
#if 0 // save sampled color values
|
||||
std::ofstream file;
|
||||
|
||||
file.open("d:/Users/Thomas/Documents/Atari/Games/test/autodetect/colors.csv", std::ios::app);
|
||||
if(file.is_open())
|
||||
{
|
||||
file << name;
|
||||
for(auto count : myColorCount)
|
||||
file << "; " << count;
|
||||
file << "\n";
|
||||
file.close();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Multiply each hue's count with its NTSC and PAL stats and aggregate results
|
||||
// If NTSC/PAL results differ significantly, overrule frame result
|
||||
FrameLayout layout = myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc;
|
||||
|
||||
constexpr std::array<double, NUM_HUES> ntscColorFactor{
|
||||
0.00000, 0.05683, 0.06220, 0.05505, 0.06162, 0.02874, 0.03532, 0.03716,
|
||||
0.15568, 0.06471, 0.02886, 0.03224, 0.06903, 0.11478, 0.02632, 0.01675
|
||||
}; // ignore black = 0x00!
|
||||
constexpr std::array<double, NUM_HUES> palColorFactor{
|
||||
0.00000, 0.00450, 0.09962, 0.07603, 0.06978, 0.13023, 0.09638, 0.02268,
|
||||
0.02871, 0.04700, 0.02950, 0.11974, 0.03474, 0.08025, 0.00642, 0.00167
|
||||
}; // ignore black = 0x00!
|
||||
// Calculation weights and params (optimum based on sampled ROMs optimized for PAL-60)
|
||||
constexpr double POWER_FACTOR = 0.17; // Level the color counts (large values become less relevant)
|
||||
constexpr uInt32 SUM_DIV = 20; // Skip too small counts
|
||||
constexpr uInt32 MIN_VALID = 3; // Minimum number of different hues with significant counts
|
||||
constexpr double SUM_FACTOR = 2.0; // Minimum sum difference which triggers a layout change
|
||||
|
||||
double ntscSum{0}, palSum{0};
|
||||
std::array<double, NUM_HUES> hueSum{0};
|
||||
double totalHueSum = 0;
|
||||
uInt32 validHues = 0;
|
||||
|
||||
// Aggregate hues
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
for(int lum = 0; lum < NUM_LUMS; ++lum)
|
||||
if(hue || lum) // skip 0x00
|
||||
hueSum[hue] += myColorCount[hue * NUM_LUMS + lum];
|
||||
hueSum[hue] = std::pow(hueSum[hue], POWER_FACTOR);
|
||||
totalHueSum += hueSum[hue];
|
||||
}
|
||||
// Calculate hue sums
|
||||
for(int hue = 0; hue < NUM_HUES; ++hue)
|
||||
{
|
||||
if(hueSum[hue] > totalHueSum / SUM_DIV)
|
||||
validHues++;
|
||||
ntscSum += hueSum[hue] * ntscColorFactor[hue];
|
||||
palSum += hueSum[hue] * palColorFactor[hue];
|
||||
}
|
||||
// Correct layout if enough valid hues and significant sum difference
|
||||
// TODO: Use fractional scanline counts for intermediate values around 285 scanlines, e.g.
|
||||
// Desert Falcon, Dumbo's Flying Circus, Dungeon, Firefox, Millipede, Popeye, RS Basketball, Star Trek, Stunt Cycle
|
||||
if(validHues >= MIN_VALID)
|
||||
{
|
||||
if(detectPal60 && layout == FrameLayout::ntsc && ntscSum * SUM_FACTOR < palSum)
|
||||
{
|
||||
layout = FrameLayout::pal60;
|
||||
Logger::debug("Changed layout from NTSC into PAL-60");
|
||||
}
|
||||
// Note: three false positives (Berzerk, Canyon Bomber, Jawbreaker) for NTSC-50 after
|
||||
// optimizing for PAL-60
|
||||
else if(detectNtsc50 && layout == FrameLayout::pal && palSum * SUM_FACTOR < ntscSum)
|
||||
{
|
||||
layout = FrameLayout::ntsc50;
|
||||
Logger::debug("Changed layout from PAL into NTSC-50");
|
||||
}
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -36,6 +145,8 @@ void FrameLayoutDetector::onReset()
|
|||
myState = State::waitForVsyncStart;
|
||||
myNtscFrames = myPalFrames = 0;
|
||||
myLinesWaitingForVsyncToStart = 0;
|
||||
myColorCount.fill(0);
|
||||
myIsRendering = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -73,6 +184,16 @@ void FrameLayoutDetector::onNextLine()
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameLayoutDetector::pixelColor(uInt8 color)
|
||||
{
|
||||
if(myTotalFrames > Metrics::initialGarbageFrames)
|
||||
myColorCount[color >> 1]++;
|
||||
// Ideas:
|
||||
// - contrast to previous pixels (left/top)
|
||||
// - ???
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameLayoutDetector::setState(State state)
|
||||
{
|
||||
|
@ -112,15 +233,15 @@ void FrameLayoutDetector::finalizeFrame()
|
|||
if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance)
|
||||
layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal);
|
||||
else if (
|
||||
// If scanline count is odd and lies between the PAL and NTSC windows we assume
|
||||
// it is NTSC (it would cause color loss on PAL CRTs)
|
||||
// If scanline count is odd and lies between the PAL and NTSC windows we assume
|
||||
// it is NTSC (it would cause color loss on PAL CRTs)
|
||||
(myCurrentFrameFinalLines < frameLinesPAL) &&
|
||||
(myCurrentFrameFinalLines > frameLinesNTSC) &&
|
||||
(myCurrentFrameFinalLines % 2)
|
||||
)
|
||||
layout(FrameLayout::ntsc);
|
||||
else
|
||||
// Take the nearest layout if all else fails
|
||||
// Take the nearest layout if all else fails
|
||||
layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal);
|
||||
|
||||
switch (layout()) {
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#ifndef TIA_FRAME_LAYOUT_DETECTOR
|
||||
#define TIA_FRAME_LAYOUT_DETECTOR
|
||||
|
||||
class M6532;
|
||||
class EventHandler;
|
||||
|
||||
#include "FrameLayout.hxx"
|
||||
#include "AbstractFrameManager.hxx"
|
||||
#include "TIAConstants.hxx"
|
||||
|
@ -37,7 +40,13 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
/**
|
||||
* Return the detected frame layout.
|
||||
*/
|
||||
FrameLayout detectedLayout() const;
|
||||
FrameLayout detectedLayout(bool detectPal60 = false, bool detectNtsc50 = false,
|
||||
const string& name = EmptyString) const;
|
||||
|
||||
/**
|
||||
* Simulate some input to pass a potential title screen.
|
||||
*/
|
||||
void FrameLayoutDetector::simulateInput(M6532& riot, EventHandler& eventHandler, bool pressed) const;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -56,6 +65,11 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
*/
|
||||
void onNextLine() override;
|
||||
|
||||
/**
|
||||
* Called when a pixel is rendered.
|
||||
*/
|
||||
void pixelColor(uInt8 color) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -118,6 +132,16 @@ class FrameLayoutDetector: public AbstractFrameManager
|
|||
*/
|
||||
uInt32 myLinesWaitingForVsyncToStart{0};
|
||||
|
||||
/**
|
||||
* We count the number of pixels for each colors used. These are
|
||||
* evaluated against statistical color distributions and, if
|
||||
* decisive, allow overruling the scanline results.
|
||||
*/
|
||||
static constexpr int NUM_HUES = 16;
|
||||
static constexpr int NUM_LUMS = 8;
|
||||
|
||||
std::array<uInt64, NUM_HUES * NUM_LUMS> myColorCount{0};
|
||||
|
||||
private:
|
||||
|
||||
FrameLayoutDetector(const FrameLayoutDetector&) = delete;
|
||||
|
|
|
@ -56,10 +56,10 @@ void JitterEmulation::setSensitivity(Int32 sensitivity)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JitterEmulation::frameComplete(Int32 scanlineCount, Int32 vsyncCycles)
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
const int vsyncLines = round((vsyncCycles - 2) / 76.0);
|
||||
cerr << "TV jitter " << myJitter << " - " << scanlineCount << ", " << vsyncCycles << ", " << vsyncLines << endl;
|
||||
#endif
|
||||
//#ifdef DEBUG_BUILD
|
||||
// const int vsyncLines = round((vsyncCycles - 2) / 76.0);
|
||||
// cerr << "TV jitter " << myJitter << " - " << scanlineCount << ", " << vsyncCycles << ", " << vsyncLines << endl;
|
||||
//#endif
|
||||
|
||||
// Check if current frame size is stable compared to previous frame
|
||||
const bool scanlinesStable = scanlineCount == myLastFrameScanlines;
|
||||
|
|
|
@ -148,16 +148,16 @@ void GameInfoDialog::addEmulationTab()
|
|||
VarList::push_back(items, "NTSC", "NTSC");
|
||||
VarList::push_back(items, "PAL", "PAL");
|
||||
VarList::push_back(items, "SECAM", "SECAM");
|
||||
VarList::push_back(items, "NTSC50", "NTSC50");
|
||||
VarList::push_back(items, "PAL60", "PAL60");
|
||||
VarList::push_back(items, "SECAM60", "SECAM60");
|
||||
VarList::push_back(items, "NTSC-50", "NTSC50");
|
||||
VarList::push_back(items, "PAL-60", "PAL60");
|
||||
VarList::push_back(items, "SECAM-60", "SECAM60");
|
||||
myFormat = new PopUpWidget(myTab, _font, t->getRight(), ypos,
|
||||
pwidth, lineHeight, items);
|
||||
myFormat->setToolTip(Event::FormatDecrease, Event::FormatIncrease);
|
||||
wid.push_back(myFormat);
|
||||
|
||||
myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + fontWidth, ypos + 4,
|
||||
"SECAM60 detected");
|
||||
"SECAM-60 detected");
|
||||
|
||||
// Phosphor
|
||||
ypos += lineHeight + VGAP;
|
||||
|
|
|
@ -65,7 +65,7 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent,
|
|||
|
||||
// Set real dimensions
|
||||
setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2,
|
||||
_th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3,
|
||||
_th + VGAP * 5 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3,
|
||||
max_w, max_h);
|
||||
|
||||
// The tab widget
|
||||
|
@ -312,6 +312,17 @@ void VideoAudioDialog::addPaletteTab()
|
|||
CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated)
|
||||
CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated)
|
||||
|
||||
ypos += VGAP;
|
||||
StaticTextWidget* s = new StaticTextWidget(myTab, _font, xpos, ypos + 1, "Autodetection");
|
||||
|
||||
myDetectPal60 = new CheckboxWidget(myTab, _font, s->getRight() + fontWidth * 2, ypos + 1, "PAL-60");
|
||||
myDetectPal60 ->setToolTip("Enable autodetection of PAL-60 based on colors used.");
|
||||
wid.push_back(myDetectPal60 );
|
||||
|
||||
myDetectNtsc50 = new CheckboxWidget(myTab, _font, myDetectPal60->getRight() + fontWidth * 2, ypos + 1, "NTSC-50");
|
||||
myDetectNtsc50 ->setToolTip("Enable autodetection of NTSC-50 based on colors used.");
|
||||
wid.push_back(myDetectNtsc50 );
|
||||
|
||||
// The resulting palette
|
||||
xpos = myPhaseShift->getRight() + fontWidth * 2;
|
||||
addPalette(xpos, VBORDER, _w - 2 * 2 - HBORDER - xpos,
|
||||
|
@ -644,6 +655,10 @@ void VideoAudioDialog::loadConfig()
|
|||
handlePaletteChange();
|
||||
colorPalette();
|
||||
|
||||
// Autodetection
|
||||
myDetectPal60->setState(settings.getBool("detectpal60"));
|
||||
myDetectNtsc50->setState(settings.getBool("detectntsc50"));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TV Effects tab
|
||||
// TV Mode
|
||||
|
@ -758,6 +773,10 @@ void VideoAudioDialog::saveConfig()
|
|||
Logger::debug("Saving palette settings...");
|
||||
instance().frameBuffer().tiaSurface().paletteHandler().saveConfig(settings);
|
||||
|
||||
// Autodetection
|
||||
settings.setValue("detectpal60", myDetectPal60->getState());
|
||||
settings.setValue("detectntsc50", myDetectNtsc50->getState());
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TV Effects tab
|
||||
// TV Mode
|
||||
|
@ -893,6 +912,8 @@ void VideoAudioDialog::setDefaults()
|
|||
myTVGamma->setValue(50);
|
||||
handlePaletteChange();
|
||||
handlePaletteUpdate();
|
||||
myDetectPal60->setState(false);
|
||||
myDetectNtsc50->setState(false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ class VideoAudioDialog : public Dialog
|
|||
|
||||
// Palettes
|
||||
PopUpWidget* myTIAPalette{nullptr};
|
||||
CheckboxWidget* myDetectPal60{nullptr};
|
||||
CheckboxWidget* myDetectNtsc50{nullptr};
|
||||
SliderWidget* myPhaseShift{nullptr};
|
||||
SliderWidget* myTVRedScale{nullptr};
|
||||
SliderWidget* myTVRedShift{nullptr};
|
||||
|
|
Loading…
Reference in New Issue