add display format auto-detection from filename (resolves #561)

This commit is contained in:
thrust26 2020-01-24 11:30:46 +01:00
parent c1781e5492
commit 792cbb4ffa
6 changed files with 120 additions and 20 deletions

View File

@ -152,6 +152,8 @@
* Added FC bankswitching for Amiga's Power Play Arcade Video Game Album
* Added auto-detection of display format based on filename.
* Auto-detection of bankswitch scheme by file extension now includes
more human-readable formats (not restricted to DOS 3-char length).
See the documentation for the new names.

View File

@ -300,6 +300,7 @@
including <a href="http://thumbulator.blogspot.ca">partial emulation of the ARM processor</a></li>
<li>Supports cartridge autodetection for almost all bankswitching schemes</li>
<li>Supports using ROM filename extensions to force specific bankswitching schemes</li>
<li>Supports using ROM filename to force specific display formats</li>
<li>Supports Supercharger single-load and multi-load games</li>
<li>Supports ROMs stored in ZIP and GZIP format, as well as the usual raw A26/BIN/ROM formats</li>
<li>Supports property file for setting the properties associated with games</li>
@ -3723,7 +3724,7 @@ Ms Pac-Man (Stella extended codes):
The value of this property must be either <b>Auto</b> or one of the following
(for more information about bank-switching see Kevin Horton's <a href="http://kevtris.org/files/sizes.txt">2600 bankswitching
document</a> or the documentation in each cartridge's source code file) types. Types marked
as (&#185;) do not currently have reliable auto-detection, those marked as (&#178;)
as (&#185;) do currently have no reliable auto-detection, those marked as (&#178;)
are not fully supported in the debugger:
<table cellpadding="2" border="1">
<tr><th>&nbsp;Type&nbsp;</th><th>Description</th><th>File Extension<br>(to force type)</th></tr>
@ -3790,8 +3791,18 @@ Ms Pac-Man (Stella extended codes):
<tr>
<td VALIGN="TOP"><i>Display.Format:</i></td>
<td>Indicates the television format the game was designed for. The value
must be <b>Auto</b>, <b>NTSC</b>, <b>PAL</b>, <b>SECAM</b>, <b>NTSC50</b>,
<b>PAL60</b> or <b>SECAM60</b>.</td>
must be <b>Auto</b> or one of the following. Types marked as (&#185;)
do currently have no reliable auto-detection. A format can be enforced
by using one of the following pattern in the filename.
<table cellpadding="2" border="1">
<tr><th>&nbsp;Format&nbsp;</th><th>Filename Pattern (to force format)</th></tr>
<tr><td>NTSC</td><td>NTSC, NTSC60, NTSC 60, NTSC-60</td></tr>
<tr><td>PAL</td><td>PAL, PAL50, PAL 50, PAL-50</td></tr>
<tr><td>SECAM &#185;</td><td>SECAM, SECAM50, SECAM 50, SECAM-50</td></tr>
<tr><td>NTSC50 &#185;</td><td>NTSC50, NTSC 50, NTSC-50</td></tr>
<tr><td>PAL60 &#185;</td><td>PAL60, PAL 60, PAL-60</td></tr>
<tr><td>SECAM60 &#185;</td><td>SECAM60, SECAM 60, SECAM-60</td></tr>
</table></td>
</tr>
<tr>

View File

@ -119,6 +119,9 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
string autodetected = "";
myDisplayFormat = myProperties.get(PropType::Display_Format);
if (myDisplayFormat == "AUTO")
myDisplayFormat = formatFromFilename();
// Add the real controllers for this system
// This must be done before the debugger is initialized
const string& md5 = myProperties.get(PropType::Cart_MD5);
@ -149,33 +152,28 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
if(myDisplayFormat == "NTSC")
{
myCurrentFormat = 1;
myConsoleTiming = ConsoleTiming::ntsc;
}
else if(myDisplayFormat == "PAL")
{
myCurrentFormat = 2;
myConsoleTiming = ConsoleTiming::pal;
}
else if(myDisplayFormat == "SECAM")
{
myCurrentFormat = 3;
myConsoleTiming = ConsoleTiming::secam;
}
else if(myDisplayFormat == "NTSC50")
{
myCurrentFormat = 4;
myConsoleTiming = ConsoleTiming::ntsc;
}
else if(myDisplayFormat == "PAL60")
{
myCurrentFormat = 5;
myConsoleTiming = ConsoleTiming::pal;
}
else if(myDisplayFormat == "SECAM60")
{
myCurrentFormat = 6;
myConsoleTiming = ConsoleTiming::secam;
}
setConsoleTiming();
setTIAProperties();
@ -213,6 +211,24 @@ Console::~Console()
myOSystem.sound().close();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::setConsoleTiming()
{
if (myDisplayFormat == "NTSC" || myDisplayFormat == "NTSC50")
{
myConsoleTiming = ConsoleTiming::ntsc;
}
else if (myDisplayFormat == "PAL" || myDisplayFormat == "PAL60")
{
myConsoleTiming = ConsoleTiming::pal;
}
else if (myDisplayFormat == "SECAM" || myDisplayFormat == "SECAM60")
{
myConsoleTiming = ConsoleTiming::secam;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::autodetectFrameLayout(bool reset)
{
@ -255,6 +271,48 @@ void Console::redetectFrameLayout()
initializeAudio();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Console::formatFromFilename() const
{
std::map<string, string> Pattern = {
{"NTSC50", "NTSC50"}, {"NTSC 50", "NTSC50"}, {"NTSC-50", "NTSC50"},
{"PAL60", "PAL60"}, {"PAL 60", "PAL60"}, {"PAL-60", "PAL60"},
{"SECAM60", "SECAM60"}, {"SECAM 60", "SECAM60"}, {"SECAM-60", "SECAM60"},
{"NTSC60", "NTSC" }, {"NTSC", "NTSC"}, // also finds "NTSC 60" and "NTSC-60"
{"PAL50", "PAL" }, {"PAL", "PAL"}, // also finds "PAL 50" and "PAL-50"
{"SECAM50", "SECAM"}, {"SECAM", "SECAM"}, // also finds "SECAM 50" and "SECAM-50"
};
string filename = myOSystem.romFile().getNameWithExt(""); // get filename *without* extension
for (const auto& item : Pattern)
{
size_t pos = filename.find(item.first);
if (pos != string::npos)
{
// avoid false positives
if (pos == filename.length() - (item.first).length() || // pattern at the very end
((pos == 0 || isWhiteSpace(filename.at(pos - 1))) && // pattern within withspaces
isWhiteSpace(filename.at(pos + (item.first).length()))))
return item.second;
}
}
// nothing found
return "AUTO";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Console::isWhiteSpace(const char s) const
{
const string WHITESPACES = " _-()[]<>";
for (size_t i = 0; i < WHITESPACES.length(); ++i)
if (s == WHITESPACES[i])
return true;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Console::save(Serializer& out) const
{
@ -331,13 +389,20 @@ void Console::setFormat(uInt32 format)
{
if (myFormatAutodetected) return;
string oldDisplayFormat = myDisplayFormat;
redetectFrameLayout();
myFormatAutodetected = true;
myDisplayFormat = formatFromFilename();
if (myDisplayFormat == "AUTO")
{
redetectFrameLayout();
myFormatAutodetected = true;
autodetected = "*";
message = "Auto-detect mode: " + myDisplayFormat;
}
else
{
message = myDisplayFormat + " mode";
}
saveformat = "AUTO";
autodetected = "*";
myConsoleTiming = myDisplayFormat == "PAL" ? ConsoleTiming::pal : ConsoleTiming::ntsc;
message = "Auto-detect mode: " + myDisplayFormat;
setConsoleTiming();
break;
}
case 1:

View File

@ -327,6 +327,11 @@ class Console : public Serializable, public ConsoleIO
void setTIAProperties();
private:
/**
* Define console timing based on current display format
*/
void setConsoleTiming();
/**
* Dry-run the emulation and detect the frame layout (PAL / NTSC).
*/
@ -337,6 +342,19 @@ class Console : public Serializable, public ConsoleIO
*/
void redetectFrameLayout();
/**
* Determine display format by filename
* Returns "AUTO" if nothing is found
*/
string formatFromFilename() const;
/**
Check if the given character is a whitespace.
@param s Character to check
@return True if whitespace character
*/
bool isWhiteSpace(const char s) const;
/**
Create the audio queue
*/

View File

@ -59,7 +59,7 @@ void KidVid::update()
myBlockIdx = KVBLOCKBITS;
myBlock = 0;
openSampleFile();
cerr << "myTape = " << myTape << endl;
//cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardOne2))
{
@ -68,7 +68,7 @@ cerr << "myTape = " << myTape << endl;
myBlockIdx = KVBLOCKBITS;
myBlock = 0;
openSampleFile();
cerr << "myTape = " << myTape << endl;
//cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardOne3))
{
@ -76,13 +76,13 @@ cerr << "myTape = " << myTape << endl;
{
myTape = 4;
myIdx = KVBLOCKBITS;
cerr << "myTape = " << myTape << endl;
//cerr << "myTape = " << myTape << endl;
}
else /* no, Smurf Save The Day */
{
myTape = 1;
myIdx = 0;
cerr << "myTape = " << myTape << endl;
//cerr << "myTape = " << myTape << endl;
}
myBlockIdx = KVBLOCKBITS;
myBlock = 0;

View File

@ -438,7 +438,11 @@ void GameInfoDialog::loadEmulationProperties(const Properties& props)
if(instance().hasConsole() && myFormat->getSelectedTag().toString() == "AUTO")
{
const string& format = instance().console().about().DisplayFormat;
string label = format.substr(0, format.length() - 1);
string label;
if (format.at(format.length() - 1) == '*')
label = format.substr(0, format.length() - 1);
else
label = format;
myFormatDetected->setLabel(label + " detected");
}
else