Merge branch 'release/6.0'
|
@ -59,6 +59,14 @@
|
|||
"iostream": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"ostream": "cpp",
|
||||
"__memory": "cpp"
|
||||
"__memory": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"__hash_table": "cpp",
|
||||
"array": "cpp",
|
||||
"queue": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"istream": "cpp",
|
||||
"thread": "cpp",
|
||||
"utility": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
22
Announce.txt
|
@ -9,7 +9,7 @@
|
|||
SSSS ttt eeeee llll llll aaaaa
|
||||
|
||||
===========================================================================
|
||||
Release 5.1.1 for Linux, MacOSX and Windows
|
||||
Release 6.0 for Linux, MacOSX and Windows
|
||||
===========================================================================
|
||||
|
||||
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
|
||||
|
@ -21,30 +21,30 @@ all of your favourite Atari 2600 games again! Stella was originally
|
|||
developed for Linux by Bradford W. Mott, however, it has been ported to a
|
||||
number of other platforms and is currently maintained by Stephen Anthony.
|
||||
|
||||
This is the 5.1.1 release of Stella for Linux, Mac OSX and Windows. The
|
||||
This is the 6.0 release of Stella for Linux, Mac OSX and Windows. The
|
||||
distributions currently available are:
|
||||
|
||||
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
|
||||
Stella-5.1.1-win32.exe (32-bit EXE installer)
|
||||
Stella-5.1.1-x64.exe (64-bit EXE installer)
|
||||
Stella-5.1.1-windows.zip (32/64 bit versions)
|
||||
Stella-6.0-win32.exe (32-bit EXE installer)
|
||||
Stella-6.0-x64.exe (64-bit EXE installer)
|
||||
Stella-6.0-windows.zip (32/64 bit versions)
|
||||
|
||||
(*) Note: Support for Windows XP is problematic on some systems,
|
||||
and will probably be discontinued in a future release.
|
||||
|
||||
* Binary distribution for MacOS X 10.7 and above :
|
||||
Stella-5.1.1-macosx.dmg (64-bit Intel)
|
||||
Stella-6.0-macosx.dmg (64-bit Intel)
|
||||
|
||||
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
|
||||
stella_5.1.1-1_i386.deb
|
||||
stella_5.1.1-1_amd64.deb
|
||||
stella_6.0-1_i386.deb
|
||||
stella_6.0-1_amd64.deb
|
||||
|
||||
* Binary distribution in 32-bit & 64-bit RPM format :
|
||||
stella-5.1.1-2.i386.rpm
|
||||
stella-5.1.1-2.x86_64.rpm
|
||||
stella-6.0-2.i386.rpm
|
||||
stella-6.0-2.x86_64.rpm
|
||||
|
||||
* Source code distribution for all platforms :
|
||||
stella-5.1.1-src.tar.xz
|
||||
stella-6.0-src.tar.xz
|
||||
|
||||
|
||||
Distribution Site
|
||||
|
|
76
Changes.txt
|
@ -17,16 +17,19 @@
|
|||
* Note: because of major TIA sound changes, the state file format has
|
||||
changed, and old state files will not work with this release.
|
||||
|
||||
* New cycle exact audio core based on work by Chris Brenner (crispy); greatly
|
||||
improved audio emulation accuracy (i.e. E.T., Ms. Pacman).
|
||||
* New cycle exact audio core based on work by Chris Brenner (crispy);
|
||||
greatly improved audio emulation accuracy (i.e. E.T., Ms. Pacman).
|
||||
|
||||
* Full rewrite of the audio subsystem; resample TIA output to target sample
|
||||
rate directly in Stella.
|
||||
* Full rewrite of the audio subsystem; resample TIA output to target
|
||||
sample rate directly in Stella.
|
||||
|
||||
* Added option to force stereo sound for all ROMs, or to use the
|
||||
setting on a per-ROM basis.
|
||||
|
||||
* Threading: decouple emulation from frame rendering.
|
||||
|
||||
* Main loop rewritten; emulating speed and timing is now much more faithful
|
||||
(i.e. speed in Pick'n'Pile).
|
||||
* Main loop rewritten; emulating speed and timing is now much more
|
||||
faithful (i.e. speed in Pick'n'Pile).
|
||||
|
||||
* Audio settings replaced with new 'audio.xxx' settings.
|
||||
|
||||
|
@ -40,17 +43,33 @@
|
|||
* UI modernization (new widget look, dialog titles added, dialogs
|
||||
refactored).
|
||||
|
||||
* Fixed excessive CPU usage while in UI modes (ROM launcher, debugger, etc).
|
||||
* Fixed excessive CPU usage while in UI modes (ROM launcher, debugger,
|
||||
etc).
|
||||
|
||||
* The bankswitch scheme can now be forced by naming the ROM with a
|
||||
specific extension (ie: .f8s for F8SC, .fe for FE, etc). The
|
||||
supported extensions are the same as the ones from HarmonyCart and
|
||||
UnoCart.
|
||||
|
||||
* The 'launcherexts' option has been replaced by a true/false option
|
||||
named 'launcherroms', which specifies to show only ROMs or all files
|
||||
in the ROM launcher.
|
||||
|
||||
* Changes in 'Game Properties' dialog
|
||||
- 'Default' button now affects only current tab like in all other dialogs.
|
||||
- 'Display' tab changes are now immediate.
|
||||
- 'Default' button now affects only current tab like in all other
|
||||
dialogs.
|
||||
- 'Display' and 'Console' tab changes are now immediate.
|
||||
- Fixed bug when selecting 'Auto-detect' format for 50Hz ROMs
|
||||
|
||||
* Fixed bug in autodetecting Genesis controllers.
|
||||
|
||||
* The Linux builds now use the system-installed PNG and ZLIB libraries
|
||||
by default.
|
||||
* Fixed bug in reading from settings file with entries that were empty;
|
||||
the parsing was failing. This affected the 'cpurandom' argument; when
|
||||
all options in it were turned off, they were all turned on again during
|
||||
the next program run.
|
||||
|
||||
* Fixed bug with 'hold' events; they are now released a short time after
|
||||
starting a ROM.
|
||||
|
||||
* When starting Stella for the first time, the first ROM selected will
|
||||
determine which path to use by default for subsequent runs.
|
||||
|
@ -61,15 +80,40 @@
|
|||
* Fixed missing TV format update in frame stats dialog when switching
|
||||
display type.
|
||||
|
||||
* For UNIX systems: in the ROM launcher, when using symlinks use the
|
||||
symlink pathname instead of the underlying filesystem pathname.
|
||||
* Fixed missing debug color update when switching display type.
|
||||
|
||||
* 'Fill to scanline' now works for scanlines above current scanline too.
|
||||
|
||||
* The debugger 'uhex' command is now honoured in CDF and BUS schemes.
|
||||
|
||||
* When switching screenmodes, the sound is now paused and later resumed.
|
||||
This fixes popping and cracking sounds apparent on some systems, notably
|
||||
OSX when toggling windowed/fullscreen mode.
|
||||
|
||||
* State file format has been optimized to be smaller, and faster loading
|
||||
and saving. This affects both the files saved to your computer as well
|
||||
as Time Machine functionality.
|
||||
|
||||
* The ROM name saved in a PNG tEXt chunk now honours the 'snapname'
|
||||
setting.
|
||||
|
||||
* Updated PAL palette.
|
||||
|
||||
* Updated included PNG library to latest stable version.
|
||||
* Added 'Cartridge.StartBank' ROM property, to force a ROM to use a
|
||||
specific bank for its reset vector.
|
||||
|
||||
* For better compatibility, the Windows 32-bit version does not requires SSE2
|
||||
anymore.
|
||||
* Added recently released 'Arkyology' prototype ROM to the database.
|
||||
|
||||
* For UNIX systems: in the ROM launcher, when using symlinks use the
|
||||
symlink pathname instead of the underlying filesystem pathname.
|
||||
|
||||
* The UNIX builds now use the system-installed PNG and ZLIB libraries
|
||||
by default.
|
||||
|
||||
* For better compatibility, the Windows 32-bit version does not require
|
||||
SSE2 anymore.
|
||||
|
||||
* Updated included PNG library to latest stable version.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
stella (6.0-1) stable; urgency=high
|
||||
|
||||
* Version 6.0 release
|
||||
|
||||
-- Stephen Anthony <stephena@users.sf.net> TODO
|
||||
|
||||
|
||||
stella (5.1.1-1) stable; urgency=high
|
||||
|
||||
* Version 5.1.1 release
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
|
||||
<center><b><font size="7">Stella</font></b></center>
|
||||
<center><h4><b>Release 5.1.1</b></h4></center>
|
||||
<center><h4><b>Release 6.0</b></h4></center>
|
||||
<center><h1><b>Integrated Debugger</b></h1></center>
|
||||
<center><h4><b>(a work in progress)</b></h4></center>
|
||||
<br>
|
||||
|
@ -1089,11 +1089,8 @@ as illustrated:</p>
|
|||
<p><img src="graphics/debugger_tiaoutcmenu.png"></p>
|
||||
<p>The options are as follows:</p>
|
||||
<ul>
|
||||
<li><b>Fill to scanline</b>: If you've already started a partial frame
|
||||
draw (ie, the frame is already partially 'greyed' out), selecting this
|
||||
option will draw all scanlines up to the vertical position where the
|
||||
mouse was clicked. Note that if you weren't in partial-frame mode,
|
||||
this option will have no effect.</li>
|
||||
<li><b>Fill to scanline</b>: This option will draw all scanlines up to the
|
||||
vertical position where the mouse was clicked.</li>
|
||||
<li><b>Toggle breakpoint</b>: Will toggle a conditional breakpoint at the
|
||||
scanline where the mouse was clicked. You can also use
|
||||
the Prompt Tab commands to list and turn off the breakpoint.</li>
|
||||
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 508 B |
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 788 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
383
docs/index.html
|
@ -26,7 +26,7 @@
|
|||
<ul>
|
||||
<li><a href="#Requirements">Requirements</a></li>
|
||||
<li><a href="#Installation">Installation</a></li>
|
||||
<li><a href="#Games">Locating Game Images (aka, ROMs)</a></li>
|
||||
<li><a href="#Games">Locating Game Images (aka ROMs)</a></li>
|
||||
<li><a href="#Playing">Playing a Game</a></li>
|
||||
<li><a href="#Keyboard">Keyboard Layout</a></li>
|
||||
<li><a href="#Hotkeys">Hotkeys</a></li>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<li><a href="#ROMInfo">ROM Launcher</a></li>
|
||||
<ul>
|
||||
<li><a href="#ROMInfoViewer">ROM Launcher Viewer</a></li>
|
||||
<li><a href="#ROMLauchnerContextMenu">ROM Launcher Context Menu</a></li>
|
||||
<li><a href="#ROMLauncherContextMenu">ROM Launcher Context Menu</a></li>
|
||||
</ul>
|
||||
<li><a href="#ROMAudit">ROM Audit Mode</a></li>
|
||||
<li><a href="#Adaptor">Stelladaptor/2600-daptor Support</a></li>
|
||||
|
@ -252,11 +252,13 @@
|
|||
|
||||
<ul>
|
||||
<li>High speed emulation using optimized C++14 code</li>
|
||||
<li>Supports high quality TIA emulation using the TIA core from
|
||||
<li>Supports high quality TIA emulation using the cycle-exact TIA core from
|
||||
<a href="https://github.com/6502ts/6502.ts">6502.ts</a> by
|
||||
Christian Speckner</li>
|
||||
<li>Supports high quality sound emulation using code derived from Ron Fries'
|
||||
TIA Sound Emulation library, including stereo sound support</li>
|
||||
<li>Supports high quality sound emulation using code derived from Chris Brenner's
|
||||
Atari 2600 FPGA project, including cycle-exact audio, analog interference
|
||||
from mixing of audio channels, as well as stereo sound support; dynamic
|
||||
sound resampling is also included</li>
|
||||
<li>Emulates the Atari 2600 Joystick Controllers using your computer's keyboard,
|
||||
joysticks or mouse</li>
|
||||
<li>Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard</li>
|
||||
|
@ -287,12 +289,13 @@
|
|||
<li>Supports DPC+/CDF bankswitching schemes from the <a href="http://harmony.atariage.com">Harmony Cart</a>,
|
||||
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 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>
|
||||
<li>Supports the NTSC, PAL and SECAM television standards in 50Hz and 60Hz mode</li>
|
||||
<li>Supports autodetection of display format for 50Hz vs. 60Hz modes</li>
|
||||
<li>Supports several "undocumented features" of the TIA graphics chip used by
|
||||
<li>Supports most "undocumented features" of the TIA graphics chip used by
|
||||
some games</li>
|
||||
<li>TIA emulation supports full collision checking, with ability to disable
|
||||
TIA sprites and collisions for each object separately</li>
|
||||
|
@ -333,7 +336,7 @@
|
|||
<li>Joysticks or gamepads are highly recommended</li>
|
||||
<li>Mouse or <a href="http://www.grandideastudio.com/portfolio/stelladaptor-2600">Stelladaptor</a>/<a href="http://2600-daptor.com">2600-daptor</a>
|
||||
with real paddles required for paddle emulation</li>
|
||||
<li>Some ROM images (See <a href="http://www.atariage.com">AtariAge</a> for more information)</li>
|
||||
<li>Some ROM images (see <a href="http://www.atariage.com">AtariAge</a> for more information)</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
@ -460,7 +463,7 @@
|
|||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<h2><b><a name="Games">Locating Game Images (aka, ROMs)</a></b></h2>
|
||||
<h2><b><a name="Games">Locating Game Images (aka ROMs)</a></b></h2>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
|
@ -487,12 +490,11 @@
|
|||
their ROM images</li>
|
||||
|
||||
<li>If you're handy with a soldering iron then you can design and build a
|
||||
device that plugs into the printer port of a PC and read the data from the
|
||||
cartridge</li>
|
||||
device that plugs into a PC and read the data from the cartridge</li>
|
||||
</ul>
|
||||
|
||||
<p><b>WARNING:</b> It is illegal to use ROM images of games that you do not
|
||||
actually own since these games are still copyrighted.</p>
|
||||
<p><b>WARNING:</b> It may be illegal to use ROM images of games that you do not
|
||||
actually own since these games may still be copyrighted.</p>
|
||||
|
||||
<p>
|
||||
<h3><b><u>Supercharger Cassettes</u></b></h3>
|
||||
|
@ -530,8 +532,24 @@
|
|||
<p>Stella supports ROMs ending with extensions .a26, .bin, .rom, .gz, and .zip.
|
||||
For the last two compressed formats (GZIP and ZIP, respectively), Stella will
|
||||
automatically decompress the archive, and use the first ROM image it finds in
|
||||
it (ie, the first one ending in a valid extension).</p>
|
||||
</blockquote>
|
||||
it (ie, the first one ending in a valid extension). If a ZIP archive contains
|
||||
many such files, Stella will display a <i>virtual filesystem</i> of the contents
|
||||
of the archive.</p>
|
||||
|
||||
<p>Other extensions are also possible, namely to force a specific bankswitch scheme.
|
||||
Normally, the bankswitching scheme for a ROM is determined automatically,
|
||||
or manually by setting a <a href="#Properties">ROM property</a>, and you never
|
||||
have to do anything yourself. However, it is also possible to force the
|
||||
bankswitch type to use by adding a special filename extension. These extensions
|
||||
are listed in the <a href="#Properties">ROM properties</a> section under
|
||||
<a href="#PropertiesCartType">Cartridge.Type -> File Extension</a>.</p>
|
||||
|
||||
<p><b>Note:</b> These extensions are the same as those used by the Harmony Cart
|
||||
and Unocart and are not case-sensitive, so you can name your files and have them
|
||||
work across all applications. <u>Again, to be clear, this is only necessary when
|
||||
you want to override the default bankswitching scheme for a ROM.</u> <b>This will
|
||||
not normally be necessary.</b></p>
|
||||
|
||||
|
||||
<h2><b><a name="Playing">Playing a Game</a></b></h2>
|
||||
|
||||
|
@ -549,38 +567,24 @@
|
|||
'ROM Launcher' mode:<br><br>
|
||||
<img src="graphics/launcher.png"></p>
|
||||
|
||||
<p>If this is your first time starting Stella, you will be asked to select the
|
||||
default ROM directory to use. This is where you have all your ROMs,
|
||||
collected as described in the previous section. Several dialogs will be shown, similar
|
||||
to the following:</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="graphics/select_romdir.png"> </td>
|
||||
<td><img src="graphics/rom_browser.png"></td>
|
||||
</tr>
|
||||
<table>
|
||||
|
||||
<p>The browser should be self-explanatory. The 'Go Up' button moves to the parent
|
||||
folder (if it exists), and the 'Base Dir' button moves to the base directory where,
|
||||
by default, all Stella-related files are stored. Double-clicking an item will
|
||||
enter that directory. Click 'Choose' to select the location, or 'Cancel' to exit
|
||||
the browser. Note that if you don't select a ROM directory now, you will be prompted
|
||||
again the next time Stella is started.</p>
|
||||
<p>If this is your first time starting Stella, you may have to navigate to your ROMs.
|
||||
The path of the first ROM you play automatically defines the default ROM path. You
|
||||
can change it later in the <b><a href="#ConfigPaths">Configure Paths</a></b> dialog.
|
||||
</p>
|
||||
|
||||
<p>At this point, you may want to set the locations for snapshots and other
|
||||
external paths. This is described in more detail in
|
||||
<b>Advanced Configuration - <a href="#Snapshots">Snapshot Settings</a></b> and
|
||||
<b>Advanced Configuration - <a href="#ConfigPaths">Config Paths</a></b>.
|
||||
<b>Advanced Configuration - <a href="#ConfigPaths">Configure Paths</a></b>.
|
||||
These settings are optional, and can be left at the defaults if you won't be using
|
||||
snapshots in the ROM launcher.</p>
|
||||
|
||||
<p>Once you've correctly set the default ROM directory, you can start emulation by
|
||||
selecting a ROM and pressing 'Enter' or clicking 'Select', or double-clicking a ROM.
|
||||
Note that some games require you to 'Reset' the console before you start playing. In this
|
||||
case, you need to hit the virtual reset switch, which by default is the F2 key.
|
||||
Also, some games may require that you press the joystick fire button to begin,
|
||||
which by default is the Left Control or Space key(s). If a game uses a
|
||||
more complex controller, see
|
||||
<p>you can start emulation by selecting a ROM and pressing 'Enter' or clicking 'Select',
|
||||
or double-clicking a ROM. Note that some games require you to 'Reset' the console
|
||||
before you start playing. In this case, you need to hit the virtual reset switch,
|
||||
which by default is the F2 key. Also, some games may require that you press the
|
||||
joystick fire button to begin, which by default is the Left Control or Space key(s),
|
||||
or button 0 on your joystick. If a game uses a more complex controller, see
|
||||
<b>Getting Started - <a href="#Keyboard">Keyboard Layout</a></b>
|
||||
for more information. To exit a game and re-enter the ROM launcher, press the 'Escape'
|
||||
key.</p>
|
||||
|
@ -1524,12 +1528,6 @@
|
|||
<td>Shift-Control + f</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Save current game's properties to a separate properties file</td>
|
||||
<td>Control + s</td>
|
||||
<td>Control + s</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Switch mouse between controller emulation modes (see <b>Game Properties - <a href="#Controller">Controller</a></b>)</td>
|
||||
<td>Control + 0</td>
|
||||
|
@ -1794,7 +1792,6 @@
|
|||
</blockquote>
|
||||
|
||||
|
||||
|
||||
<br><br>
|
||||
<p><h2>
|
||||
<a name="TimeMachine">Stella's 'Time Machine'</a></h2>
|
||||
|
@ -1829,13 +1826,14 @@
|
|||
<tr><th>Item</th><th>Description</th></tr>
|
||||
<tr><td>Current time</td><td>Shows the time of the currently selected status,
|
||||
relative to the first one</td></tr>
|
||||
<tr><td>'Start/Stop' button</td><td>Starts or stops the Time Machine</td></tr>
|
||||
<tr><td>'Continue' button</td><td>Exits the dialog and continues emulation</td></tr>
|
||||
<tr><td>'Rewind All' button</td><td>Navigates back to the begin of the timeline</td></tr>
|
||||
<tr><td>'Rewind One' button</td><td>Navigates back by one state</td></tr>
|
||||
<tr><td>'Continue' button</td><td>Exits the dialog and continues emulation.</td></tr>
|
||||
<tr><td>Navigation info</td><td>Informs about the interval of the user's last
|
||||
Time Machine navigation. The interval can vary if the timeline is compressed.</td></tr>
|
||||
<tr><td>'Unwind One' button</td><td>Navigates forward by one state</td></tr>
|
||||
<tr><td>'Unwind All' button</td><td>Navigates forward to the end of the timeline</td></tr>
|
||||
<tr><td>Navigation info</td><td>Informs about the interval of the user's last
|
||||
Time Machine navigation. The interval can vary if the timeline is compressed.</td></tr>
|
||||
<tr><td>Total time</td><td>Shows the total time covered by the save states
|
||||
(aka 'Horizon')</td></tr>
|
||||
</table>
|
||||
|
@ -1844,6 +1842,7 @@
|
|||
<p>The 'Time Machine' mode can be configured by the user. For details see
|
||||
<a href="#Debugger"><b>Developer Options</b> - Time Machine</a></h2> tab.</p>
|
||||
|
||||
|
||||
<!-- ///////////////////////////////////////////////////////////////////////// -->
|
||||
<br><br>
|
||||
<p><h1>
|
||||
|
@ -1904,21 +1903,8 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-framerate <number></pre></td>
|
||||
<td>Display the given number of frames per second. Normally, Stella
|
||||
will determine framerate based on number of scanlines.
|
||||
Setting this to 0 automatically enables auto-frame
|
||||
calculation (ie, framerate based on scanlines).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-timing <sleep|busy></pre></td>
|
||||
<td>Determines type of wait to perform between processing frames.
|
||||
Sleep will release the CPU as much as possible, and is the
|
||||
preferred method on laptops (and other low-powered devices)
|
||||
and when using VSync. Busy will emulate z26 busy-wait
|
||||
behaviour, and use all possible CPU time, but may eliminate
|
||||
graphical 'tearing' in software mode.</td>
|
||||
<td><pre>-speed <number></pre></td>
|
||||
<td>Control the emulation speed (as a percentage, 10 - 1000).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -2196,7 +2182,7 @@
|
|||
|
||||
<tr>
|
||||
<td><pre>-snaploaddir <path></pre></td>
|
||||
<td>The directory to load snapshot files from.</td>
|
||||
<td>The directory to load ROM info viewer snaposhot files from.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -2251,11 +2237,9 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-launcherexts <allfiles|allroms|LIST></pre></td>
|
||||
<td>Specifies which files to show in the ROM launcher
|
||||
('allfiles' is self-explanatory, 'allroms' is all files
|
||||
with valid rom extensions (currently: a26, bin, rom,
|
||||
gz, zip), 'LIST' is a ':' separated list of valid rom extensions.</td>
|
||||
<td><pre>-launcherroms <1|0></pre></td>
|
||||
<td>Specifies whether to show ROMs only (the default) or all
|
||||
files in the ROM launcher.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -2621,20 +2605,19 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Renderer</td><td>Use specified rendering mode</td><td>-video</td></tr>
|
||||
<tr><td>TIA Zoom</td><td>(Integral) zoom level for emulation mode </td><td>-tia.zoom</td></tr>
|
||||
<tr><td>TIA Palette</td><td>Palette for emulation mode</td><td>-palette</td></tr>
|
||||
<tr><td>TIA Inter</td><td>Interpolation for TIA image</td><td>-tia.inter</td></tr>
|
||||
<tr><td>Timing (*)</td><td>How to wait between frames (requires restart)</td><td>-timing</td></tr>
|
||||
<tr><td>NTSC Aspect</td><td>Width of TIA image in NTSC mode</td><td>-tia.aspectn</td></tr>
|
||||
<tr><td>PAL Aspect</td><td>Width of TIA image in PAL mode</td><td>-tia.aspectp</td></tr>
|
||||
<tr><td>Framerate</td><td>Frames per second in emulation mode</td><td>-framerate</td></tr>
|
||||
<tr><td>TIA palette</td><td>Palette for emulation mode</td><td>-palette</td></tr>
|
||||
<tr><td>TIA zoom</td><td>(Integral) zoom level for emulation mode </td><td>-tia.zoom</td></tr>
|
||||
<tr><td>TIA interpolation</td><td>Interpolation for TIA image</td><td>-tia.inter</td></tr>
|
||||
<tr><td>NTSC aspect</td><td>Width of TIA image in NTSC mode</td><td>-tia.aspectn</td></tr>
|
||||
<tr><td>PAL aspect</td><td>Width of TIA image in PAL mode</td><td>-tia.aspectp</td></tr>
|
||||
<tr><td>Emul. speed</td><td>Emulation speed</td><td>-speed</td></tr>
|
||||
<tr><td>Fullscreen</td><td>Self-explanatory</td><td>-fullscreen</td></tr>
|
||||
<tr><td>Fullscreen Fill</td><td>Completely fill TIA image in fullscreen</td><td>-tia.fsfill</td></tr>
|
||||
<tr><td>VSync</td><td>Enable vertical sync'ed updates</td><td>-vsync</td></tr>
|
||||
<tr><td>Fast SC/AR BIOS</td><td>Skip progress loading bars for SuperCharger ROMs</td><td>-fastscbios</td></tr>
|
||||
<tr><td>Fullscreen fill</td><td>Completely fill TIA image in fullscreen</td><td>-tia.fsfill</td></tr>
|
||||
<tr><td>VSync</td><td>Enable vertical synced updates</td><td>-vsync</td></tr>
|
||||
<tr><td>Fast SuperCharger load</td><td>Skip progress loading bars for SuperCharger ROMs</td><td>-fastscbios</td></tr>
|
||||
<tr><td>Show UI messages</td><td>Overlay UI messages onscreen</td><td>-uimessages</td></tr>
|
||||
<tr><td>Center window</td><td>Attempt to center application window</td><td>-center</td></tr>
|
||||
<tr><td>Use multi-threading</td><td>Enable multi-threaded rendering</td><td>-threads</td></tr>
|
||||
<tr><td>Multi-threading</td><td>Enable multi-threaded rendering</td><td>-threads</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -2649,18 +2632,18 @@
|
|||
<td valign="top">
|
||||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>TV Mode</td><td>Disable TV effects, or select TV preset</td><td>-tv.filter</td></tr>
|
||||
<tr><td>TV Phosphor</td><td>Enable phosphor mode under what conditions</td><td>-tv.phosphor</td></tr>
|
||||
<tr><td>Phosphor (Default)</td><td>Default blend level to use in phosphor mode<br/>
|
||||
(needs to be manually set for your particular hardware)</td><td>-tv.phosblend</td></tr>
|
||||
<tr><td>Scanline Intensity</td><td>Sets scanline black-level intensity.</br>
|
||||
Note: No scanlines in 1x mode snapshots.</td><td>-tv.scanlines</td></tr>
|
||||
<tr><td>Scanline Interpolation</td><td>Smooth/blend scanlines into image</td><td>-tv.scaninter</td></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' mode</td><td>-tv.contrast, tv.hue, 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>Default (phosphor)</td><td>Default blend level to use in phosphor mode<br/>
|
||||
(needs to be manually set for your particular hardware)</td><td>-tv.phosblend</td></tr>
|
||||
<tr><td>Scanline intensity</td><td>Sets scanline black-level intensity.</br>
|
||||
Note: No scanlines in 1x mode snapshots.</td><td>-tv.scanlines</td></tr>
|
||||
<tr><td>Scanline interpolation</td><td>Smooth/blend scanlines into image</td><td>-tv.scaninter</td></tr>
|
||||
<tr><td>Clone Composite</td><td>Copy 'Composite' attributes to 'Custom' sliders</td><td> </td></tr>
|
||||
<tr><td>Clone S-Video</td><td>Copy 'S-Video' attributes to 'Custom' sliders</td><td> </td></tr>
|
||||
<tr><td>Clone RGB</td><td>Copy 'RGB' attributes to 'Custom' sliders</td><td> </td></tr>
|
||||
<tr><td>Clone Bad Adjust</td><td>Copy 'Bad Adjust' attributes to 'Custom' sliders</td><td> </td></tr>
|
||||
<tr><td>Clone Bad adjust</td><td>Copy 'Bad Adjust' attributes to 'Custom' sliders</td><td> </td></tr>
|
||||
<tr><td>Revert</td><td>Revert attribute sliders to saved 'Custom' settings</td><td> </td></tr>
|
||||
</table>
|
||||
</td>
|
||||
|
@ -2695,16 +2678,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<p><b>UI Settings</b> dialog (2 tabs):</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
<td><img src="graphics/options_ui.png"></td>
|
||||
<td> </td>
|
||||
<td valign="top"><br>This tab is described in further detail in
|
||||
<b>Advanced Configuration - <a href="#ROMInfo">ROM Launcher</a></b>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<p><b>User Interface Settings</b> dialog (2 tabs):</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
<td><img src="graphics/options_misc.png"><br><br></td>
|
||||
|
@ -2712,8 +2686,8 @@
|
|||
<td valign="top">
|
||||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Interface Palette</td><td>Palette to use for UI elements (see examples)</td><td>-uipalette</td></tr>
|
||||
<tr><td>List quick delay</td><td>Time to wait between keypresses in list-widgets</td><td>-listdelay</td></tr>
|
||||
<tr><td>Theme</td><td>Theme to use for UI elements (see examples)</td><td>-uipalette</td></tr>
|
||||
<tr><td>List input delay</td><td>Maximum delay between keypresses in list-widgets before a search string resets. </td><td>-listdelay</td></tr>
|
||||
<tr><td>Mouse wheel scroll</td><td>Number of lines a mouse scroll will move in list-widgets</td><td>-mscroll</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
|
@ -2725,6 +2699,15 @@
|
|||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
<td><img src="graphics/options_ui.png"></td>
|
||||
<td> </td>
|
||||
<td valign="top"><br>This tab is described in further detail in
|
||||
<b>Advanced Configuration - <a href="#ROMInfo">ROM Launcher</a></b>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<a name="Snapshots"></a>
|
||||
<p><b>Snapshot Settings</b> dialog:</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
|
@ -2735,7 +2718,7 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Save path</td><td>Specifies where to save snapshots</td><td>-snapsavedir</td></tr>
|
||||
<tr><td>Load path</td><td>Specifies where to load snapshots</td><td>-snaploaddir</td></tr>
|
||||
<!--<tr><td>Load path</td><td>Specifies where to load snapshots</td><td>-snaploaddir</td></tr> -->
|
||||
<tr><td>Continuous snapshot interval</td><td>Interval (in seconds) between snapshots</td><td>-ssinterval</td></tr>
|
||||
<tr><td>Use actual ROM name</td><td>Use the actual ROM filename instead of the internal database name.</td><td>-snapname</td></tr>
|
||||
<tr><td>Overwrite existing files</td><td>Whether to overwrite old snapshots</td><td>-sssingle</td></tr>
|
||||
|
@ -2746,7 +2729,7 @@
|
|||
</table>
|
||||
<br>
|
||||
<a name="ConfigPaths"></a>
|
||||
<p><b>Config Paths</b> dialog:</p>
|
||||
<p><b>Configure Paths</b> dialog:</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
<td><img src="graphics/launcher_options_files.png"></td>
|
||||
|
@ -2853,7 +2836,6 @@
|
|||
<td valign="top">
|
||||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Stelladaptor port order</td><td>Specifies which virtual port each Stelladaptor/2600-daptor uses (See <b>Advanced Configuration - <a href="#Adaptor">Stelladaptor/2600-daptor Support</a></b>)</td><td>-saport</td></tr>
|
||||
<tr><td>Use mouse as ...</td><td>Allow the mouse to emulate various controllers</td><td>-usemouse</td></tr>
|
||||
<tr><td>Mouse cursor visibility</td><td>Show/hide cursor depending on current state</td><td>-cursor</td></tr>
|
||||
<tr><td>Joystick deadzone size</td><td>Deadzone area for axes on joysticks/gamepads</td><td>-joydeadzone</td></tr>
|
||||
|
@ -2863,8 +2845,9 @@
|
|||
<tr><td>Allow all 4 directions ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
|
||||
<tr><td>Grab mouse ...</td><td>Keep mouse in window in emulation mode<br/>(only when used as controller)<br/>
|
||||
Note: The sensitivity may greatly vary when the mouse is not grabbed.</td><td>-grabmouse</td></tr>
|
||||
<tr><td>Use Control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>
|
||||
<tr><td>Joystick Database</td><td>Show all joysticks that Stella knows about, with the option to remove them</td><td> </td></tr>
|
||||
<tr><td>Use control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>
|
||||
<tr><td>Swap Stelladaptor ports</td><td>Swap the order of the detected Stelladaptors/2600-daptors (see <b>Advanced Configuration - <a href="#Adaptor">Stelladaptor/2600-daptor Support</a></b>)</td><td>-saport</td></tr>
|
||||
<tr><td>Joystick database</td><td>Show all joysticks that Stella knows about, with the option to remove them</td><td> </td></tr>
|
||||
<tr><td>Erase EEPROM</td><td>Erase the whole AtariVox/SaveKey flash memory</td><td> </td></tr>
|
||||
<tr><td>AVox serial port</td><td>Described in further detail in <b>Advanced Configuration - <a href="#AtariVox">AtariVox/SaveKey Support</a></b> </td><td>-avoxport</td></tr>
|
||||
</table>
|
||||
|
@ -2913,7 +2896,7 @@
|
|||
<p>ROM Info Viewer in 1x mode, UI sized 1000x760, medium launcher font:</p>
|
||||
<img src="graphics/rominfo_1x_large.png">
|
||||
|
||||
<p>ROM Info Viewer in 2x mode, UI sized 1400x900, large launcher font:</p>
|
||||
<p>ROM Info Viewer in 2x mode, UI sized 1280x900, large launcher font:</p>
|
||||
<img src="graphics/rominfo_2x_small.png">
|
||||
|
||||
<p>The text box in the upper right corner can be used to narrow down the
|
||||
|
@ -2926,7 +2909,7 @@
|
|||
case sensitive, so you don't need to worry about capital or lower-case
|
||||
letters.</p>
|
||||
|
||||
<h3><b><a name="ROMLauchnerContextMenu">ROM Lauchner Context Menu</a></b></h3>
|
||||
<h3><b><a name="ROMLauncherContextMenu">ROM Launcher Context Menu</a></b></h3>
|
||||
|
||||
<p>The ROM launcher also contains a context menu, selected by clicking the
|
||||
right mouse button anywhere in the current window. This context menu
|
||||
|
@ -2938,7 +2921,7 @@
|
|||
temporarily held down. Selecting options from this dialog will cause all ROMs launched
|
||||
after that to use those properties you specify. Clicking <b>Defaults</b> will disable
|
||||
its functionality, and use ROM properties as defined by the ROM itself. The dialog is as
|
||||
follows (See <b>Advanced Configuration - <a href="#Properties">Game Properties</a></b>
|
||||
follows (see <b>Advanced Configuration - <a href="#Properties">Game Properties</a></b>
|
||||
for more information concerning ROM properties):</p>
|
||||
<table border="5" cellpadding="2" frame="box" rules="none">
|
||||
<tr>
|
||||
|
@ -2948,12 +2931,12 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>For more information,<br>see <a href="#CommandLine">Commandline</a></th></tr>
|
||||
<tr><td>Bankswitch type</td><td>-bs</td></tr>
|
||||
<tr><td>Left Difficulty</td><td>-ld</td></tr>
|
||||
<tr><td>Right Difficulty</td><td>-rd</td></tr>
|
||||
<tr><td>TV Type</td><td>-tv</td></tr>
|
||||
<tr><td>Startup Mode</td><td>-debug</td></tr>
|
||||
<tr><td>Left Joy items</td><td>-holdjoy0</td></tr>
|
||||
<tr><td>Right Joy items</td><td>-holdjoy1</td></tr>
|
||||
<tr><td>TV type</td><td>-tv</td></tr>
|
||||
<tr><td>Left difficulty</td><td>-ld</td></tr>
|
||||
<tr><td>Right difficulty</td><td>-rd</td></tr>
|
||||
<tr><td>Startup mode</td><td>-debug</td></tr>
|
||||
<tr><td>Left joy items</td><td>-holdjoy0</td></tr>
|
||||
<tr><td>Right joy items</td><td>-holdjoy1</td></tr>
|
||||
<tr><td>Console: Select</td><td>-holdselect</td></tr>
|
||||
<tr><td>Console: Reset</td><td>-holdreset</td></tr>
|
||||
</table>
|
||||
|
@ -2963,23 +2946,14 @@
|
|||
</table>
|
||||
</li>
|
||||
|
||||
<li><p><b>Filter listing</b>: Selecting this option shows a dialog whereby
|
||||
one can filter the types of files shown in the listing. The dialog is as
|
||||
follows:</p>
|
||||
<p><img src="graphics/launcher_filter.png"></p>
|
||||
<p>Currently, the choices are as follows:</p>
|
||||
<p><ul>
|
||||
<li><b>All files</b> - self explanatory, show all files in the ROM
|
||||
listing. This is the default, and emulates the behaviour of
|
||||
all previous versions of Stella.</li>
|
||||
<li><b>All roms</b> - show only files with a valid ROM extension.
|
||||
Currently, this means extensions .a26, .bin, .rom, .gz, .zip.</li>
|
||||
<li><b>ROMs ending with</b> - show only files with a ROM extension
|
||||
as selected from the checkboxes.</li>
|
||||
</ul></p>
|
||||
</li>
|
||||
|
||||
<li><b>Reload listing</b>: Selecting this performs a reload of the
|
||||
<br><li><b>Show only ROM files</b>: Selecting this reloads the current listing,
|
||||
showing only files that have a valid ROM extension.</li>
|
||||
|
||||
<br><li><b>Show all files</b>: Selecting this reloads the current listing,
|
||||
showing <i>all</i> files (with no restriction on file name).</li>
|
||||
|
||||
<br><li><b>Reload listing</b>: Selecting this performs a reload of the
|
||||
current listing. It is an alternative to pressing the Control-r
|
||||
key combo.</li>
|
||||
</ol></p>
|
||||
|
@ -3010,9 +2984,9 @@
|
|||
don't use this function. There is no undo feature, and one won't be
|
||||
added.</li>
|
||||
<li>Only filenames that Stella considers to be valid ROMs will be
|
||||
considered. Currently, this means files that end in '.a26',
|
||||
'.bin', '.rom', '.gz' and '.zip'. Files which don't have these
|
||||
extensions will be ignored.</li>
|
||||
considered. Currently, this means files with extensions described in
|
||||
"Supported File formats". Files which don't have these extensions will
|
||||
be ignored.</li>
|
||||
<li>If a valid ROM doesn't have a properties entry, it will be
|
||||
ignored.</li>
|
||||
</ul>
|
||||
|
@ -3079,7 +3053,7 @@
|
|||
|
||||
<p>The location of the EEPROM files are configurable through the
|
||||
'<i>-nvramdir</i>' commandline argument and within the application itself
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Config Paths</a></b>).
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Configure Paths</a></b>).
|
||||
If the path for these files hasn't been set, the default location will depend on the
|
||||
version of Stella, as follows:</p>
|
||||
|
||||
|
@ -3130,8 +3104,8 @@
|
|||
<table border="1" cellpadding="4">
|
||||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Player/Developer settings</td><td>Selects the active settings set</td><td>-dev.settings</td></tr>
|
||||
<tr><td>Frame Statistics</td><td>Overlay console info on the TIA image during emulation.</td><td>-plr.stats<br/>-dev.stats</td></tr>
|
||||
<tr><td>Console</td><td>Select the console type, this affects Color/B&W/Pause key emulation and zero-page RAM initialzation</td><td>-plr.console <br/>-dev.console</td></tr>
|
||||
<tr><td>Console info overlay</td><td>Overlay console info on the TIA image during emulation.</td><td>-plr.stats<br/>-dev.stats</td></tr>
|
||||
<tr><td>Console</td><td>Select the console type, this affects Color/B&W/Pause key emulation and zero-page RAM initialization</td><td>-plr.console <br/>-dev.console</td></tr>
|
||||
<tr><td>Random startup bank</td><td>Randomize the startup bank (only for selected bankswitch types)</td><td>-plr.bankrandom<br/>-dev.bankrandom</td></tr>
|
||||
<tr><td>Randomize zero-page ...</td><td>When loading a ROM, randomize all RAM content instead of initializing with all zeroes (for 'Console' = 'Atari 2600' only)</td><td>-plr.ramrandom<br/>-dev.ramrandom</td></tr>
|
||||
<tr><td>Randomize CPU</td><td>When loading a ROM, randomize the content of the specified CPU registers</td><td>-plr.cpurandom<br/>-dev.cpurandom</td></tr>
|
||||
|
@ -3219,7 +3193,7 @@
|
|||
will be compressed (*). This means that more and more intermediate
|
||||
states will be removed and the interval between save states
|
||||
becomes larger the further they are back in time.<br>
|
||||
(*) Compresion only works if 'Uncompressed size' is smaller than
|
||||
(*) Compression only works if 'Uncompressed size' is smaller than
|
||||
'Buffer size'.
|
||||
</td>
|
||||
<td>-plr.tm.horizon<br>-dev.tm.horizon</td>
|
||||
|
@ -3240,7 +3214,7 @@
|
|||
<tr><td>Font size</td><td>Self-explanatory</td><td>-dbg.fontsize</td></tr>
|
||||
<tr><td>Font style</td><td>Self-explanatory</td><td>-dbg.fontstyle</td></tr>
|
||||
<tr><td>Debugger width/height</td><td>Self-explanatory</td><td>-dbg.res</td></tr>
|
||||
<tr><td>Trap on 'ghost' reads</td><td>Defines whether the debugger should consider CPU 'ghost' reads for trap adresses.</td><td><span style="white-space:nowrap">-dbg.ghostreadstrap</span></td></tr>
|
||||
<tr><td>Trap on 'ghost' reads</td><td>Defines whether the debugger should consider CPU 'ghost' reads for trap addresses.</td><td><span style="white-space:nowrap">-dbg.ghostreadstrap</span></td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -3264,7 +3238,7 @@
|
|||
frames per second, bankswitch and display formats, etc. The following shows
|
||||
an example of this information:
|
||||
<p><img src="graphics/developer_stats.png"></p>
|
||||
<p>The two lines of output describe the following:
|
||||
<p>The three lines of output describe the following:
|
||||
<ol>
|
||||
<li>Number of scanlines in current frame, associated framerate, and
|
||||
resulting display format. Note that the framerate shown is the
|
||||
|
@ -3272,6 +3246,8 @@
|
|||
number of scanlines). If the '*' character is present, it means
|
||||
the display format was auto-detected as shown. For the given example,
|
||||
the format was auto-detected as 'NTSC'.</li>
|
||||
<li>Effective emulation speed displayed as frames per second and user
|
||||
defined emulation speed displayed as percentage relative to normal speed.</li>
|
||||
<li>Cartridge information. If the '*' character is present,
|
||||
it means the bankswitch format was auto-detected as shown. The item
|
||||
in round brackets indicates ROM size. For the given example,
|
||||
|
@ -3424,7 +3400,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
|
||||
<p>The name of the cheat database file is configurable through the
|
||||
'<i>-cheatfile</i>' commandline argument and within the application itself
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Config Paths</a></b>). If the
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Configure Paths</a></b>). If the
|
||||
path for this file hasn't been set, the default filename will depend on the
|
||||
version of Stella, as follows:</p>
|
||||
|
||||
|
@ -3576,7 +3552,12 @@ Ms Pac-Man (Stella extended codes):
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN="TOP"><i>Cartridge.Type:</i></td>
|
||||
<td VALIGN="TOP"><i>Cartridge.StartBank:</i></td>
|
||||
<td>Indicates which bank to use for reading the reset vector.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN="TOP"><a name="PropertiesCartType"><i>Cartridge.Type:</i></a></td>
|
||||
<td>Indicates the bank-switching type for the game.
|
||||
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
|
||||
|
@ -3584,62 +3565,68 @@ Ms Pac-Man (Stella extended codes):
|
|||
as (¹) do not currently have reliable auto-detection, those marked as (²)
|
||||
are not fully supported in the debugger:
|
||||
<table cellpadding="2" border="1">
|
||||
<tr><th> Type </th><th>Description</th></tr>
|
||||
<tr><td>0840 </td><td>8K ECONObanking </td></tr>
|
||||
<tr><td>2IN1 ¹</td><td>4-32K Multicart (2 games) </td></tr>
|
||||
<tr><td>4IN1 ¹</td><td>8-32K Multicart (4 games) </td></tr>
|
||||
<tr><td>8IN1 ¹</td><td>16-64K Multicart (8 games) </td></tr>
|
||||
<tr><td>16IN1 ¹</td><td>32-128K Multicart (16 games) </td></tr>
|
||||
<tr><td>32IN1 ¹</td><td>64-128K Multicart (32 games) </td></tr>
|
||||
<tr><td>64IN1 ¹</td><td>64/128K Multicart </td></tr>
|
||||
<tr><td>128IN1 ¹</td><td>256/512K Multicart </td></tr>
|
||||
<tr><td>2K </td><td>64-2048 byte Atari </td></tr>
|
||||
<tr><td>3E </td><td>32K Tigervision </td></tr>
|
||||
<tr><td>3E+ </td><td>3E+ (TJ modified DASH) </td></tr>
|
||||
<tr><td>3F </td><td>512K Tigervision </td></tr>
|
||||
<tr><td>4A50 ²</td><td>64K 4A50 + ram </td></tr>
|
||||
<tr><td>4K </td><td>4K Atari </td></tr>
|
||||
<tr><td>4KSC </td><td>CPUWIZ 4K + ram </td></tr>
|
||||
<tr><td>AR </td><td>Supercharger </td></tr>
|
||||
<tr><td>BF </td><td>CPUWIZ 256K </td></tr>
|
||||
<tr><td>BFSC </td><td>CPUWIZ 256K + ram</td></tr>
|
||||
<tr><td>BUS </td><td>Experimental</td></tr>
|
||||
<tr><td>CDF </td><td>Chris, Darrell, Fred</td></tr>
|
||||
<tr><td>CM ¹</td><td>Spectravideo CompuMate </td></tr>
|
||||
<tr><td>CTY ¹²</td><td>CDW - Chetiry </td></tr>
|
||||
<tr><td>CV </td><td>Commavid extra ram </td></tr>
|
||||
<tr><td>CV+ </td><td>Extended Commavid extra ram</td></tr>
|
||||
<tr><td>DASH </td><td>Boulder Dash 2 </td></tr>
|
||||
<tr><td>DF </td><td>CPUWIZ 128K </td></tr>
|
||||
<tr><td>DFSC </td><td>CPUWIZ 128K + ram</td></tr>
|
||||
<tr><td>DPC </td><td>Pitfall II </td></tr>
|
||||
<tr><td>DPC+</td><td>Enhanced DPC </td></tr>
|
||||
<tr><td>E0 </td><td>8K Parker Bros </td></tr>
|
||||
<tr><td>E7 </td><td>16K M-network </td></tr>
|
||||
<tr><td>E78K </td><td>8K M-network </td></tr>
|
||||
<tr><td>EF </td><td>64K Homestar Runner </td></tr>
|
||||
<tr><td>EFSC </td><td>64K Homestar Runner + ram</td></tr>
|
||||
<tr><td>F0 </td><td>Dynacom Megaboy </td></tr>
|
||||
<tr><td>F4 </td><td>32K Atari </td></tr>
|
||||
<tr><td>F4SC </td><td>32K Atari + ram </td></tr>
|
||||
<tr><td>F6 </td><td>16K Atari </td></tr>
|
||||
<tr><td>F6SC </td><td>16K Atari + ram </td></tr>
|
||||
<tr><td>F8 </td><td>8K Atari </td></tr>
|
||||
<tr><td>F8SC </td><td>8K Atari + ram </td></tr>
|
||||
<tr><td>FA </td><td>CBS RAM Plus </td></tr>
|
||||
<tr><td>FA2 </td><td>CBS RAM Plus 24/28K </td></tr>
|
||||
<tr><td>FE </td><td>8K Decathlon </td></tr>
|
||||
<tr><td>MDM </td><td>Menu Driven Megacart </td></tr>
|
||||
<tr><td>SB </td><td>128-256k SUPERbanking </td></tr>
|
||||
<tr><td>UA </td><td>8K UA Ltd. </td></tr>
|
||||
<tr><td>WD </td><td>Wickstead Design </td></tr>
|
||||
<tr><td>X07 ¹</td><td>64K AtariAge </td></tr>
|
||||
<tr><th> Type </th><th>Description</th><th>File Extension<br>(to force type)</th></tr>
|
||||
<tr><td>0840 </td><td>8K ECONObanking </td><td>.084 </td></tr>
|
||||
<tr><td>2IN1 ¹</td><td>4-32K Multicart (2 games) </td><td>.2N1 </td></tr>
|
||||
<tr><td>4IN1 ¹</td><td>8-32K Multicart (4 games) </td><td>.4N1 </td></tr>
|
||||
<tr><td>8IN1 ¹</td><td>16-64K Multicart (8 games) </td><td>.8N1 </td></tr>
|
||||
<tr><td>16IN1 ¹</td><td>32-128K Multicart (16 games) </td><td>.16N </td></tr>
|
||||
<tr><td>32IN1 ¹</td><td>64-128K Multicart (32 games) </td><td>.32N </td></tr>
|
||||
<tr><td>64IN1 ¹</td><td>64/128K Multicart </td><td>.64N </td></tr>
|
||||
<tr><td>128IN1 ¹</td><td>256/512K Multicart </td><td>.128 </td></tr>
|
||||
<tr><td>2K </td><td>64-2048 byte Atari </td><td>.2K </td></tr>
|
||||
<tr><td>3E </td><td>32K Tigervision </td><td>.3E </td></tr>
|
||||
<tr><td>3E+ </td><td>3E+ (TJ modified DASH) </td><td>.3EP </td></tr>
|
||||
<tr><td>3F </td><td>512K Tigervision </td><td>.3F </td></tr>
|
||||
<tr><td>4A50 ²</td><td>64K 4A50 + ram </td><td>.4A5 </td></tr>
|
||||
<tr><td>4K </td><td>4K Atari </td><td>.4K </td></tr>
|
||||
<tr><td>4KSC </td><td>CPUWIZ 4K + ram </td><td>.4KS </td></tr>
|
||||
<tr><td>AR </td><td>Supercharger </td><td>.AR </td></tr>
|
||||
<tr><td>BF </td><td>CPUWIZ 256K </td><td>.BF </td></tr>
|
||||
<tr><td>BFSC </td><td>CPUWIZ 256K + ram</td><td>.BFS </td></tr>
|
||||
<tr><td>BUS </td><td>Experimental</td><td>.BUS </td></tr>
|
||||
<tr><td>CDF </td><td>Chris, Darrell, Fred</td><td>.CDF </td></tr>
|
||||
<tr><td>CM ¹</td><td>Spectravideo CompuMate </td><td>.CM </td></tr>
|
||||
<tr><td>CTY ¹²</td><td>CDW - Chetiry </td><td>.CTY </td></tr>
|
||||
<tr><td>CV </td><td>Commavid extra ram </td><td>.CV </td></tr>
|
||||
<tr><td>CV+ </td><td>Extended Commavid extra ram</td><td>.CVP </td></tr>
|
||||
<tr><td>DASH </td><td>Boulder Dash 2 </td><td>.DAS </td></tr>
|
||||
<tr><td>DF </td><td>CPUWIZ 128K </td><td>.DF </td></tr>
|
||||
<tr><td>DFSC </td><td>CPUWIZ 128K + ram</td><td>.DFS </td></tr>
|
||||
<tr><td>DPC </td><td>Pitfall II </td><td>.DPC </td></tr>
|
||||
<tr><td>DPC+</td><td>Enhanced DPC </td><td>.DPP </td></tr>
|
||||
<tr><td>E0 </td><td>8K Parker Bros </td><td>.E0 </td></tr>
|
||||
<tr><td>E7 </td><td>16K M-network </td><td>.E7 </td></tr>
|
||||
<tr><td>E78K </td><td>8K M-network </td><td>.E78 </td></tr>
|
||||
<tr><td>EF </td><td>64K Homestar Runner </td><td>.EF </td></tr>
|
||||
<tr><td>EFSC </td><td>64K Homestar Runner + ram</td><td>.EFS </td></tr>
|
||||
<tr><td>F0 </td><td>Dynacom Megaboy </td><td>.F0 </td></tr>
|
||||
<tr><td>F4 </td><td>32K Atari </td><td>.F4 </td></tr>
|
||||
<tr><td>F4SC </td><td>32K Atari + ram </td><td>.F4S </td></tr>
|
||||
<tr><td>F6 </td><td>16K Atari </td><td>.F6 </td></tr>
|
||||
<tr><td>F6SC </td><td>16K Atari + ram </td><td>.F6S </td></tr>
|
||||
<tr><td>F8 </td><td>8K Atari </td><td>.F8 </td></tr>
|
||||
<tr><td>F8SC </td><td>8K Atari + ram </td><td>.F8S </td></tr>
|
||||
<tr><td>FA </td><td>CBS RAM Plus </td><td>.FA </td></tr>
|
||||
<tr><td>FA2 </td><td>CBS RAM Plus 24/28K </td><td>.FA2 </td></tr>
|
||||
<tr><td>FE </td><td>8K Decathlon </td><td>.FE </td></tr>
|
||||
<tr><td>MDM </td><td>Menu Driven Megacart </td><td>.MDM </td></tr>
|
||||
<tr><td>SB </td><td>128-256k SUPERbanking </td><td>.SB </td></tr>
|
||||
<tr><td>UA </td><td>8K UA Ltd. </td><td>.UA </td></tr>
|
||||
<tr><td>WD </td><td>Wickstead Design </td><td>.WD </td></tr>
|
||||
<tr><td>X07 ¹</td><td>64K AtariAge </td><td>.X07 </td></tr>
|
||||
</table></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a><img src="graphics/options_gameinfo_console.png"></a>
|
||||
<table CELLSPACING="10">
|
||||
<tr>
|
||||
<td VALIGN="TOP"><i>Console.TelevisionType:</i></td>
|
||||
<td>Indicates the default television setting for the
|
||||
game. The value must be <b>Color</b> or <b>BW</b>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN="TOP"><i>Console.LeftDifficulty:</i></td>
|
||||
<td>Indicates the default difficulty setting for the left
|
||||
|
@ -3651,12 +3638,6 @@ Ms Pac-Man (Stella extended codes):
|
|||
<td>Indicates the default difficulty setting for the
|
||||
right player. The value must be <b>A</b> or <b>B</b>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN="TOP"><i>Console.TelevisionType:</i></td>
|
||||
<td>Indicates the default television setting for the
|
||||
game. The value must be <b>Color</b> or <b>BW</b>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a name="Controller"><img src="graphics/options_gameinfo_controller.png"></a>
|
||||
|
@ -3684,8 +3665,6 @@ Ms Pac-Man (Stella extended codes):
|
|||
<tr><td>CompuMate </td><td>Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).</td></tr>
|
||||
<tr><td>Mindlink </td><td>Mindlink controller.</td></tr>
|
||||
</table></td>
|
||||
|
||||
https://atariage.com/2600/programming/atarivox_mem_list.html
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -3777,7 +3756,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
-->
|
||||
<p>The name of the properties file is configurable through the
|
||||
'<i>-propsfile</i>' commandline argument and within the application itself
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Config Paths</a></b>). If the
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Configure Paths</a></b>). If the
|
||||
path for this file hasn't been set, the default filename will depend on the
|
||||
version of Stella, as follows:</p>
|
||||
|
||||
|
@ -3842,7 +3821,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
|
||||
<p>The name of the palette file is configurable through the
|
||||
'<i>-palettefile</i>' commandline argument and within the application itself
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Config Paths</a></b>). If the
|
||||
(see <b>Advanced Configuration - <a href="#ConfigPaths">Configure Paths</a></b>). If the
|
||||
path for this file hasn't been set, the default filename will depend on the
|
||||
version of Stella, as follows:</p>
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ BankRomCheat::BankRomCheat(OSystem& os, const string& name, const string& code)
|
|||
|
||||
bank = unhex(myCode.substr(0, 2));
|
||||
address = 0xf000 + unhex(myCode.substr(2, 3));
|
||||
value = unhex(myCode.substr(5, 2));
|
||||
count = unhex(myCode.substr(7, 1)) + 1;
|
||||
value = uInt8(unhex(myCode.substr(5, 2)));
|
||||
count = uInt8(unhex(myCode.substr(7, 1)) + 1);
|
||||
|
||||
// Back up original data; we need this if the cheat is ever disabled
|
||||
for(int i = 0; i < count; ++i)
|
||||
|
|
|
@ -42,7 +42,7 @@ bool CheatManager::add(const string& name, const string& code,
|
|||
return false;
|
||||
|
||||
// Delete duplicate entries
|
||||
for(uInt32 i = 0; i < myCheatList.size(); i++)
|
||||
for(uInt32 i = 0; i < myCheatList.size(); ++i)
|
||||
{
|
||||
if(myCheatList[i]->name() == name || myCheatList[i]->code() == code)
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ void CheatManager::addPerFrame(const string& name, const string& code, bool enab
|
|||
// Make sure there are no duplicates
|
||||
bool found = false;
|
||||
uInt32 i;
|
||||
for(i = 0; i < myPerFrameList.size(); i++)
|
||||
for(i = 0; i < myPerFrameList.size(); ++i)
|
||||
{
|
||||
if(myPerFrameList[i]->code() == cheat->code())
|
||||
{
|
||||
|
@ -291,7 +291,7 @@ void CheatManager::loadCheats(const string& md5sum)
|
|||
void CheatManager::saveCheats(const string& md5sum)
|
||||
{
|
||||
ostringstream cheats;
|
||||
for(uInt32 i = 0; i < myCheatList.size(); i++)
|
||||
for(uInt32 i = 0; i < myCheatList.size(); ++i)
|
||||
{
|
||||
cheats << myCheatList[i]->name() << ":"
|
||||
<< myCheatList[i]->code() << ":"
|
||||
|
|
|
@ -37,7 +37,7 @@ using CheatList = vector<shared_ptr<Cheat>>;
|
|||
class CheatManager
|
||||
{
|
||||
public:
|
||||
CheatManager(OSystem& osystem);
|
||||
explicit CheatManager(OSystem& osystem);
|
||||
|
||||
/**
|
||||
Adds the specified cheat to an internal list.
|
||||
|
|
|
@ -25,8 +25,8 @@ CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
|
|||
: Cheat(os, name, code)
|
||||
{
|
||||
address = 0xf000 + unhex(code.substr(0, 3));
|
||||
value = unhex(code.substr(3, 2));
|
||||
count = unhex(code.substr(5, 1)) + 1;
|
||||
value = uInt8(unhex(code.substr(3, 2)));
|
||||
count = uInt8(unhex(code.substr(5, 1)) + 1);
|
||||
|
||||
// Back up original data; we need this if the cheat is ever disabled
|
||||
for(int i = 0; i < count; ++i)
|
||||
|
|
|
@ -27,13 +27,14 @@ AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo)
|
|||
myFragmentQueue(capacity),
|
||||
myAllFragments(capacity + 2),
|
||||
mySize(0),
|
||||
myNextFragment(0)
|
||||
myNextFragment(0),
|
||||
myIgnoreOverflows(true)
|
||||
{
|
||||
const uInt8 sampleSize = myIsStereo ? 2 : 1;
|
||||
|
||||
myFragmentBuffer = make_unique<Int16[]>(myFragmentSize * sampleSize * (capacity + 2));
|
||||
|
||||
for (uInt32 i = 0; i < capacity; i++)
|
||||
for (uInt32 i = 0; i < capacity; ++i)
|
||||
myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() + i * sampleSize * myFragmentSize;
|
||||
|
||||
myAllFragments[capacity] = myFirstFragmentForEnqueue =
|
||||
|
@ -85,13 +86,13 @@ Int16* AudioQueue::enqueue(Int16* fragment)
|
|||
return newFragment;
|
||||
}
|
||||
|
||||
const uInt8 capacity = myFragmentQueue.size();
|
||||
const uInt8 capacity = uInt8(myFragmentQueue.size());
|
||||
const uInt8 fragmentIndex = (myNextFragment + mySize) % capacity;
|
||||
|
||||
newFragment = myFragmentQueue.at(fragmentIndex);
|
||||
myFragmentQueue.at(fragmentIndex) = fragment;
|
||||
|
||||
if (mySize < capacity) mySize++;
|
||||
if (mySize < capacity) ++mySize;
|
||||
else {
|
||||
myNextFragment = (myNextFragment + 1) % capacity;
|
||||
if (!myIgnoreOverflows) (cerr << "audio buffer overflow\n").flush();
|
||||
|
@ -117,7 +118,7 @@ Int16* AudioQueue::dequeue(Int16* fragment)
|
|||
Int16* nextFragment = myFragmentQueue.at(myNextFragment);
|
||||
myFragmentQueue.at(myNextFragment) = fragment;
|
||||
|
||||
mySize--;
|
||||
--mySize;
|
||||
myNextFragment = (myNextFragment + 1) % myFragmentQueue.size();
|
||||
|
||||
return nextFragment;
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#include "Settings.hxx"
|
||||
|
||||
namespace {
|
||||
uInt32 convertInt(int x, int defaultValue)
|
||||
uInt32 lboundInt(int x, int defaultValue)
|
||||
{
|
||||
return x <= defaultValue ? defaultValue : x;
|
||||
return x <= 0 ? defaultValue : x;
|
||||
}
|
||||
|
||||
AudioSettings::Preset normalizedPreset(int numericPreset)
|
||||
|
@ -42,17 +42,11 @@ namespace {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::AudioSettings()
|
||||
: mySettings(),
|
||||
myIsPersistent(false)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::AudioSettings(Settings* settings)
|
||||
AudioSettings::AudioSettings(Settings& settings)
|
||||
: mySettings(settings),
|
||||
myIsPersistent(true)
|
||||
{
|
||||
setPreset(normalizedPreset(mySettings->getInt(SETTING_PRESET)));
|
||||
setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET)));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -113,14 +107,14 @@ AudioSettings::Preset AudioSettings::preset()
|
|||
uInt32 AudioSettings::sampleRate()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_SAMPLE_RATE), DEFAULT_SAMPLE_RATE) : myPresetSampleRate;
|
||||
return customSettings() ? lboundInt(mySettings.getInt(SETTING_SAMPLE_RATE), DEFAULT_SAMPLE_RATE) : myPresetSampleRate;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::fragmentSize()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_FRAGMENT_SIZE), DEFAULT_FRAGMENT_SIZE) : myPresetFragmentSize;
|
||||
return customSettings() ? lboundInt(mySettings.getInt(SETTING_FRAGMENT_SIZE), DEFAULT_FRAGMENT_SIZE) : myPresetFragmentSize;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -128,7 +122,7 @@ uInt32 AudioSettings::bufferSize()
|
|||
{
|
||||
updatePresetFromSettings();
|
||||
// 0 is a valid value -> keep it
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_BUFFER_SIZE), 0) : myPresetBufferSize;
|
||||
return customSettings() ? lboundInt(mySettings.getInt(SETTING_BUFFER_SIZE), 0) : myPresetBufferSize;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -136,27 +130,34 @@ uInt32 AudioSettings::headroom()
|
|||
{
|
||||
updatePresetFromSettings();
|
||||
// 0 is a valid value -> keep it
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_HEADROOM), 0) : myPresetHeadroom;
|
||||
return customSettings() ? lboundInt(mySettings.getInt(SETTING_HEADROOM), 0) : myPresetHeadroom;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::ResamplingQuality AudioSettings::resamplingQuality()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? normalizeResamplingQuality(mySettings->getInt(SETTING_RESAMPLING_QUALITY)) : myPresetResamplingQuality;
|
||||
return customSettings() ? normalizeResamplingQuality(mySettings.getInt(SETTING_RESAMPLING_QUALITY)) : myPresetResamplingQuality;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string AudioSettings::stereo() const
|
||||
{
|
||||
// 0 is a valid value -> keep it
|
||||
return mySettings.getString(SETTING_STEREO);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::volume() const
|
||||
{
|
||||
// 0 is a valid value -> keep it
|
||||
return convertInt(mySettings->getInt(SETTING_VOLUME), 0);
|
||||
return lboundInt(mySettings.getInt(SETTING_VOLUME), 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AudioSettings::enabled() const
|
||||
{
|
||||
return mySettings->getBool(SETTING_ENABLED);
|
||||
return mySettings.getBool(SETTING_ENABLED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -205,7 +206,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
|
|||
throw runtime_error("invalid preset");
|
||||
}
|
||||
|
||||
if (myIsPersistent) mySettings->setValue(SETTING_PRESET, static_cast<int>(myPreset));
|
||||
if (myIsPersistent) mySettings.setValue(SETTING_PRESET, static_cast<int>(myPreset));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -213,8 +214,8 @@ void AudioSettings::setSampleRate(uInt32 sampleRate)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_SAMPLE_RATE, sampleRate);
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_SAMPLE_RATE, sampleRate);
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -222,8 +223,8 @@ void AudioSettings::setFragmentSize(uInt32 fragmentSize)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_FRAGMENT_SIZE, fragmentSize);
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_FRAGMENT_SIZE, fragmentSize);
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -231,8 +232,8 @@ void AudioSettings::setBufferSize(uInt32 bufferSize)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_BUFFER_SIZE, bufferSize);
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_BUFFER_SIZE, bufferSize);
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -240,8 +241,8 @@ void AudioSettings::setHeadroom(uInt32 headroom)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_HEADROOM, headroom);
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_HEADROOM, headroom);
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -249,8 +250,16 @@ void AudioSettings::setResamplingQuality(AudioSettings::ResamplingQuality resamp
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(resamplingQuality));
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(resamplingQuality));
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setStereo(const string& mode)
|
||||
{
|
||||
if(!myIsPersistent) return;
|
||||
|
||||
mySettings.setValue(SETTING_STEREO, mode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -258,8 +267,8 @@ void AudioSettings::setVolume(uInt32 volume)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_VOLUME, volume);
|
||||
normalize(*mySettings);
|
||||
mySettings.setValue(SETTING_VOLUME, volume);
|
||||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -267,7 +276,7 @@ void AudioSettings::setEnabled(bool isEnabled)
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
mySettings->setValue(SETTING_ENABLED, isEnabled);
|
||||
mySettings.setValue(SETTING_ENABLED, isEnabled);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -287,5 +296,5 @@ void AudioSettings::updatePresetFromSettings()
|
|||
{
|
||||
if (!myIsPersistent) return;
|
||||
|
||||
setPreset(normalizedPreset(mySettings->getInt(SETTING_PRESET)));
|
||||
setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET)));
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ class AudioSettings
|
|||
static constexpr const char* SETTING_BUFFER_SIZE = "audio.buffer_size";
|
||||
static constexpr const char* SETTING_HEADROOM = "audio.headroom";
|
||||
static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
|
||||
static constexpr const char* SETTING_STEREO = "audio.stereo";
|
||||
static constexpr const char* SETTING_VOLUME = "audio.volume";
|
||||
static constexpr const char* SETTING_ENABLED = "audio.enabled";
|
||||
|
||||
|
@ -55,6 +56,7 @@ class AudioSettings
|
|||
static constexpr uInt32 DEFAULT_BUFFER_SIZE = 3;
|
||||
static constexpr uInt32 DEFAULT_HEADROOM = 2;
|
||||
static constexpr ResamplingQuality DEFAULT_RESAMPLING_QUALITY = ResamplingQuality::lanczos_2;
|
||||
static constexpr const char* DEFAULT_STEREO = "byrom";
|
||||
static constexpr uInt32 DEFAULT_VOLUME = 80;
|
||||
static constexpr bool DEFAULT_ENABLED = true;
|
||||
|
||||
|
@ -63,9 +65,7 @@ class AudioSettings
|
|||
|
||||
public:
|
||||
|
||||
AudioSettings();
|
||||
|
||||
AudioSettings(Settings* mySettings);
|
||||
explicit AudioSettings(Settings& mySettings);
|
||||
|
||||
static void normalize(Settings& settings);
|
||||
|
||||
|
@ -81,6 +81,8 @@ class AudioSettings
|
|||
|
||||
ResamplingQuality resamplingQuality();
|
||||
|
||||
string stereo() const;
|
||||
|
||||
uInt32 volume() const;
|
||||
|
||||
bool enabled() const;
|
||||
|
@ -97,6 +99,8 @@ class AudioSettings
|
|||
|
||||
void setResamplingQuality(ResamplingQuality resamplingQuality);
|
||||
|
||||
void setStereo(const string& mode);
|
||||
|
||||
void setVolume(uInt32 volume);
|
||||
|
||||
void setEnabled(bool isEnabled);
|
||||
|
@ -111,7 +115,7 @@ class AudioSettings
|
|||
|
||||
private:
|
||||
|
||||
Settings* mySettings;
|
||||
Settings& mySettings;
|
||||
|
||||
Preset myPreset;
|
||||
|
||||
|
|
|
@ -19,21 +19,6 @@
|
|||
|
||||
namespace Common {
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Base::setHexUppercase(bool enable)
|
||||
{
|
||||
if(enable)
|
||||
{
|
||||
myHexflags |= std::ios_base::uppercase;
|
||||
myFmt = Base::myUpperFmt;
|
||||
}
|
||||
else
|
||||
{
|
||||
myHexflags &= ~std::ios_base::uppercase;
|
||||
myFmt = Base::myLowerFmt;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Base::toString(int value, Common::Base::Format outputBase)
|
||||
{
|
||||
|
@ -42,7 +27,6 @@ string Base::toString(int value, Common::Base::Format outputBase)
|
|||
if(outputBase == Base::F_DEFAULT)
|
||||
outputBase = myDefaultBase;
|
||||
|
||||
// Note: generates warnings about 'nonliteral' format
|
||||
switch(outputBase)
|
||||
{
|
||||
case Base::F_2: // base 2: 8 or 16 bits (depending on value)
|
||||
|
@ -63,9 +47,9 @@ string Base::toString(int value, Common::Base::Format outputBase)
|
|||
|
||||
case Base::F_10: // base 10: 3 or 5 bytes (depending on value)
|
||||
if(value < 0x100)
|
||||
std::snprintf(vToS_buf, 4, "%3d", value);
|
||||
std::snprintf(vToS_buf, 4, "%3d", value & 0xff);
|
||||
else
|
||||
std::snprintf(vToS_buf, 6, "%5d", value);
|
||||
std::snprintf(vToS_buf, 6, "%5d", value & 0xffff);
|
||||
break;
|
||||
|
||||
case Base::F_10_02: // base 10: 2 digits (with leading zero)
|
||||
|
@ -77,32 +61,34 @@ string Base::toString(int value, Common::Base::Format outputBase)
|
|||
break;
|
||||
|
||||
case Base::F_16_1: // base 16: 1 byte wide
|
||||
std::snprintf(vToS_buf, 2, myFmt[0], value);
|
||||
std::snprintf(vToS_buf, 2, hexUppercase() ? "%1X" : "%1x", value);
|
||||
break;
|
||||
case Base::F_16_2: // base 16: 2 bytes wide
|
||||
std::snprintf(vToS_buf, 3, myFmt[1], value);
|
||||
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
break;
|
||||
case Base::F_16_2_2:
|
||||
std::snprintf(vToS_buf, 6, "%02X.%02X", value >> 8, value & 0xff );
|
||||
std::snprintf(vToS_buf, 6, hexUppercase() ? "%02X.%02X" : "%02x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::F_16_3_2:
|
||||
std::snprintf(vToS_buf, 7, "%03X.%02X", value >> 8, value & 0xff );
|
||||
std::snprintf(vToS_buf, 7, hexUppercase() ? "%03X.%02X" : "%03x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::F_16_4: // base 16: 4 bytes wide
|
||||
std::snprintf(vToS_buf, 5, myFmt[2], value);
|
||||
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
break;
|
||||
case Base::F_16_8: // base 16: 8 bytes wide
|
||||
std::snprintf(vToS_buf, 9, myFmt[3], value);
|
||||
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
break;
|
||||
|
||||
case Base::F_16: // base 16: 2, 4, 8 bytes (depending on value)
|
||||
default:
|
||||
if(value < 0x100)
|
||||
std::snprintf(vToS_buf, 3, myFmt[1], value);
|
||||
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
else if(value < 0x10000)
|
||||
std::snprintf(vToS_buf, 5, myFmt[2], value);
|
||||
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
else
|
||||
std::snprintf(vToS_buf, 9, myFmt[3], value);
|
||||
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -115,13 +101,4 @@ Base::Format Base::myDefaultBase = Base::F_16;
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* const Base::myLowerFmt[4] = {
|
||||
"%1x", "%02x", "%04x", "%08x"
|
||||
};
|
||||
const char* const Base::myUpperFmt[4] = {
|
||||
"%1X", "%02X", "%04X", "%08X"
|
||||
};
|
||||
const char* const* Base::myFmt = Base::myLowerFmt;
|
||||
|
||||
} // Namespace Common
|
||||
|
|
|
@ -61,7 +61,10 @@ class Base
|
|||
static Base::Format format() { return myDefaultBase; }
|
||||
|
||||
/** Get/set HEX output to be upper/lower case */
|
||||
static void setHexUppercase(bool enable);
|
||||
static void setHexUppercase(bool enable) {
|
||||
if(enable) myHexflags |= std::ios_base::uppercase;
|
||||
else myHexflags &= ~std::ios_base::uppercase;
|
||||
}
|
||||
static bool hexUppercase() { return myHexflags & std::ios_base::uppercase; }
|
||||
|
||||
/** Output HEX digits in 0.5/1/2/4 byte format */
|
||||
|
@ -98,13 +101,6 @@ class Base
|
|||
// Upper or lower case for HEX digits
|
||||
static std::ios_base::fmtflags myHexflags;
|
||||
|
||||
// Format specifiers to use for sprintf (eventually we may convert
|
||||
// to C++ streams
|
||||
static ostringstream buf;
|
||||
static const char* const myLowerFmt[4];
|
||||
static const char* const myUpperFmt[4];
|
||||
static const char* const* myFmt;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Base() = delete;
|
||||
|
|
|
@ -35,7 +35,7 @@ class EventHandlerSDL2 : public EventHandler
|
|||
/**
|
||||
Create a new SDL2 event handler object
|
||||
*/
|
||||
EventHandlerSDL2(OSystem& osystem);
|
||||
explicit EventHandlerSDL2(OSystem& osystem);
|
||||
virtual ~EventHandlerSDL2() = default;
|
||||
|
||||
private:
|
||||
|
@ -57,7 +57,7 @@ class EventHandlerSDL2 : public EventHandler
|
|||
class JoystickSDL2 : public PhysicalJoystick
|
||||
{
|
||||
public:
|
||||
JoystickSDL2(int idx);
|
||||
explicit JoystickSDL2(int idx);
|
||||
virtual ~JoystickSDL2();
|
||||
|
||||
private:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <set>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Bankswitch.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "FSNodeFactory.hxx"
|
||||
#include "FSNodeZIP.hxx"
|
||||
|
@ -38,14 +39,6 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
_isDirectory(false),
|
||||
_isFile(false)
|
||||
{
|
||||
// Is this a valid file?
|
||||
auto isFile = [](const string& file)
|
||||
{
|
||||
return BSPF::endsWithIgnoreCase(file, ".a26") ||
|
||||
BSPF::endsWithIgnoreCase(file, ".bin") ||
|
||||
BSPF::endsWithIgnoreCase(file, ".rom");
|
||||
};
|
||||
|
||||
// Extract ZIP file and virtual file (if specified)
|
||||
size_t pos = BSPF::findIgnoreCase(p, ".zip");
|
||||
if(pos == string::npos)
|
||||
|
@ -54,8 +47,18 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
_zipFile = p.substr(0, pos+4);
|
||||
|
||||
// Open file at least once to initialize the virtual file count
|
||||
ZipHandler& zip = open(_zipFile);
|
||||
_numFiles = zip.romFiles();
|
||||
try
|
||||
{
|
||||
myZipHandler->open(_zipFile);
|
||||
}
|
||||
catch(const runtime_error&)
|
||||
{
|
||||
// TODO: Actually present the error passed in back to the user
|
||||
// For now, we just indicate that no ROMs were found
|
||||
_error = ZIPERR_NO_ROMS;
|
||||
return;
|
||||
}
|
||||
_numFiles = myZipHandler->romFiles();
|
||||
if(_numFiles == 0)
|
||||
{
|
||||
_error = ZIPERR_NO_ROMS;
|
||||
|
@ -67,16 +70,16 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
if(pos+5 < p.length())
|
||||
{
|
||||
_virtualPath = p.substr(pos+5);
|
||||
_isFile = isFile(_virtualPath);
|
||||
_isFile = Bankswitch::isValidRomName(_virtualPath);
|
||||
_isDirectory = !_isFile;
|
||||
}
|
||||
else if(_numFiles == 1)
|
||||
{
|
||||
bool found = false;
|
||||
while(zip.hasNext() && !found)
|
||||
while(myZipHandler->hasNext() && !found)
|
||||
{
|
||||
const string& file = zip.next();
|
||||
if(isFile(file))
|
||||
const string& file = myZipHandler->next();
|
||||
if(Bankswitch::isValidRomName(file))
|
||||
{
|
||||
_virtualPath = file;
|
||||
_isFile = true;
|
||||
|
@ -143,11 +146,14 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
return false;
|
||||
|
||||
std::set<string> dirs;
|
||||
ZipHandler& zip = open(_zipFile);
|
||||
while(zip.hasNext())
|
||||
myZipHandler->open(_zipFile);
|
||||
while(myZipHandler->hasNext())
|
||||
{
|
||||
// Only consider entries that start with '_virtualPath'
|
||||
const string& next = zip.next();
|
||||
// Ignore empty filenames and '__MACOSX' virtual directories
|
||||
const string& next = myZipHandler->next();
|
||||
if(BSPF::startsWithIgnoreCase(next, "__MACOSX") || next == EmptyString)
|
||||
continue;
|
||||
if(BSPF::startsWithIgnoreCase(next, _virtualPath))
|
||||
{
|
||||
// First strip off the leading directory
|
||||
|
@ -181,13 +187,13 @@ uInt32 FilesystemNodeZIP::read(BytePtr& image) const
|
|||
case ZIPERR_NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs");
|
||||
}
|
||||
|
||||
ZipHandler& zip = open(_zipFile);
|
||||
myZipHandler->open(_zipFile);
|
||||
|
||||
bool found = false;
|
||||
while(zip.hasNext() && !found)
|
||||
found = zip.next() == _virtualPath;
|
||||
while(myZipHandler->hasNext() && !found)
|
||||
found = myZipHandler->next() == _virtualPath;
|
||||
|
||||
return found ? zip.decompress(image) : 0;
|
||||
return found ? uInt32(myZipHandler->decompress(image)) : 0; // TODO: 64bit
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -43,27 +43,27 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
*
|
||||
* @param path String with the path the new node should point to.
|
||||
*/
|
||||
FilesystemNodeZIP(const string& path);
|
||||
explicit FilesystemNodeZIP(const string& path);
|
||||
|
||||
bool exists() const { return _realNode && _realNode->exists(); }
|
||||
const string& getName() const { return _name; }
|
||||
const string& getPath() const { return _path; }
|
||||
string getShortPath() const { return _shortPath; }
|
||||
bool isDirectory() const { return _isDirectory; }
|
||||
bool isFile() const { return _isFile; }
|
||||
bool isReadable() const { return _realNode && _realNode->isReadable(); }
|
||||
bool isWritable() const { return false; }
|
||||
bool exists() const override { return _realNode && _realNode->exists(); }
|
||||
const string& getName() const override { return _name; }
|
||||
const string& getPath() const override { return _path; }
|
||||
string getShortPath() const override { return _shortPath; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isFile() const override { return _isFile; }
|
||||
bool isReadable() const override { return _realNode && _realNode->isReadable(); }
|
||||
bool isWritable() const override { return false; }
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// For now, ZIP files cannot be modified in any way
|
||||
bool makeDir() { return false; }
|
||||
bool rename(const string& newfile) { return false; }
|
||||
bool makeDir() override { return false; }
|
||||
bool rename(const string& newfile) override { return false; }
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const;
|
||||
AbstractFSNodePtr getParent() const;
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
uInt32 read(BytePtr& image) const;
|
||||
uInt32 read(BytePtr& image) const override;
|
||||
|
||||
private:
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
|
@ -101,11 +101,6 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
|
||||
// ZipHandler static reference variable responsible for accessing ZIP files
|
||||
static unique_ptr<ZipHandler> myZipHandler;
|
||||
inline static ZipHandler& open(const string& file)
|
||||
{
|
||||
myZipHandler->open(file);
|
||||
return *myZipHandler;
|
||||
}
|
||||
|
||||
// Get last component of path
|
||||
static const char* lastPathComponent(const string& str)
|
||||
|
|
|
@ -26,7 +26,7 @@ class FpsMeter
|
|||
{
|
||||
public:
|
||||
|
||||
FpsMeter(uInt32 queueSize);
|
||||
explicit FpsMeter(uInt32 queueSize);
|
||||
|
||||
void reset(uInt32 garbageFrameLimit = 0);
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "SDL_lib.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class FrameBufferSDL2 : public FrameBuffer
|
|||
/**
|
||||
Creates a new SDL2 framebuffer
|
||||
*/
|
||||
FrameBufferSDL2(OSystem& osystem);
|
||||
explicit FrameBufferSDL2(OSystem& osystem);
|
||||
virtual ~FrameBufferSDL2();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -84,7 +84,7 @@ class LinkedObjectPool
|
|||
iter it = myCurrent;
|
||||
uInt32 idx = 1;
|
||||
|
||||
while(it-- != myList.begin()) idx++;
|
||||
while(it-- != myList.begin()) ++idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ class MouseControl
|
|||
int xid, yid;
|
||||
string message;
|
||||
|
||||
MouseMode(const string& msg = "")
|
||||
explicit MouseMode(const string& msg = "")
|
||||
: xtype(Controller::Joystick),
|
||||
ytype(Controller::Joystick),
|
||||
xid(-1),
|
||||
|
|
|
@ -524,21 +524,6 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool sta
|
|||
myOSystem.console().changeHeight(-1);
|
||||
break;
|
||||
|
||||
case KBDK_S: // Ctrl-s saves properties to a file
|
||||
{
|
||||
string filename = myOSystem.baseDir() +
|
||||
myOSystem.console().properties().get(Cartridge_Name) + ".pro";
|
||||
ofstream out(filename);
|
||||
if(out)
|
||||
{
|
||||
out << myOSystem.console().properties();
|
||||
myOSystem.frameBuffer().showMessage("Properties saved");
|
||||
}
|
||||
else
|
||||
myOSystem.frameBuffer().showMessage("Error saving properties");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
|
|
|
@ -49,7 +49,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
|||
|
||||
ifstream in(filename, std::ios_base::binary);
|
||||
if(!in.is_open())
|
||||
loadImageERROR("No image found");
|
||||
loadImageERROR("No snapshot found");
|
||||
|
||||
// Create the PNG loading context structure
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
|
||||
|
@ -331,7 +331,10 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
||||
<< BSPF::ARCH << "]";
|
||||
VarList::push_back(comments, "Software", version.str());
|
||||
VarList::push_back(comments, "ROM Name", myOSystem.console().properties().get(Cartridge_Name));
|
||||
const string& name = (myOSystem.settings().getString("snapname") == "int")
|
||||
? myOSystem.console().properties().get(Cartridge_Name)
|
||||
: myOSystem.romFile().getName();
|
||||
VarList::push_back(comments, "ROM Name", name);
|
||||
VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(Cartridge_MD5));
|
||||
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class Properties;
|
|||
class PNGLibrary
|
||||
{
|
||||
public:
|
||||
PNGLibrary(OSystem& osystem);
|
||||
explicit PNGLibrary(OSystem& osystem);
|
||||
|
||||
/**
|
||||
Read a PNG image from the specified file into a FBSurface structure,
|
||||
|
|
|
@ -179,6 +179,7 @@ class RewindManager
|
|||
// The goal of LinkedObjectPool is to not do any allocations at all
|
||||
RewindState() : cycles(0) { }
|
||||
RewindState(const RewindState& rs) : cycles(rs.cycles) { }
|
||||
RewindState& operator= (const RewindState& rs) { cycles = rs.cycles; return *this; }
|
||||
|
||||
// Output object info; used for debugging only
|
||||
friend ostream& operator<<(ostream& os, const RewindState& s) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class SoundNull : public Sound
|
|||
Create a new sound object. The init method must be invoked before
|
||||
using the object.
|
||||
*/
|
||||
SoundNull(OSystem& osystem) : Sound(osystem)
|
||||
explicit SoundNull(OSystem& osystem) : Sound(osystem)
|
||||
{
|
||||
myOSystem.logMessage("Sound disabled.\n", 1);
|
||||
}
|
||||
|
@ -71,23 +71,10 @@ class SoundNull : public Sound
|
|||
Set the mute state of the sound object. While muted no sound is played.
|
||||
|
||||
@param state Mutes sound if true, unmute if false
|
||||
*/
|
||||
void mute(bool state) override { }
|
||||
|
||||
/**
|
||||
Get the fragment size.
|
||||
@return The previous (old) mute state
|
||||
*/
|
||||
uInt32 getFragmentSize() const override { return 512; }
|
||||
|
||||
/**
|
||||
Get the sample rate.
|
||||
*/
|
||||
uInt32 getSampleRate() const override { return 31400; }
|
||||
|
||||
/**
|
||||
Reset the sound device.
|
||||
*/
|
||||
void reset() override { }
|
||||
bool mute(bool state) override { return true; }
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
|
@ -106,6 +93,11 @@ class SoundNull : public Sound
|
|||
*/
|
||||
void adjustVolume(Int8 direction) override { }
|
||||
|
||||
/**
|
||||
This method is called to provide information about the sound device.
|
||||
*/
|
||||
string about() const override { return "Sound disabled"; }
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
SoundNull() = delete;
|
||||
|
|
|
@ -40,7 +40,10 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
|||
myIsInitializedFlag(false),
|
||||
myVolume(100),
|
||||
myVolumeFactor(0xffff),
|
||||
myDevice(0),
|
||||
myEmulationTiming(nullptr),
|
||||
myCurrentFragment(nullptr),
|
||||
myUnderrun(false),
|
||||
myAudioSettings(audioSettings)
|
||||
{
|
||||
myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2);
|
||||
|
@ -54,31 +57,9 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
|||
return;
|
||||
}
|
||||
|
||||
// The sound system is opened only once per program run, to eliminate
|
||||
// issues with opening and closing it multiple times
|
||||
// This fixes a bug most prevalent with ATI video cards in Windows,
|
||||
// whereby sound stopped working after the first video change
|
||||
SDL_AudioSpec desired;
|
||||
desired.freq = myAudioSettings.sampleRate();
|
||||
desired.format = AUDIO_F32SYS;
|
||||
desired.channels = 2;
|
||||
desired.samples = myAudioSettings.fragmentSize();
|
||||
desired.callback = callback;
|
||||
desired.userdata = static_cast<void*>(this);
|
||||
|
||||
myDevice = SDL_OpenAudioDevice(0, 0, &desired, &myHardwareSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
|
||||
if(myDevice == 0)
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
buf << "WARNING: Couldn't open SDL audio device! " << endl
|
||||
<< " " << SDL_GetError() << endl;
|
||||
myOSystem.logMessage(buf.str(), 0);
|
||||
SDL_zero(myHardwareSpec);
|
||||
if(!openDevice())
|
||||
return;
|
||||
}
|
||||
|
||||
myIsInitializedFlag = true;
|
||||
|
||||
mute(true);
|
||||
|
||||
|
@ -94,6 +75,35 @@ SoundSDL2::~SoundSDL2()
|
|||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL2::openDevice()
|
||||
{
|
||||
SDL_AudioSpec desired;
|
||||
desired.freq = myAudioSettings.sampleRate();
|
||||
desired.format = AUDIO_F32SYS;
|
||||
desired.channels = 2;
|
||||
desired.samples = static_cast<Uint16>(myAudioSettings.fragmentSize());
|
||||
desired.callback = callback;
|
||||
desired.userdata = static_cast<void*>(this);
|
||||
|
||||
if(myIsInitializedFlag)
|
||||
SDL_CloseAudioDevice(myDevice);
|
||||
myDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &myHardwareSpec,
|
||||
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
|
||||
if(myDevice == 0)
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
buf << "WARNING: Couldn't open SDL audio device! " << endl
|
||||
<< " " << SDL_GetError() << endl;
|
||||
myOSystem.logMessage(buf.str(), 0);
|
||||
|
||||
return myIsInitializedFlag = false;
|
||||
}
|
||||
return myIsInitializedFlag = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::setEnabled(bool state)
|
||||
{
|
||||
|
@ -108,6 +118,14 @@ void SoundSDL2::setEnabled(bool state)
|
|||
void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
||||
EmulationTiming* emulationTiming)
|
||||
{
|
||||
string pre_about = myAboutString;
|
||||
|
||||
// Do we need to re-open the sound device?
|
||||
// Only do this when absolutely necessary
|
||||
if(myAudioSettings.sampleRate() != uInt32(myHardwareSpec.freq) ||
|
||||
myAudioSettings.fragmentSize() != uInt32(myHardwareSpec.samples))
|
||||
openDevice();
|
||||
|
||||
myEmulationTiming = emulationTiming;
|
||||
|
||||
myOSystem.logMessage("SoundSDL2::open started ...", 2);
|
||||
|
@ -127,18 +145,13 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
|||
// Adjust volume to that defined in settings
|
||||
setVolume(myAudioSettings.volume());
|
||||
|
||||
// Show some info
|
||||
ostringstream buf;
|
||||
buf << "Sound enabled:" << endl
|
||||
<< " Volume: " << myVolume << endl
|
||||
<< " Frag size: " << uInt32(myHardwareSpec.samples) << endl
|
||||
<< " Frequency: " << uInt32(myHardwareSpec.freq) << endl
|
||||
<< " Channels: " << uInt32(myHardwareSpec.channels)
|
||||
<< endl;
|
||||
myOSystem.logMessage(buf.str(), 1);
|
||||
|
||||
initResampler();
|
||||
|
||||
// Show some info
|
||||
myAboutString = about();
|
||||
if(myAboutString != pre_about)
|
||||
myOSystem.logMessage(myAboutString, 1);
|
||||
|
||||
// And start the SDL sound subsystem ...
|
||||
mute(false);
|
||||
|
||||
|
@ -157,21 +170,16 @@ void SoundSDL2::close()
|
|||
myCurrentFragment = nullptr;
|
||||
|
||||
myOSystem.logMessage("SoundSDL2::close", 2);
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::mute(bool state)
|
||||
bool SoundSDL2::mute(bool state)
|
||||
{
|
||||
bool oldstate = SDL_GetAudioDeviceStatus(myDevice) == SDL_AUDIO_PAUSED;
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
SDL_PauseAudioDevice(myDevice, state ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::reset()
|
||||
{
|
||||
return oldstate;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -215,15 +223,51 @@ void SoundSDL2::adjustVolume(Int8 direction)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL2::getFragmentSize() const
|
||||
string SoundSDL2::about() const
|
||||
{
|
||||
return myHardwareSpec.samples;
|
||||
ostringstream buf;
|
||||
buf << "Sound enabled:" << endl
|
||||
<< " Volume: " << myVolume << "%" << endl
|
||||
<< " Channels: " << uInt32(myHardwareSpec.channels)
|
||||
<< (myAudioQueue->isStereo() ? " (Stereo)" : " (Mono)") << endl
|
||||
<< " Preset: ";
|
||||
switch (myAudioSettings.preset()) {
|
||||
case AudioSettings::Preset::custom:
|
||||
buf << "Custom" << endl;
|
||||
break;
|
||||
case AudioSettings::Preset::lowQualityMediumLag:
|
||||
buf << "Low quality, medium lag" << endl;
|
||||
break;
|
||||
case AudioSettings::Preset::highQualityMediumLag:
|
||||
buf << "High quality, medium lag" << endl;
|
||||
break;
|
||||
case AudioSettings::Preset::highQualityLowLag:
|
||||
buf << "High quality, low lag" << endl;
|
||||
break;
|
||||
case AudioSettings::Preset::veryHighQualityVeryLowLag:
|
||||
buf << "Very high quality, very low lag" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL2::getSampleRate() const
|
||||
buf << " Fragment size: " << uInt32(myHardwareSpec.samples) << " bytes" << endl
|
||||
<< " Sample rate: " << uInt32(myHardwareSpec.freq) << " Hz" << endl;
|
||||
buf << " Resampling: ";
|
||||
switch(myAudioSettings.resamplingQuality())
|
||||
{
|
||||
return myHardwareSpec.freq;
|
||||
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
||||
buf << "Quality 1, nearest neighbor" << endl;
|
||||
break;
|
||||
case AudioSettings::ResamplingQuality::lanczos_2:
|
||||
buf << "Quality 2, Lanczos (a = 2)" << endl;
|
||||
break;
|
||||
case AudioSettings::ResamplingQuality::lanczos_3:
|
||||
buf << "Quality 3, Lanczos (a = 3)" << endl;
|
||||
break;
|
||||
}
|
||||
buf << " Headroom: " << std::fixed << std::setprecision(1)
|
||||
<< (0.5 * myAudioSettings.headroom()) << " frames" << endl
|
||||
<< " Buffer size: " << std::fixed << std::setprecision(1)
|
||||
<< (0.5 * myAudioSettings.bufferSize()) << " frames" << endl;
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -257,20 +301,16 @@ void SoundSDL2::initResampler()
|
|||
Resampler::Format formatTo =
|
||||
Resampler::Format(myHardwareSpec.freq, myHardwareSpec.samples, myHardwareSpec.channels > 1);
|
||||
|
||||
|
||||
switch (myAudioSettings.resamplingQuality()) {
|
||||
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
||||
myResampler = make_unique<SimpleResampler>(formatFrom, formatTo, nextFragmentCallback);
|
||||
(cerr << "resampling quality 1: using nearest neighbor resampling\n").flush();
|
||||
break;
|
||||
|
||||
case AudioSettings::ResamplingQuality::lanczos_2:
|
||||
(cerr << "resampling quality 2: using nearest Lanczos resampling, a = 2\n").flush();
|
||||
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 2);
|
||||
break;
|
||||
|
||||
case AudioSettings::ResamplingQuality::lanczos_3:
|
||||
(cerr << "resampling quality 3: using nearest Lanczos resampling, a = 3\n").flush();
|
||||
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 3);
|
||||
break;
|
||||
|
||||
|
|
|
@ -74,13 +74,10 @@ class SoundSDL2 : public Sound
|
|||
Set the mute state of the sound object. While muted no sound is played.
|
||||
|
||||
@param state Mutes sound if true, unmute if false
|
||||
*/
|
||||
void mute(bool state) override;
|
||||
|
||||
/**
|
||||
Reset the sound device.
|
||||
@return The previous (old) mute state
|
||||
*/
|
||||
void reset() override;
|
||||
bool mute(bool state) override;
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
|
@ -99,9 +96,10 @@ class SoundSDL2 : public Sound
|
|||
*/
|
||||
void adjustVolume(Int8 direction) override;
|
||||
|
||||
uInt32 getFragmentSize() const override;
|
||||
|
||||
uInt32 getSampleRate() const override;
|
||||
/**
|
||||
This method is called to provide information about the sound device.
|
||||
*/
|
||||
string about() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -115,6 +113,12 @@ class SoundSDL2 : public Sound
|
|||
void processFragment(float* stream, uInt32 length);
|
||||
|
||||
private:
|
||||
/**
|
||||
The actual sound device is opened only when absolutely necessary.
|
||||
Typically this will only happen once per program run, but it can also
|
||||
happen dynamically when changing sample rate and/or fragment size.
|
||||
*/
|
||||
bool openDevice();
|
||||
|
||||
void initResampler();
|
||||
|
||||
|
@ -142,6 +146,8 @@ class SoundSDL2 : public Sound
|
|||
|
||||
AudioSettings& myAudioSettings;
|
||||
|
||||
string myAboutString;
|
||||
|
||||
private:
|
||||
// Callback function invoked by the SDL Audio library when it needs data
|
||||
static void callback(void* udata, uInt8* stream, int len);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#define STATE_HEADER "05099000state"
|
||||
#define STATE_HEADER "05099200state"
|
||||
// #define MOVIE_HEADER "03030000movie"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -229,8 +229,6 @@ void StateManager::loadState(int slot)
|
|||
{
|
||||
if(in.getString() != STATE_HEADER)
|
||||
buf << "Incompatible state " << slot << " file";
|
||||
else if(in.getString() != myOSystem.console().cartridge().name())
|
||||
buf << "State " << slot << " file doesn't match current ROM";
|
||||
else
|
||||
{
|
||||
if(myOSystem.console().load(in))
|
||||
|
@ -275,9 +273,6 @@ void StateManager::saveState(int slot)
|
|||
// Add header so that if the state format changes in the future,
|
||||
// we'll know right away, without having to parse the rest of the file
|
||||
out.putString(STATE_HEADER);
|
||||
|
||||
// Sanity check; prepend the cart type/name
|
||||
out.putString(myOSystem.console().cartridge().name());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -325,10 +320,9 @@ bool StateManager::loadState(Serializer& in)
|
|||
// Make sure the file can be opened for reading
|
||||
if(in)
|
||||
{
|
||||
// First test if we have a valid header and cart type
|
||||
// First test if we have a valid header
|
||||
// If so, do a complete state load using the Console
|
||||
return in.getString() == STATE_HEADER &&
|
||||
in.getString() == myOSystem.console().cartridge().name() &&
|
||||
myOSystem.console().load(in);
|
||||
}
|
||||
}
|
||||
|
@ -354,9 +348,6 @@ bool StateManager::saveState(Serializer& out)
|
|||
// we'll know right away, without having to parse the rest of the file
|
||||
out.putString(STATE_HEADER);
|
||||
|
||||
// Sanity check; prepend the cart type/name
|
||||
out.putString(myOSystem.console().cartridge().name());
|
||||
|
||||
// Do a complete state save using the Console
|
||||
if(myOSystem.console().save(out))
|
||||
return true;
|
||||
|
|
|
@ -43,7 +43,7 @@ class StateManager
|
|||
/**
|
||||
Create a new statemananger class.
|
||||
*/
|
||||
StateManager(OSystem& osystem);
|
||||
explicit StateManager(OSystem& osystem);
|
||||
~StateManager();
|
||||
|
||||
public:
|
||||
|
|
|
@ -34,7 +34,7 @@ class StringParser
|
|||
|
||||
@param str The string to split
|
||||
*/
|
||||
StringParser(const string& str)
|
||||
explicit StringParser(const string& str)
|
||||
{
|
||||
istringstream buf(str);
|
||||
string line;
|
||||
|
@ -57,16 +57,17 @@ class StringParser
|
|||
|
||||
while(std::getline(buf, line, '\n'))
|
||||
{
|
||||
size_t beg = 0, len = maxlen, size = line.size();
|
||||
size_t len = maxlen, size = line.size();
|
||||
|
||||
if(size <= len)
|
||||
myStringList.push_back(line);
|
||||
else
|
||||
{
|
||||
size_t beg = 0;
|
||||
while((beg + maxlen) < size)
|
||||
{
|
||||
size_t spos = line.find_last_of(' ', beg + len);
|
||||
if(spos > beg)
|
||||
if(spos != string::npos && spos > beg)
|
||||
len = spos - beg;
|
||||
|
||||
myStringList.push_back(line.substr(beg, len));
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 <cassert>
|
||||
#include "TimerManager.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::TimerManager()
|
||||
: nextId(no_timer + 1),
|
||||
queue(),
|
||||
done(false)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::~TimerManager()
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
|
||||
// The worker might not be running
|
||||
if (worker.joinable())
|
||||
{
|
||||
done = true;
|
||||
lock.unlock();
|
||||
wakeUp.notify_all();
|
||||
|
||||
// If a timer handler is running, this
|
||||
// will make sure it has returned before
|
||||
// allowing any deallocations to happen
|
||||
worker.join();
|
||||
|
||||
// Note that any timers still in the queue
|
||||
// will be destructed properly but they
|
||||
// will not be invoked
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::TimerId TimerManager::addTimer(
|
||||
millisec msDelay,
|
||||
millisec msPeriod,
|
||||
const TFunction& func)
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
|
||||
// Lazily start thread when first timer is requested
|
||||
if (!worker.joinable())
|
||||
worker = std::thread(&TimerManager::timerThreadWorker, this);
|
||||
|
||||
// Assign an ID and insert it into function storage
|
||||
auto id = nextId++;
|
||||
auto iter = active.emplace(id, Timer(id, Clock::now() + Duration(msDelay),
|
||||
Duration(msPeriod), std::move(func)));
|
||||
|
||||
// Insert a reference to the Timer into ordering queue
|
||||
Queue::iterator place = queue.emplace(iter.first->second);
|
||||
|
||||
// We need to notify the timer thread only if we inserted
|
||||
// this timer into the front of the timer queue
|
||||
bool needNotify = (place == queue.begin());
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (needNotify)
|
||||
wakeUp.notify_all();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TimerManager::clear(TimerId id)
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
auto i = active.find(id);
|
||||
return destroy_impl(lock, i, true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TimerManager::clear()
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
while (!active.empty())
|
||||
destroy_impl(lock, active.begin(), queue.size() == 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::size_t TimerManager::size() const noexcept
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
return active.size();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TimerManager::empty() const noexcept
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
return active.empty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager& TimerManager::global()
|
||||
{
|
||||
static TimerManager singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TimerManager::timerThreadWorker()
|
||||
{
|
||||
ScopedLock lock(sync);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
// Wait for done or work
|
||||
wakeUp.wait(lock, [this] { return done || !queue.empty(); });
|
||||
continue;
|
||||
}
|
||||
|
||||
auto queueHead = queue.begin();
|
||||
Timer& timer = *queueHead;
|
||||
auto now = Clock::now();
|
||||
if (now >= timer.next)
|
||||
{
|
||||
queue.erase(queueHead);
|
||||
|
||||
// Mark it as running to handle racing destroy
|
||||
timer.running = true;
|
||||
|
||||
// Call the handler outside the lock
|
||||
lock.unlock();
|
||||
timer.handler();
|
||||
lock.lock();
|
||||
|
||||
if (timer.running)
|
||||
{
|
||||
timer.running = false;
|
||||
|
||||
// If it is periodic, schedule a new one
|
||||
if (timer.period.count() > 0)
|
||||
{
|
||||
timer.next = timer.next + timer.period;
|
||||
queue.emplace(timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not rescheduling, destruct it
|
||||
active.erase(timer.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// timer.running changed!
|
||||
//
|
||||
// Running was set to false, destroy was called
|
||||
// for this Timer while the callback was in progress
|
||||
// (this thread was not holding the lock during the callback)
|
||||
// The thread trying to destroy this timer is waiting on
|
||||
// a condition variable, so notify it
|
||||
timer.waitCond->notify_all();
|
||||
|
||||
// The clearTimer call expects us to remove the instance
|
||||
// when it detects that it is racing with its callback
|
||||
active.erase(timer.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait until the timer is ready or a timer creation notifies
|
||||
Timestamp next = timer.next;
|
||||
wakeUp.wait_until(lock, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// NOTE: if notify is true, returns with lock unlocked
|
||||
bool TimerManager::destroy_impl(ScopedLock& lock, TimerMap::iterator i,
|
||||
bool notify)
|
||||
{
|
||||
assert(lock.owns_lock());
|
||||
|
||||
if (i == active.end())
|
||||
return false;
|
||||
|
||||
Timer& timer = i->second;
|
||||
if (timer.running)
|
||||
{
|
||||
// A callback is in progress for this Timer,
|
||||
// so flag it for deletion in the worker
|
||||
timer.running = false;
|
||||
|
||||
// Assign a condition variable to this timer
|
||||
timer.waitCond.reset(new ConditionVar);
|
||||
|
||||
// Block until the callback is finished
|
||||
if (std::this_thread::get_id() != worker.get_id())
|
||||
timer.waitCond->wait(lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue.erase(timer);
|
||||
active.erase(i);
|
||||
|
||||
if (notify)
|
||||
{
|
||||
lock.unlock();
|
||||
wakeUp.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// TimerManager::Timer implementation
|
||||
//
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::Timer::Timer(TimerId tid)
|
||||
: id(tid),
|
||||
running(false)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::Timer::Timer(Timer&& r) noexcept
|
||||
: id(std::move(r.id)),
|
||||
next(std::move(r.next)),
|
||||
period(std::move(r.period)),
|
||||
handler(std::move(r.handler)),
|
||||
running(std::move(r.running))
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::Timer::Timer(TimerId tid, Timestamp tnext, Duration tperiod,
|
||||
const TFunction& func) noexcept
|
||||
: id(tid),
|
||||
next(tnext),
|
||||
period(tperiod),
|
||||
handler(std::move(func)),
|
||||
running(false)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TIMER_MANAGER_HXX
|
||||
#define TIMER_MANAGER_HXX
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class provides a portable periodic/one-shot timer infrastructure
|
||||
using worker threads and generic C++11 code.
|
||||
|
||||
@author Doug Gale (doug65536)
|
||||
From "Code Review"
|
||||
https://codereview.stackexchange.com/questions/127552/portable-periodic-one-shot-timer-thread-follow-up
|
||||
|
||||
Modifications and cleanup for Stella by Stephen Anthony
|
||||
*/
|
||||
class TimerManager
|
||||
{
|
||||
public:
|
||||
// Each Timer is assigned a unique ID of type TimerId
|
||||
using TimerId = uInt64;
|
||||
|
||||
// Function object we actually use
|
||||
using TFunction = std::function<void()>;
|
||||
|
||||
// Values that are a large-range millisecond count
|
||||
using millisec = uInt64;
|
||||
|
||||
// Constructor does not start worker until there is a Timer.
|
||||
explicit TimerManager();
|
||||
|
||||
// Destructor is thread safe, even if a timer callback is running.
|
||||
// All callbacks are guaranteed to have returned before this
|
||||
// destructor returns.
|
||||
~TimerManager();
|
||||
|
||||
/**
|
||||
Create a new timer using milliseconds, and add it to the internal queue.
|
||||
|
||||
@param msDelay Callback starts firing this many milliseconds from now
|
||||
@param msPeriod If non-zero, callback is fired again after this period
|
||||
@param func The callback to run at the specified interval
|
||||
|
||||
@return Id used to identify the timer for later use
|
||||
*/
|
||||
TimerId addTimer(millisec msDelay, millisec msPeriod, const TFunction& func);
|
||||
|
||||
/**
|
||||
Convenience function; setInterval API like browser javascript.
|
||||
|
||||
Call function every 'period' ms, starting 'period' ms from now.
|
||||
*/
|
||||
TimerId setInterval(const TFunction& func, millisec period) {
|
||||
return addTimer(period, period, std::move(func));
|
||||
}
|
||||
|
||||
/**
|
||||
Convenience function; setTimeout API like browser javascript.
|
||||
|
||||
Call function once 'timeout' ms from now.
|
||||
*/
|
||||
TimerId setTimeout(const TFunction& func, millisec timeout) {
|
||||
return addTimer(timeout, 0, std::move(func));
|
||||
}
|
||||
|
||||
/**
|
||||
Destroy the specified timer.
|
||||
|
||||
Synchronizes with the worker thread if the callback for this timer
|
||||
is running, which guarantees that the handler for that callback is
|
||||
not running before clear() returns.
|
||||
|
||||
You are not required to clear any timers. You can forget their
|
||||
TimerId if you do not need to cancel them.
|
||||
|
||||
The only time you need this is when you want to stop a timer that
|
||||
has a repetition period, or you want to cancel a timeout that has
|
||||
not fired yet.
|
||||
*/
|
||||
bool clear(TimerId id);
|
||||
|
||||
/**
|
||||
Destroy all timers, but preserve id uniqueness.
|
||||
This carefully makes sure every timer is not executing its callback
|
||||
before destructing it.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
// Peek at current state
|
||||
std::size_t size() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
// Returns lazily initialized singleton
|
||||
static TimerManager& global();
|
||||
|
||||
private:
|
||||
using Lock = std::mutex;
|
||||
using ScopedLock = std::unique_lock<Lock>;
|
||||
using ConditionVar = std::condition_variable;
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using Timestamp = std::chrono::time_point<Clock>;
|
||||
using Duration = std::chrono::milliseconds;
|
||||
|
||||
struct Timer
|
||||
{
|
||||
explicit Timer(TimerId id = 0);
|
||||
Timer(Timer&& r) noexcept;
|
||||
Timer& operator=(Timer&& r) noexcept;
|
||||
|
||||
Timer(TimerId id, Timestamp next, Duration period, const TFunction& func) noexcept;
|
||||
|
||||
// Never called
|
||||
Timer(Timer const& r) = delete;
|
||||
Timer& operator=(Timer const& r) = delete;
|
||||
|
||||
TimerId id;
|
||||
Timestamp next;
|
||||
Duration period;
|
||||
TFunction handler;
|
||||
|
||||
// You must be holding the 'sync' lock to assign waitCond
|
||||
std::unique_ptr<ConditionVar> waitCond;
|
||||
|
||||
bool running;
|
||||
};
|
||||
|
||||
// Comparison functor to sort the timer "queue" by Timer::next
|
||||
struct NextActiveComparator
|
||||
{
|
||||
bool operator()(Timer const& a, Timer const& b) const noexcept
|
||||
{
|
||||
return a.next < b.next;
|
||||
}
|
||||
};
|
||||
|
||||
// Queue is a set of references to Timer objects, sorted by next
|
||||
using QueueValue = std::reference_wrapper<Timer>;
|
||||
using Queue = std::multiset<QueueValue, NextActiveComparator>;
|
||||
using TimerMap = std::unordered_map<TimerId, Timer>;
|
||||
|
||||
void timerThreadWorker();
|
||||
bool destroy_impl(ScopedLock& lock, TimerMap::iterator i, bool notify);
|
||||
|
||||
// Inexhaustible source of unique IDs
|
||||
TimerId nextId;
|
||||
|
||||
// The Timer objects are physically stored in this map
|
||||
TimerMap active;
|
||||
|
||||
// The ordering queue holds references to items in 'active'
|
||||
Queue queue;
|
||||
|
||||
// One worker thread for an unlimited number of timers is acceptable
|
||||
// Lazily started when first timer is started
|
||||
// TODO: Implement auto-stopping the timer thread when it is idle for
|
||||
// a configurable period.
|
||||
mutable Lock sync;
|
||||
ConditionVar wakeUp;
|
||||
std::thread worker;
|
||||
bool done;
|
||||
|
||||
// Valid IDs are guaranteed not to be this value
|
||||
static TimerId constexpr no_timer = TimerId(0);
|
||||
};
|
||||
|
||||
#endif // TIMERTHREAD_H
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef VERSION_HXX
|
||||
#define VERSION_HXX
|
||||
|
||||
#define STELLA_VERSION "6.0_pre1"
|
||||
#define STELLA_BUILD "4434"
|
||||
#define STELLA_VERSION "6.0_beta1"
|
||||
#define STELLA_BUILD "4514"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,254 +18,296 @@
|
|||
#ifndef ZIP_HANDLER_HXX
|
||||
#define ZIP_HANDLER_HXX
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Copyright Aaron Giles
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name 'MAME' nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#define ZIP_DECOMPRESS_BUFSIZE 16384
|
||||
|
||||
/**
|
||||
This class implements a thin wrapper around the zip file management code
|
||||
from the MAME project.
|
||||
|
||||
@author Wrapper class by Stephen Anthony, with main functionality
|
||||
by Aaron Giles
|
||||
@author Original code by Aaron Giles, ZipHandler wrapper class and heavy
|
||||
modifications/refactoring by Stephen Anthony.
|
||||
*/
|
||||
class ZipHandler
|
||||
{
|
||||
public:
|
||||
ZipHandler();
|
||||
~ZipHandler();
|
||||
|
||||
// Open ZIP file for processing
|
||||
// An exception will be thrown on any errors
|
||||
void open(const string& filename);
|
||||
|
||||
// The following form an iterator for processing the filenames in the ZIP file
|
||||
void reset(); // Reset iterator to first file
|
||||
bool hasNext(); // Answer whether there are more files present
|
||||
string next(); // Get next file
|
||||
bool hasNext() const; // Answer whether there are more files present
|
||||
const string& next(); // Get next file
|
||||
|
||||
// Decompress the currently selected file and return its length
|
||||
// An exception will be thrown on any errors
|
||||
uInt32 decompress(BytePtr& image);
|
||||
uInt64 decompress(BytePtr& image);
|
||||
|
||||
// Answer the number of ROM files found in the archive
|
||||
// Currently, this means files with extension a26/bin/rom
|
||||
uInt16 romFiles() const { return myZip ? myZip->romfiles : 0; }
|
||||
// Answer the number of ROM files (with a valid extension) found
|
||||
uInt16 romFiles() const { return myZip ? myZip->myRomfiles : 0; }
|
||||
|
||||
private:
|
||||
// Replaces functionaity of various osd_xxxx functions
|
||||
static bool stream_open(const char* filename, fstream** stream, uInt64& length);
|
||||
static void stream_close(fstream** stream);
|
||||
static bool stream_read(fstream* stream, void* buffer, uInt64 offset,
|
||||
uInt32 length, uInt32& actual);
|
||||
|
||||
/* Error types */
|
||||
enum zip_error
|
||||
// Error types
|
||||
enum class ZipError
|
||||
{
|
||||
ZIPERR_NONE = 0,
|
||||
ZIPERR_OUT_OF_MEMORY,
|
||||
ZIPERR_FILE_ERROR,
|
||||
ZIPERR_BAD_SIGNATURE,
|
||||
ZIPERR_DECOMPRESS_ERROR,
|
||||
ZIPERR_FILE_TRUNCATED,
|
||||
ZIPERR_FILE_CORRUPT,
|
||||
ZIPERR_UNSUPPORTED,
|
||||
ZIPERR_BUFFER_TOO_SMALL
|
||||
NONE = 0,
|
||||
OUT_OF_MEMORY,
|
||||
FILE_ERROR,
|
||||
BAD_SIGNATURE,
|
||||
DECOMPRESS_ERROR,
|
||||
FILE_TRUNCATED,
|
||||
FILE_CORRUPT,
|
||||
UNSUPPORTED,
|
||||
LZMA_UNSUPPORTED,
|
||||
BUFFER_TOO_SMALL
|
||||
};
|
||||
|
||||
/* contains extracted file header information */
|
||||
struct zip_file_header
|
||||
// Contains extracted file header information
|
||||
struct ZipHeader
|
||||
{
|
||||
uInt32 signature; /* central file header signature */
|
||||
uInt16 version_created; /* version made by */
|
||||
uInt16 version_needed; /* version needed to extract */
|
||||
uInt16 bit_flag; /* general purpose bit flag */
|
||||
uInt16 compression; /* compression method */
|
||||
uInt16 file_time; /* last mod file time */
|
||||
uInt16 file_date; /* last mod file date */
|
||||
uInt32 crc; /* crc-32 */
|
||||
uInt32 compressed_length; /* compressed size */
|
||||
uInt32 uncompressed_length; /* uncompressed size */
|
||||
uInt16 filename_length; /* filename length */
|
||||
uInt16 extra_field_length; /* extra field length */
|
||||
uInt16 file_comment_length; /* file comment length */
|
||||
uInt16 start_disk_number; /* disk number start */
|
||||
uInt16 internal_attributes; /* internal file attributes */
|
||||
uInt32 external_attributes; /* external file attributes */
|
||||
uInt32 local_header_offset; /* relative offset of local header */
|
||||
const char* filename; /* filename */
|
||||
uInt16 versionCreated; // version made by
|
||||
uInt16 versionNeeded; // version needed to extract
|
||||
uInt16 bitFlag; // general purpose bit flag
|
||||
uInt16 compression; // compression method
|
||||
uInt16 fileTime; // last mod file time
|
||||
uInt16 fileDate; // last mod file date
|
||||
uInt32 crc; // crc-32
|
||||
uInt64 compressedLength; // compressed size
|
||||
uInt64 uncompressedLength; // uncompressed size
|
||||
uInt32 startDiskNumber; // disk number start
|
||||
uInt64 localHeaderOffset; // relative offset of local header
|
||||
string filename; // filename
|
||||
|
||||
uInt8* raw; /* pointer to the raw data */
|
||||
uInt32 rawlength; /* length of the raw data */
|
||||
uInt8 saved; /* saved byte from after filename */
|
||||
/** Constructor */
|
||||
ZipHeader();
|
||||
};
|
||||
|
||||
/* contains extracted end of central directory information */
|
||||
struct zip_ecd
|
||||
// Contains extracted end of central directory information
|
||||
struct ZipEcd
|
||||
{
|
||||
uInt32 signature; /* end of central dir signature */
|
||||
uInt16 disk_number; /* number of this disk */
|
||||
uInt16 cd_start_disk_number; /* number of the disk with the start of the central directory */
|
||||
uInt16 cd_disk_entries; /* total number of entries in the central directory on this disk */
|
||||
uInt16 cd_total_entries; /* total number of entries in the central directory */
|
||||
uInt32 cd_size; /* size of the central directory */
|
||||
uInt32 cd_start_disk_offset; /* offset of start of central directory with respect to the starting disk number */
|
||||
uInt16 comment_length; /* .ZIP file comment length */
|
||||
const char* comment; /* .ZIP file comment */
|
||||
uInt32 diskNumber; // number of this disk
|
||||
uInt32 cdStartDiskNumber; // number of the disk with the start of the central directory
|
||||
uInt64 cdDiskEntries; // total number of entries in the central directory on this disk
|
||||
uInt64 cdTotalEntries; // total number of entries in the central directory
|
||||
uInt64 cdSize; // size of the central directory
|
||||
uInt64 cdStartDiskOffset; // offset of start of central directory with respect to the starting disk number
|
||||
|
||||
uInt8* raw; /* pointer to the raw data */
|
||||
uInt32 rawlength; /* length of the raw data */
|
||||
/** Constructor */
|
||||
ZipEcd();
|
||||
};
|
||||
|
||||
/* describes an open ZIP file */
|
||||
struct zip_file
|
||||
// Describes an open ZIP file
|
||||
struct ZipFile
|
||||
{
|
||||
const char* filename; /* copy of ZIP filename (for caching) */
|
||||
fstream* file; /* C++ fstream file handle */
|
||||
uInt64 length; /* length of zip file */
|
||||
uInt16 romfiles; /* number of ROM files in central directory */
|
||||
string myFilename; // copy of ZIP filename (for caching)
|
||||
fstream myStream; // C++ fstream file handle
|
||||
uInt64 myLength; // length of zip file
|
||||
uInt16 myRomfiles; // number of ROM files in central directory
|
||||
|
||||
zip_ecd ecd; /* end of central directory */
|
||||
ZipEcd myEcd; // end of central directory
|
||||
|
||||
uInt8* cd; /* central directory raw data */
|
||||
uInt32 cd_pos; /* position in central directory */
|
||||
zip_file_header header; /* current file header */
|
||||
BytePtr myCd; // central directory raw data
|
||||
uInt64 myCdPos; // position in central directory
|
||||
ZipHeader myHeader; // current file header
|
||||
|
||||
uInt8 buffer[ZIP_DECOMPRESS_BUFSIZE]; /* buffer for decompression */
|
||||
BytePtr myBuffer; // buffer for decompression
|
||||
|
||||
/** Constructor */
|
||||
explicit ZipFile(const string& filename);
|
||||
|
||||
/** Open the file and set up the internal stream buffer*/
|
||||
bool open();
|
||||
|
||||
/** Read the ZIP contents from the internal stream buffer */
|
||||
void initialize();
|
||||
|
||||
/** Close previously opened internal stream buffer */
|
||||
void close();
|
||||
|
||||
/** Read the ECD data */
|
||||
void readEcd();
|
||||
|
||||
/** Read data from stream */
|
||||
bool readStream(BytePtr& out, uInt64 offset, uInt64 length, uInt64& actual);
|
||||
|
||||
/** Return the next entry in the ZIP file */
|
||||
const ZipHeader* const nextFile();
|
||||
|
||||
/** Decompress the most recently found file in the ZIP into target buffer */
|
||||
void decompress(BytePtr& out, uInt64 length);
|
||||
|
||||
/** Return the offset of the compressed data */
|
||||
uInt64 getCompressedDataOffset();
|
||||
|
||||
/** Decompress type 0 data (which is uncompressed) */
|
||||
void decompressDataType0(uInt64 offset, BytePtr& out, uInt64 length);
|
||||
|
||||
/** Decompress type 8 data (which is deflated) */
|
||||
void decompressDataType8(uInt64 offset, BytePtr& out, uInt64 length);
|
||||
};
|
||||
using ZipFilePtr = unique_ptr<ZipFile>;
|
||||
|
||||
enum {
|
||||
/* number of open files to cache */
|
||||
ZIP_CACHE_SIZE = 8,
|
||||
|
||||
/* offsets in end of central directory structure */
|
||||
ZIPESIG = 0x00,
|
||||
ZIPEDSK = 0x04,
|
||||
ZIPECEN = 0x06,
|
||||
ZIPENUM = 0x08,
|
||||
ZIPECENN = 0x0a,
|
||||
ZIPECSZ = 0x0c,
|
||||
ZIPEOFST = 0x10,
|
||||
ZIPECOML = 0x14,
|
||||
ZIPECOM = 0x16,
|
||||
|
||||
/* offsets in central directory entry structure */
|
||||
ZIPCENSIG = 0x00,
|
||||
ZIPCVER = 0x04,
|
||||
ZIPCOS = 0x05,
|
||||
ZIPCVXT = 0x06,
|
||||
ZIPCEXOS = 0x07,
|
||||
ZIPCFLG = 0x08,
|
||||
ZIPCMTHD = 0x0a,
|
||||
ZIPCTIM = 0x0c,
|
||||
ZIPCDAT = 0x0e,
|
||||
ZIPCCRC = 0x10,
|
||||
ZIPCSIZ = 0x14,
|
||||
ZIPCUNC = 0x18,
|
||||
ZIPCFNL = 0x1c,
|
||||
ZIPCXTL = 0x1e,
|
||||
ZIPCCML = 0x20,
|
||||
ZIPDSK = 0x22,
|
||||
ZIPINT = 0x24,
|
||||
ZIPEXT = 0x26,
|
||||
ZIPOFST = 0x2a,
|
||||
ZIPCFN = 0x2e,
|
||||
|
||||
/* offsets in local file header structure */
|
||||
ZIPLOCSIG = 0x00,
|
||||
ZIPVER = 0x04,
|
||||
ZIPGENFLG = 0x06,
|
||||
ZIPMTHD = 0x08,
|
||||
ZIPTIME = 0x0a,
|
||||
ZIPDATE = 0x0c,
|
||||
ZIPCRC = 0x0e,
|
||||
ZIPSIZE = 0x12,
|
||||
ZIPUNCMP = 0x16,
|
||||
ZIPFNLN = 0x1a,
|
||||
ZIPXTRALN = 0x1c,
|
||||
ZIPNAME = 0x1e
|
||||
};
|
||||
|
||||
private:
|
||||
/* ----- ZIP file access ----- */
|
||||
|
||||
/* open a ZIP file and parse its central directory */
|
||||
zip_error zip_file_open(const char* filename, zip_file** zip);
|
||||
|
||||
/* close a ZIP file (may actually be left open due to caching) */
|
||||
void zip_file_close(zip_file* zip);
|
||||
|
||||
/* clear out all open ZIP files from the cache */
|
||||
void zip_file_cache_clear();
|
||||
|
||||
|
||||
/* ----- contained file access ----- */
|
||||
|
||||
/* find the next file in the ZIP */
|
||||
const zip_file_header* zip_file_next_file(zip_file* zip);
|
||||
|
||||
/* decompress the most recently found file in the ZIP */
|
||||
zip_error zip_file_decompress(zip_file* zip, void* buffer, uInt32 length);
|
||||
|
||||
inline static uInt16 read_word(uInt8* buf)
|
||||
/** Classes to parse the ZIP metadata in an abstracted way */
|
||||
class ReaderBase
|
||||
{
|
||||
uInt16 p0 = uInt16(buf[0]), p1 = uInt16(buf[1]);
|
||||
return (p1 << 8) | p0;
|
||||
protected:
|
||||
explicit ReaderBase(const uInt8* const b) : myBuf(b) { }
|
||||
|
||||
uInt8 read_byte(size_t offs) const
|
||||
{
|
||||
return myBuf[offs];
|
||||
}
|
||||
uInt16 read_word(size_t offs) const
|
||||
{
|
||||
return (uInt16(myBuf[offs + 1]) << 8) |
|
||||
(uInt16(myBuf[offs + 0]) << 0);
|
||||
}
|
||||
uInt32 read_dword(std::size_t offs) const
|
||||
{
|
||||
return (uInt32(myBuf[offs + 3]) << 24) |
|
||||
(uInt32(myBuf[offs + 2]) << 16) |
|
||||
(uInt32(myBuf[offs + 1]) << 8) |
|
||||
(uInt32(myBuf[offs + 0]) << 0);
|
||||
}
|
||||
uInt64 read_qword(size_t offs) const
|
||||
{
|
||||
return (uInt64(myBuf[offs + 7]) << 56) |
|
||||
(uInt64(myBuf[offs + 6]) << 48) |
|
||||
(uInt64(myBuf[offs + 5]) << 40) |
|
||||
(uInt64(myBuf[offs + 4]) << 32) |
|
||||
(uInt64(myBuf[offs + 3]) << 24) |
|
||||
(uInt64(myBuf[offs + 2]) << 16) |
|
||||
(uInt64(myBuf[offs + 1]) << 8) |
|
||||
(uInt64(myBuf[offs + 0]) << 0);
|
||||
}
|
||||
string read_string(size_t offs, size_t len = string::npos) const
|
||||
{
|
||||
return string(reinterpret_cast<char const *>(myBuf + offs), len);
|
||||
}
|
||||
|
||||
inline static uInt32 read_dword(uInt8* buf)
|
||||
private:
|
||||
const uInt8* const myBuf;
|
||||
};
|
||||
|
||||
class LocalFileHeaderReader : public ReaderBase
|
||||
{
|
||||
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
}
|
||||
public:
|
||||
explicit LocalFileHeaderReader(const uInt8* const b) : ReaderBase(b) { }
|
||||
|
||||
/* cache management */
|
||||
static void free_zip_file(zip_file* zip);
|
||||
uInt32 signature() const { return read_dword(0x00); }
|
||||
uInt8 versionNeeded() const { return read_byte(0x04); }
|
||||
uInt8 osNeeded() const { return read_byte(0x05); }
|
||||
uInt16 generalFlag() const { return read_word(0x06); }
|
||||
uInt16 compressionMethod() const { return read_word(0x08); }
|
||||
uInt16 modifiedTime() const { return read_word(0x0a); }
|
||||
uInt16 modifiedDate() const { return read_word(0x0c); }
|
||||
uInt32 crc32() const { return read_dword(0x0e); }
|
||||
uInt32 compressedSize() const { return read_dword(0x12); }
|
||||
uInt32 uncompressedSize() const { return read_dword(0x16); }
|
||||
uInt16 filenameLength() const { return read_word(0x1a); }
|
||||
uInt16 extraFieldLength() const { return read_word(0x1c); }
|
||||
string filename() const { return read_string(0x1e, filenameLength()); }
|
||||
|
||||
/* ZIP file parsing */
|
||||
static zip_error read_ecd(zip_file* zip);
|
||||
static zip_error get_compressed_data_offset(zip_file* zip, uInt64& offset);
|
||||
bool signatureCorrect() const { return signature() == 0x04034b50; }
|
||||
|
||||
/* decompression interfaces */
|
||||
static zip_error decompress_data_type_0(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length);
|
||||
static zip_error decompress_data_type_8(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length);
|
||||
size_t totalLength() const { return minimumLength() + filenameLength() + extraFieldLength(); }
|
||||
static size_t minimumLength() { return 0x1e; }
|
||||
};
|
||||
|
||||
class CentralDirEntryReader : public ReaderBase
|
||||
{
|
||||
public:
|
||||
explicit CentralDirEntryReader(const uInt8* const b) : ReaderBase(b) { }
|
||||
|
||||
uInt32 signature() const { return read_dword(0x00); }
|
||||
uInt8 versionCreated() const { return read_byte(0x04); }
|
||||
uInt8 osCreated() const { return read_byte(0x05); }
|
||||
uInt8 versionNeeded() const { return read_byte(0x06); }
|
||||
uInt8 osNeeded() const { return read_byte(0x07); }
|
||||
uInt16 generalFlag() const { return read_word(0x08); }
|
||||
uInt16 compressionMethod() const { return read_word(0x0a); }
|
||||
uInt16 modifiedTime() const { return read_word(0x0c); }
|
||||
uInt16 modifiedDate() const { return read_word(0x0e); }
|
||||
uInt32 crc32() const { return read_dword(0x10); }
|
||||
uInt32 compressedSize() const { return read_dword(0x14); }
|
||||
uInt32 uncompressedSize() const { return read_dword(0x18); }
|
||||
uInt16 filenameLength() const { return read_word(0x1c); }
|
||||
uInt16 extraFieldLength() const { return read_word(0x1e); }
|
||||
uInt16 fileCommentLength() const { return read_word(0x20); }
|
||||
uInt16 startDisk() const { return read_word(0x22); }
|
||||
uInt16 intFileAttr() const { return read_word(0x24); }
|
||||
uInt32 extFileAttr() const { return read_dword(0x26); }
|
||||
uInt32 headerOffset() const { return read_dword(0x2a); }
|
||||
string filename() const { return read_string(0x2e, filenameLength()); }
|
||||
string fileComment() const { return read_string(0x2e + filenameLength() + extraFieldLength(), fileCommentLength()); }
|
||||
|
||||
bool signatureCorrect() const { return signature() == 0x02014b50; }
|
||||
|
||||
size_t totalLength() const { return minimumLength() + filenameLength() + extraFieldLength() + fileCommentLength(); }
|
||||
static size_t minimumLength() { return 0x2e; }
|
||||
};
|
||||
|
||||
class EcdReader : public ReaderBase
|
||||
{
|
||||
public:
|
||||
explicit EcdReader(const uInt8* const b) : ReaderBase(b) { }
|
||||
|
||||
uInt32 signature() const { return read_dword(0x00); }
|
||||
uInt16 thisDiskNo() const { return read_word(0x04); }
|
||||
uInt16 dirStartDisk() const { return read_word(0x06); }
|
||||
uInt16 dirDiskEntries() const { return read_word(0x08); }
|
||||
uInt16 dirTotalEntries() const { return read_word(0x0a); }
|
||||
uInt32 dirSize() const { return read_dword(0x0c); }
|
||||
uInt32 dirOffset() const { return read_dword(0x10); }
|
||||
uInt16 commentLength() const { return read_word(0x14); }
|
||||
string comment() const { return read_string(0x16, commentLength()); }
|
||||
|
||||
bool signatureCorrect() const { return signature() == 0x06054b50; }
|
||||
|
||||
size_t totalLength() const { return minimumLength() + commentLength(); }
|
||||
static size_t minimumLength() { return 0x16; }
|
||||
};
|
||||
|
||||
class GeneralFlagReader
|
||||
{
|
||||
public:
|
||||
explicit GeneralFlagReader(uInt16 val) : myValue(val) { }
|
||||
|
||||
bool encrypted() const { return bool(myValue & 0x0001); }
|
||||
bool implode8kDict() const { return bool(myValue & 0x0002); }
|
||||
bool implode3Trees() const { return bool(myValue & 0x0004); }
|
||||
uInt32 deflateOption() const { return uInt32((myValue >> 1) & 0x0003); }
|
||||
bool lzmaEosMark() const { return bool(myValue & 0x0002); }
|
||||
bool useDescriptor() const { return bool(myValue & 0x0008); }
|
||||
bool patchData() const { return bool(myValue & 0x0020); }
|
||||
bool strongEncryption() const { return bool(myValue & 0x0040); }
|
||||
bool utf8Encoding() const { return bool(myValue & 0x0800); }
|
||||
bool directoryEncryption() const { return bool(myValue & 0x2000); }
|
||||
|
||||
private:
|
||||
zip_file* myZip;
|
||||
zip_file* myZipCache[ZIP_CACHE_SIZE];
|
||||
uInt16 myValue;
|
||||
};
|
||||
|
||||
private:
|
||||
/** Get message for given ZipError enumeration */
|
||||
string errorMessage(ZipError err) const;
|
||||
|
||||
/** Search cache for given ZIP file */
|
||||
ZipFilePtr findCached(const string& filename);
|
||||
|
||||
/** Close a ZIP file and add it to the cache */
|
||||
void addToCache();
|
||||
|
||||
private:
|
||||
static constexpr uInt32 DECOMPRESS_BUFSIZE = 16384;
|
||||
static constexpr uInt32 CACHE_SIZE = 8; // number of open files to cache
|
||||
|
||||
ZipFilePtr myZip;
|
||||
std::array<ZipFilePtr, CACHE_SIZE> myZipCache;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -38,7 +38,7 @@ float ConvolutionBuffer::convoluteWith(float* kernel) const
|
|||
{
|
||||
float result = 0.;
|
||||
|
||||
for (uInt32 i = 0; i < mySize; i++) {
|
||||
for (uInt32 i = 0; i < mySize; ++i) {
|
||||
result += kernel[i] * myData[(myFirstIndex + i) % mySize];
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class ConvolutionBuffer
|
|||
{
|
||||
public:
|
||||
|
||||
ConvolutionBuffer(uInt32 size);
|
||||
explicit ConvolutionBuffer(uInt32 size);
|
||||
|
||||
void shift(float nextValue);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace {
|
|||
|
||||
uInt32 reducedDenominator(uInt32 n, uInt32 d)
|
||||
{
|
||||
for (uInt32 i = std::min(n ,d); i > 1; i--) {
|
||||
for (uInt32 i = std::min(n ,d); i > 1; --i) {
|
||||
if ((n % i == 0) && (d % i == 0)) {
|
||||
n /= i;
|
||||
d /= i;
|
||||
|
@ -49,7 +49,7 @@ namespace {
|
|||
);
|
||||
}
|
||||
|
||||
double lanczosKernel(float x, uInt32 a) {
|
||||
float lanczosKernel(float x, uInt32 a) {
|
||||
return sinc(x) * sinc(x / static_cast<float>(a));
|
||||
}
|
||||
|
||||
|
@ -103,13 +103,13 @@ void LanczosResampler::precomputeKernels()
|
|||
// timeIndex = time * formatFrom.sampleRate * formatTo.sampleRAte
|
||||
uInt32 timeIndex = 0;
|
||||
|
||||
for (uInt32 i = 0; i < myPrecomputedKernelCount; i++) {
|
||||
for (uInt32 i = 0; i < myPrecomputedKernelCount; ++i) {
|
||||
float* kernel = myPrecomputedKernels.get() + myKernelSize * i;
|
||||
// The kernel is normalized such to be evaluate on time * formatFrom.sampleRate
|
||||
float center =
|
||||
static_cast<float>(timeIndex) / static_cast<float>(myFormatTo.sampleRate);
|
||||
|
||||
for (uInt32 j = 0; j < 2 * myKernelParameter; j++) {
|
||||
for (uInt32 j = 0; j < 2 * myKernelParameter; ++j) {
|
||||
kernel[j] = lanczosKernel(
|
||||
center - static_cast<float>(j) + static_cast<float>(myKernelParameter) - 1.f, myKernelParameter
|
||||
) * CLIPPING_FACTOR;
|
||||
|
@ -150,7 +150,7 @@ void LanczosResampler::fillFragment(float* fragment, uInt32 length)
|
|||
|
||||
const uInt32 outputSamples = myFormatTo.stereo ? (length >> 1) : length;
|
||||
|
||||
for (uInt32 i = 0; i < outputSamples; i++) {
|
||||
for (uInt32 i = 0; i < outputSamples; ++i) {
|
||||
float* kernel = myPrecomputedKernels.get() + (myCurrentKernelIndex * myKernelSize);
|
||||
myCurrentKernelIndex = (myCurrentKernelIndex + 1) % myPrecomputedKernelCount;
|
||||
|
||||
|
@ -194,7 +194,7 @@ inline void LanczosResampler::shiftSamples(uInt32 samplesToShift)
|
|||
else
|
||||
myBuffer->shift(myHighPass.apply(myCurrentFragment[myFragmentIndex] / static_cast<float>(0x7fff)));
|
||||
|
||||
myFragmentIndex++;
|
||||
++myFragmentIndex;
|
||||
|
||||
if (myFragmentIndex >= myFormatFrom.fragmentSize) {
|
||||
myFragmentIndex %= myFormatFrom.fragmentSize;
|
||||
|
|
|
@ -33,7 +33,7 @@ class LanczosResampler : public Resampler
|
|||
uInt32 kernelParameter
|
||||
);
|
||||
|
||||
virtual void fillFragment(float* fragment, uInt32 length);
|
||||
void fillFragment(float* fragment, uInt32 length) override;
|
||||
|
||||
virtual ~LanczosResampler() = default;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ void SimpleResampler::fillFragment(float* fragment, uInt32 length)
|
|||
const uInt32 outputSamples = myFormatTo.stereo ? (length >> 1) : length;
|
||||
|
||||
// For the following math, remember that myTimeIndex = time * myFormatFrom.sampleRate * myFormatTo.sampleRate
|
||||
for (uInt32 i = 0; i < outputSamples; i++) {
|
||||
for (uInt32 i = 0; i < outputSamples; ++i) {
|
||||
if (myFormatFrom.stereo) {
|
||||
float sampleL = static_cast<float>(myCurrentFragment[2*myFragmentIndex]) / static_cast<float>(0x7fff);
|
||||
float sampleR = static_cast<float>(myCurrentFragment[2*myFragmentIndex + 1]) / static_cast<float>(0x7fff);
|
||||
|
|
|
@ -30,7 +30,7 @@ class SimpleResampler : public Resampler
|
|||
Resampler::NextFragmentCallback NextFragmentCallback
|
||||
);
|
||||
|
||||
virtual void fillFragment(float* fragment, uInt32 length);
|
||||
void fillFragment(float* fragment, uInt32 length) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
@author Bradford W. Mott and Stephen Anthony
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
// Types for 8/16/32/64-bit signed and unsigned integers
|
||||
using Int8 = int8_t;
|
||||
|
@ -48,6 +49,7 @@ using uInt64 = uint64_t;
|
|||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
@ -93,10 +95,6 @@ namespace BSPF
|
|||
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
static const string PATH_SEPARATOR = "\\";
|
||||
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type
|
||||
#pragma warning(2:4264) // no override available for virtual member function from base 'class'; function is hidden
|
||||
#pragma warning(2:4265) // class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(2:4266) // no override available for virtual member function from base 'type'; function is hidden
|
||||
#define ATTRIBUTE_FMT_PRINTF
|
||||
#else
|
||||
#error Update src/common/bspf.hxx for path separator
|
||||
|
@ -203,7 +201,7 @@ namespace BSPF
|
|||
if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1)))
|
||||
{
|
||||
size_t pos = 1;
|
||||
for(uInt32 j = 1; j < s2.size(); j++)
|
||||
for(uInt32 j = 1; j < s2.size(); ++j)
|
||||
{
|
||||
size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos);
|
||||
if(found == string::npos)
|
||||
|
@ -214,6 +212,21 @@ namespace BSPF
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// C++11 way to get local time
|
||||
// Equivalent to the C-style localtime() function, but is thread-safe
|
||||
inline std::tm localTime()
|
||||
{
|
||||
std::time_t currtime;
|
||||
std::time(&currtime);
|
||||
std::tm tm_snapshot;
|
||||
#if defined BSPF_WINDOWS && !defined __GNUG__
|
||||
localtime_s(&tm_snapshot, &currtime);
|
||||
#else
|
||||
localtime_r(&currtime, &tm_snapshot);
|
||||
#endif
|
||||
return tm_snapshot;
|
||||
}
|
||||
} // namespace BSPF
|
||||
|
||||
#endif
|
||||
|
|
|
@ -151,7 +151,7 @@ int main(int argc, char* argv[])
|
|||
if(initBreak != "")
|
||||
{
|
||||
Debugger& dbg = theOSystem->debugger();
|
||||
int bp = dbg.stringToValue(initBreak);
|
||||
uInt16 bp = uInt16(dbg.stringToValue(initBreak));
|
||||
dbg.setBreakPoint(bp, true);
|
||||
theOSystem->settings().setValue("break", "");
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ MODULE_OBJS := \
|
|||
src/common/RewindManager.o \
|
||||
src/common/SoundSDL2.o \
|
||||
src/common/StateManager.o \
|
||||
src/common/TimerManager.o \
|
||||
src/common/ZipHandler.o \
|
||||
src/common/AudioQueue.o \
|
||||
src/common/AudioSettings.o \
|
||||
|
|
|
@ -257,38 +257,38 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_
|
|||
{
|
||||
// Store back into displayed frame buffer (for next frame)
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
}
|
||||
// finish final pixels
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
#if 0
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]);
|
||||
bufofs++;
|
||||
++bufofs;
|
||||
#endif
|
||||
|
||||
atari_in += in_width;
|
||||
|
@ -300,7 +300,9 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_
|
|||
inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const
|
||||
{
|
||||
#define TO_RGB(color, red, green, blue) \
|
||||
const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color;
|
||||
const uInt8 red = uInt8(color >> 16); \
|
||||
const uInt8 green = uInt8(color >> 8);\
|
||||
const uInt8 blue = uInt8(color);
|
||||
|
||||
TO_RGB(c, rc, gc, bc);
|
||||
TO_RGB(p, rp, gp, bp);
|
||||
|
@ -332,9 +334,9 @@ void AtariNTSC::init(init_t& impl, const Setup& setup)
|
|||
initFilters(impl, setup);
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
if (true) /* was (gamma_size > 1) */
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const to_float = 1.0f / (gamma_size - 1/*(gamma_size > 1)*/);
|
||||
float const gamma = 1.1333f - float(setup.gamma) * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
|
@ -367,9 +369,10 @@ void AtariNTSC::init(init_t& impl, const Setup& setup)
|
|||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n2 );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
#if 0 // burst_count is always 0
|
||||
if ( burst_count > 1 )
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
#endif
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
|
@ -383,7 +386,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup)
|
|||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + float(setup.sharpness) * 0.032;
|
||||
float const rolloff = 1 + float(setup.sharpness) * 0.032f;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = float(pow( rolloff, maxh ));
|
||||
float sum;
|
||||
|
@ -406,7 +409,7 @@ void AtariNTSC::initFilters(init_t& impl, const Setup& setup)
|
|||
pow_a_n * rolloff * float(cos( (maxh - 1) * angle ));
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - 0.5;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,7 +539,7 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out)
|
|||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
while ( /*alignment_count > 1 && */ --alignment_remain );
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
|
|
@ -185,7 +185,11 @@ class AtariNTSC
|
|||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
|
||||
init_t() : contrast(0.0), brightness(0.0), artifacts(0.0), fringing(0.0) { }
|
||||
init_t() : contrast(0.0), brightness(0.0), artifacts(0.0), fringing(0.0) {
|
||||
std::fill(to_rgb, to_rgb + burst_count * 6, 0.0);
|
||||
std::fill(to_float, to_float + gamma_size, 0.0);
|
||||
std::fill(kernel, kernel + rescale_out * kernel_size * 2, 0.0);
|
||||
}
|
||||
};
|
||||
init_t myImpl;
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ string NTSCFilter::setPreviousAdjustable()
|
|||
return "'Custom' TV mode not selected";
|
||||
|
||||
if(myCurrentAdjustable == 0) myCurrentAdjustable = 9;
|
||||
else myCurrentAdjustable--;
|
||||
else --myCurrentAdjustable;
|
||||
ostringstream buf;
|
||||
buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type
|
||||
<< "' selected";
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "System.hxx"
|
||||
#include "M6502.hxx"
|
||||
|
@ -462,7 +460,7 @@ bool CartDebug::addDirective(CartDebug::DisasmType type,
|
|||
i->end = tag.start - 1;
|
||||
|
||||
// Insert new endpoint
|
||||
i++;
|
||||
++i;
|
||||
list.insert(i, tag2);
|
||||
break; // no need to go further; this is the insertion point
|
||||
}
|
||||
|
@ -1101,10 +1099,9 @@ string CartDebug::saveDisassembly()
|
|||
}
|
||||
|
||||
// Some boilerplate, similar to what DiStella adds
|
||||
time_t currtime;
|
||||
time(&currtime);
|
||||
auto timeinfo = BSPF::localTime();
|
||||
out << "; Disassembly of " << myOSystem.romFile().getShortPath() << "\n"
|
||||
<< "; Disassembled " << ctime(&currtime)
|
||||
<< "; Disassembled " << std::put_time(&timeinfo, "%c\n")
|
||||
<< "; Using Stella " << STELLA_VERSION << "\n;\n"
|
||||
<< "; ROM properties name : " << myConsole.properties().get(Cartridge_Name) << "\n"
|
||||
<< "; ROM properties MD5 : " << myConsole.properties().get(Cartridge_MD5) << "\n"
|
||||
|
@ -1182,10 +1179,10 @@ string CartDebug::saveDisassembly()
|
|||
out << "\n";
|
||||
out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $"
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< (stackUsed|codeUsed ? "; (" : "")
|
||||
<< ((stackUsed|codeUsed) ? "; (" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< (stackUsed | codeUsed ? ")" : "")
|
||||
<< ((stackUsed | codeUsed) ? ")" : "")
|
||||
<< "\n";
|
||||
addLine = false;
|
||||
} else if (ramUsed|codeUsed|stackUsed) {
|
||||
|
@ -1292,7 +1289,7 @@ string CartDebug::clearConfig(int bank)
|
|||
endbank = startbank + 1;
|
||||
}
|
||||
|
||||
uInt32 count = 0;
|
||||
size_t count = 0;
|
||||
for(uInt32 b = startbank; b < endbank; ++b)
|
||||
{
|
||||
count += myBankInfo[b].directiveList.size();
|
||||
|
|
|
@ -33,6 +33,8 @@ class CpuState : public DebuggerState
|
|||
int PC, SP, PS, A, X, Y;
|
||||
int srcS, srcA, srcX, srcY;
|
||||
BoolArray PSbits;
|
||||
|
||||
CpuState() : PC(0), SP(0), PS(0), A(0), X(0), Y(0), srcS(0), srcA(0), srcX(0), srcY(0) { }
|
||||
};
|
||||
|
||||
class CpuDebug : public DebuggerSystem
|
||||
|
|