Merge branch 'release/6.0'

This commit is contained in:
Christian Speckner 2018-09-16 23:15:39 +02:00
commit 37a2de58f4
335 changed files with 7510 additions and 6998 deletions

10
.vscode/settings.json vendored
View File

@ -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"
}
}

View File

@ -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

View File

@ -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!

7
debian/changelog vendored
View File

@ -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

View File

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -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 -&gt; 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">&nbsp;&nbsp;</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 &lt;number&gt;</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 &lt;sleep|busy&gt;</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 &lt;number&gt;</pre></td>
<td>Control the emulation speed (as a percentage, 10 - 1000).</td>
</tr>
<tr>
@ -2196,7 +2182,7 @@
<tr>
<td><pre>-snaploaddir &lt;path&gt;</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 &lt;allfiles|allroms|LIST&gt;</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 &lt;1|0&gt;</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>&nbsp;</td></tr>
<tr><td>Clone S-Video</td><td>Copy 'S-Video' attributes to 'Custom' sliders</td><td>&nbsp;</td></tr>
<tr><td>Clone RGB</td><td>Copy 'RGB' attributes to 'Custom' sliders</td><td>&nbsp;</td></tr>
<tr><td>Clone Bad Adjust</td><td>Copy 'Bad Adjust' attributes to 'Custom' sliders</td><td>&nbsp;</td></tr>
<tr><td>Clone Bad adjust</td><td>Copy 'Bad Adjust' attributes to 'Custom' sliders</td><td>&nbsp;</td></tr>
<tr><td>Revert</td><td>Revert attribute sliders to saved 'Custom' settings</td><td>&nbsp;</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>&nbsp;&nbsp;&nbsp;&nbsp;</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>&nbsp;&nbsp;&nbsp;&nbsp;</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>&nbsp;</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>&nbsp;</td></tr>
<tr><td>Erase EEPROM</td><td>Erase the whole AtariVox/SaveKey flash memory</td><td>&nbsp;</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 (&#185;) do not currently have reliable auto-detection, those marked as (&#178;)
are not fully supported in the debugger:
<table cellpadding="2" border="1">
<tr><th>&nbsp;Type&nbsp;</th><th>Description</th></tr>
<tr><td>0840 </td><td>8K ECONObanking </td></tr>
<tr><td>2IN1 &#185;</td><td>4-32K Multicart (2 games) </td></tr>
<tr><td>4IN1 &#185;</td><td>8-32K Multicart (4 games) </td></tr>
<tr><td>8IN1 &#185;</td><td>16-64K Multicart (8 games) </td></tr>
<tr><td>16IN1 &#185;</td><td>32-128K Multicart (16 games) </td></tr>
<tr><td>32IN1 &#185;</td><td>64-128K Multicart (32 games) </td></tr>
<tr><td>64IN1 &#185;</td><td>64/128K Multicart </td></tr>
<tr><td>128IN1 &#185;</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 &#178;</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 &#185;</td><td>Spectravideo CompuMate </td></tr>
<tr><td>CTY &#185;&#178;</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 &#185;</td><td>64K AtariAge </td></tr>
<tr><th>&nbsp;Type&nbsp;</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 &#185;</td><td>4-32K Multicart (2 games) </td><td>.2N1 </td></tr>
<tr><td>4IN1 &#185;</td><td>8-32K Multicart (4 games) </td><td>.4N1 </td></tr>
<tr><td>8IN1 &#185;</td><td>16-64K Multicart (8 games) </td><td>.8N1 </td></tr>
<tr><td>16IN1 &#185;</td><td>32-128K Multicart (16 games) </td><td>.16N </td></tr>
<tr><td>32IN1 &#185;</td><td>64-128K Multicart (32 games) </td><td>.32N </td></tr>
<tr><td>64IN1 &#185;</td><td>64/128K Multicart </td><td>.64N </td></tr>
<tr><td>128IN1 &#185;</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 &#178;</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 &#185;</td><td>Spectravideo CompuMate </td><td>.CM </td></tr>
<tr><td>CTY &#185;&#178;</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 &#185;</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>

View File

@ -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)

View File

@ -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() << ":"

View File

@ -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.

View File

@ -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)

View File

@ -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;

View File

@ -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)));
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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)

View File

@ -26,7 +26,7 @@ class FpsMeter
{
public:
FpsMeter(uInt32 queueSize);
explicit FpsMeter(uInt32 queueSize);
void reset(uInt32 garbageFrameLimit = 0);

View File

@ -15,8 +15,6 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <ctime>
#include "SDL_lib.hxx"
#include "bspf.hxx"

View File

@ -40,7 +40,7 @@ class FrameBufferSDL2 : public FrameBuffer
/**
Creates a new SDL2 framebuffer
*/
FrameBufferSDL2(OSystem& osystem);
explicit FrameBufferSDL2(OSystem& osystem);
virtual ~FrameBufferSDL2();
//////////////////////////////////////////////////////////////////////

View File

@ -84,7 +84,7 @@ class LinkedObjectPool
iter it = myCurrent;
uInt32 idx = 1;
while(it-- != myList.begin()) idx++;
while(it-- != myList.begin()) ++idx;
return idx;
}

View File

@ -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),

View File

@ -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;

View File

@ -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());

View File

@ -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,

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -43,7 +43,7 @@ class StateManager
/**
Create a new statemananger class.
*/
StateManager(OSystem& osystem);
explicit StateManager(OSystem& osystem);
~StateManager();
public:

View File

@ -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));

260
src/common/TimerManager.cxx Normal file
View File

@ -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)
{
}

193
src/common/TimerManager.hxx Normal file
View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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];
}

View File

@ -24,7 +24,7 @@ class ConvolutionBuffer
{
public:
ConvolutionBuffer(uInt32 size);
explicit ConvolutionBuffer(uInt32 size);
void shift(float nextValue);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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", "");
}

View File

@ -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 \

View File

@ -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 );
}

View File

@ -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;

View File

@ -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";

View File

@ -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();

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More