mirror of https://github.com/stella-emu/stella.git
add display format auto-detection from filename (resolves #561)
This commit is contained in:
parent
c1781e5492
commit
792cbb4ffa
|
@ -152,6 +152,8 @@
|
||||||
|
|
||||||
* Added FC bankswitching for Amiga's Power Play Arcade Video Game Album
|
* 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
|
* Auto-detection of bankswitch scheme by file extension now includes
|
||||||
more human-readable formats (not restricted to DOS 3-char length).
|
more human-readable formats (not restricted to DOS 3-char length).
|
||||||
See the documentation for the new names.
|
See the documentation for the new names.
|
||||||
|
|
|
@ -300,6 +300,7 @@
|
||||||
including <a href="http://thumbulator.blogspot.ca">partial emulation of the ARM processor</a></li>
|
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 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 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 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 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>
|
<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
|
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
|
(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
|
document</a> or the documentation in each cartridge's source code file) types. Types marked
|
||||||
as (¹) do not currently have reliable auto-detection, those marked as (²)
|
as (¹) do currently have no reliable auto-detection, those marked as (²)
|
||||||
are not fully supported in the debugger:
|
are not fully supported in the debugger:
|
||||||
<table cellpadding="2" border="1">
|
<table cellpadding="2" border="1">
|
||||||
<tr><th> Type </th><th>Description</th><th>File Extension<br>(to force type)</th></tr>
|
<tr><th> Type </th><th>Description</th><th>File Extension<br>(to force type)</th></tr>
|
||||||
|
@ -3790,8 +3791,18 @@ Ms Pac-Man (Stella extended codes):
|
||||||
<tr>
|
<tr>
|
||||||
<td VALIGN="TOP"><i>Display.Format:</i></td>
|
<td VALIGN="TOP"><i>Display.Format:</i></td>
|
||||||
<td>Indicates the television format the game was designed for. The value
|
<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>,
|
must be <b>Auto</b> or one of the following. Types marked as (¹)
|
||||||
<b>PAL60</b> or <b>SECAM60</b>.</td>
|
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> Format </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 ¹</td><td>SECAM, SECAM50, SECAM 50, SECAM-50</td></tr>
|
||||||
|
<tr><td>NTSC50 ¹</td><td>NTSC50, NTSC 50, NTSC-50</td></tr>
|
||||||
|
<tr><td>PAL60 ¹</td><td>PAL60, PAL 60, PAL-60</td></tr>
|
||||||
|
<tr><td>SECAM60 ¹</td><td>SECAM60, SECAM 60, SECAM-60</td></tr>
|
||||||
|
</table></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -119,6 +119,9 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||||
string autodetected = "";
|
string autodetected = "";
|
||||||
myDisplayFormat = myProperties.get(PropType::Display_Format);
|
myDisplayFormat = myProperties.get(PropType::Display_Format);
|
||||||
|
|
||||||
|
if (myDisplayFormat == "AUTO")
|
||||||
|
myDisplayFormat = formatFromFilename();
|
||||||
|
|
||||||
// Add the real controllers for this system
|
// Add the real controllers for this system
|
||||||
// This must be done before the debugger is initialized
|
// This must be done before the debugger is initialized
|
||||||
const string& md5 = myProperties.get(PropType::Cart_MD5);
|
const string& md5 = myProperties.get(PropType::Cart_MD5);
|
||||||
|
@ -149,33 +152,28 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||||
if(myDisplayFormat == "NTSC")
|
if(myDisplayFormat == "NTSC")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 1;
|
myCurrentFormat = 1;
|
||||||
myConsoleTiming = ConsoleTiming::ntsc;
|
|
||||||
}
|
}
|
||||||
else if(myDisplayFormat == "PAL")
|
else if(myDisplayFormat == "PAL")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 2;
|
myCurrentFormat = 2;
|
||||||
myConsoleTiming = ConsoleTiming::pal;
|
|
||||||
}
|
}
|
||||||
else if(myDisplayFormat == "SECAM")
|
else if(myDisplayFormat == "SECAM")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 3;
|
myCurrentFormat = 3;
|
||||||
myConsoleTiming = ConsoleTiming::secam;
|
|
||||||
}
|
}
|
||||||
else if(myDisplayFormat == "NTSC50")
|
else if(myDisplayFormat == "NTSC50")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 4;
|
myCurrentFormat = 4;
|
||||||
myConsoleTiming = ConsoleTiming::ntsc;
|
|
||||||
}
|
}
|
||||||
else if(myDisplayFormat == "PAL60")
|
else if(myDisplayFormat == "PAL60")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 5;
|
myCurrentFormat = 5;
|
||||||
myConsoleTiming = ConsoleTiming::pal;
|
|
||||||
}
|
}
|
||||||
else if(myDisplayFormat == "SECAM60")
|
else if(myDisplayFormat == "SECAM60")
|
||||||
{
|
{
|
||||||
myCurrentFormat = 6;
|
myCurrentFormat = 6;
|
||||||
myConsoleTiming = ConsoleTiming::secam;
|
|
||||||
}
|
}
|
||||||
|
setConsoleTiming();
|
||||||
|
|
||||||
setTIAProperties();
|
setTIAProperties();
|
||||||
|
|
||||||
|
@ -213,6 +211,24 @@ Console::~Console()
|
||||||
myOSystem.sound().close();
|
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)
|
void Console::autodetectFrameLayout(bool reset)
|
||||||
{
|
{
|
||||||
|
@ -255,6 +271,48 @@ void Console::redetectFrameLayout()
|
||||||
initializeAudio();
|
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
|
bool Console::save(Serializer& out) const
|
||||||
{
|
{
|
||||||
|
@ -331,13 +389,20 @@ void Console::setFormat(uInt32 format)
|
||||||
{
|
{
|
||||||
if (myFormatAutodetected) return;
|
if (myFormatAutodetected) return;
|
||||||
|
|
||||||
string oldDisplayFormat = myDisplayFormat;
|
myDisplayFormat = formatFromFilename();
|
||||||
redetectFrameLayout();
|
if (myDisplayFormat == "AUTO")
|
||||||
myFormatAutodetected = true;
|
{
|
||||||
|
redetectFrameLayout();
|
||||||
|
myFormatAutodetected = true;
|
||||||
|
autodetected = "*";
|
||||||
|
message = "Auto-detect mode: " + myDisplayFormat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = myDisplayFormat + " mode";
|
||||||
|
}
|
||||||
saveformat = "AUTO";
|
saveformat = "AUTO";
|
||||||
autodetected = "*";
|
setConsoleTiming();
|
||||||
myConsoleTiming = myDisplayFormat == "PAL" ? ConsoleTiming::pal : ConsoleTiming::ntsc;
|
|
||||||
message = "Auto-detect mode: " + myDisplayFormat;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
@ -327,6 +327,11 @@ class Console : public Serializable, public ConsoleIO
|
||||||
void setTIAProperties();
|
void setTIAProperties();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Define console timing based on current display format
|
||||||
|
*/
|
||||||
|
void setConsoleTiming();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dry-run the emulation and detect the frame layout (PAL / NTSC).
|
* Dry-run the emulation and detect the frame layout (PAL / NTSC).
|
||||||
*/
|
*/
|
||||||
|
@ -337,6 +342,19 @@ class Console : public Serializable, public ConsoleIO
|
||||||
*/
|
*/
|
||||||
void redetectFrameLayout();
|
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
|
Create the audio queue
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -59,7 +59,7 @@ void KidVid::update()
|
||||||
myBlockIdx = KVBLOCKBITS;
|
myBlockIdx = KVBLOCKBITS;
|
||||||
myBlock = 0;
|
myBlock = 0;
|
||||||
openSampleFile();
|
openSampleFile();
|
||||||
cerr << "myTape = " << myTape << endl;
|
//cerr << "myTape = " << myTape << endl;
|
||||||
}
|
}
|
||||||
else if(myEvent.get(Event::KeyboardOne2))
|
else if(myEvent.get(Event::KeyboardOne2))
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,7 @@ cerr << "myTape = " << myTape << endl;
|
||||||
myBlockIdx = KVBLOCKBITS;
|
myBlockIdx = KVBLOCKBITS;
|
||||||
myBlock = 0;
|
myBlock = 0;
|
||||||
openSampleFile();
|
openSampleFile();
|
||||||
cerr << "myTape = " << myTape << endl;
|
//cerr << "myTape = " << myTape << endl;
|
||||||
}
|
}
|
||||||
else if(myEvent.get(Event::KeyboardOne3))
|
else if(myEvent.get(Event::KeyboardOne3))
|
||||||
{
|
{
|
||||||
|
@ -76,13 +76,13 @@ cerr << "myTape = " << myTape << endl;
|
||||||
{
|
{
|
||||||
myTape = 4;
|
myTape = 4;
|
||||||
myIdx = KVBLOCKBITS;
|
myIdx = KVBLOCKBITS;
|
||||||
cerr << "myTape = " << myTape << endl;
|
//cerr << "myTape = " << myTape << endl;
|
||||||
}
|
}
|
||||||
else /* no, Smurf Save The Day */
|
else /* no, Smurf Save The Day */
|
||||||
{
|
{
|
||||||
myTape = 1;
|
myTape = 1;
|
||||||
myIdx = 0;
|
myIdx = 0;
|
||||||
cerr << "myTape = " << myTape << endl;
|
//cerr << "myTape = " << myTape << endl;
|
||||||
}
|
}
|
||||||
myBlockIdx = KVBLOCKBITS;
|
myBlockIdx = KVBLOCKBITS;
|
||||||
myBlock = 0;
|
myBlock = 0;
|
||||||
|
|
|
@ -438,7 +438,11 @@ void GameInfoDialog::loadEmulationProperties(const Properties& props)
|
||||||
if(instance().hasConsole() && myFormat->getSelectedTag().toString() == "AUTO")
|
if(instance().hasConsole() && myFormat->getSelectedTag().toString() == "AUTO")
|
||||||
{
|
{
|
||||||
const string& format = instance().console().about().DisplayFormat;
|
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");
|
myFormatDetected->setLabel(label + " detected");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue