Merge branch 'master' into feature/filesystem

This commit is contained in:
Stephen Anthony 2022-09-04 19:59:40 -02:30
commit 52e50fea8d
6 changed files with 142 additions and 37 deletions

View File

@ -25,6 +25,8 @@
* Added Joy2B+ controller support * Added Joy2B+ controller support
* Enhanced Kid Vid support to play tape audio
* Added BUS bankswitching support for some older demos * Added BUS bankswitching support for some older demos
* Fixed broken 7800 pause key support * Fixed broken 7800 pause key support

View File

@ -21,7 +21,7 @@
<img src="graphics/stella_icon.png"> <img src="graphics/stella_icon.png">
<h2><b>A multi-platform Atari 2600 VCS emulator</b></h2> <h2><b>A multi-platform Atari 2600 VCS emulator</b></h2>
<h4><b>Release 6.7</b></h4> <h4><b>Release 7.0</b></h4>
<br> <br>
<h2><b>User's Guide</b></h2> <h2><b>User's Guide</b></h2>
@ -282,6 +282,7 @@
<li>Emulates <a href="https://en.wikipedia.org/wiki/CompuMate">Spectravideo CompuMate</a> system using your computer's keyboard, <li>Emulates <a href="https://en.wikipedia.org/wiki/CompuMate">Spectravideo CompuMate</a> system using your computer's keyboard,
including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to
to the actual keys on your keyboard</li> to the actual keys on your keyboard</li>
<li>Emulates the Kid Vid Voice Module</li>
<li>Supports autodetection for most common controller types</li> <li>Supports autodetection for most common controller types</li>
<li>Support for real Atari 2600 controllers using the <li>Support for real Atari 2600 controllers using the
<a href="http://www.grandideastudio.com/stelladaptor-2600">Stelladaptor</a> and <a href="http://www.grandideastudio.com/stelladaptor-2600">Stelladaptor</a> and
@ -1047,6 +1048,17 @@
</tr> </tr>
</table> </table>
</br>
<p><b>Kid Vid Voice Module (can be remapped via Keyboard Controller)</b></p>
<table BORDER=2>
<tr><th>Function</th> <th>Key</th></tr>
<tr><td>Start game #1</td><td>8 (same as Right Pad Button '1')</td></tr>
<tr><td>Start game #2</td><td>9 (same as Right Pad Button '2')</td></tr>
<tr><td>Start game #3</td><td>0 (same as Right Pad Button '3')</td></tr>
<tr><td>Skip current song</td><td>P (same as Right Pad Button '6')</td></tr>
</table>
</br> </br>
<p><b>CompuMate Controller (cannot be remapped)</b></p> <p><b>CompuMate Controller (cannot be remapped)</b></p>
@ -1071,7 +1083,6 @@
<tr><td>[ </td><td>[ or Shift + 8 </td></tr> <tr><td>[ </td><td>[ or Shift + 8 </td></tr>
<tr><td>] </td><td>] or Shift + 9 </td></tr> <tr><td>] </td><td>] or Shift + 9 </td></tr>
<tr><td>&quot; </td><td>" (Shift + ') or Shift + 0 </td></tr> <tr><td>&quot; </td><td>" (Shift + ') or Shift + 0 </td></tr>
</table> </table>
</br> </br>
@ -5023,7 +5034,12 @@ Ms Pac-Man (Stella extended codes):
<tr><td>CompuMate &#185</td><td>Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).</td></tr> <tr><td>CompuMate &#185</td><td>Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).</td></tr>
<tr><td>Lightgun</td><td>Atari XG-1 compatible Light Gun.</td></tr> <tr><td>Lightgun</td><td>Atari XG-1 compatible Light Gun.</td></tr>
<tr><td>MindLink &#185</td><td>MindLink controller.</td></tr> <tr><td>MindLink &#185</td><td>MindLink controller.</td></tr>
<tr><td>KidVid</td><td>Kid Vid Voice Module, limited support (Right Keyboard controller buttons 1, 2 and 3 start the games, default mapping is 8, 9 and 0).</td></tr> <tr><td>KidVid</td><td>Kid Vid Voice Module.</br>
Audio files can be downloaded e.g. from <a href="https://www.atariage.com/2600/archives/KidVidAudio/">AtariAge</a>.
Put unzipped .WAV files into Stella's base directory (see properties
or palette files below for details).</br>
Note: Stella supports playing the games without audio files too.
</td></tr>
<tr><td>QuadTari</td><td><a href="#Quadtari">QuadTari</a> controller, limited support (see below).</td></tr> <tr><td>QuadTari</td><td><a href="#Quadtari">QuadTari</a> controller, limited support (see below).</td></tr>
</table></td> </table></td>
</tr> </tr>

View File

@ -453,7 +453,7 @@ void SoundSDL2::stopWav()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundSDL2::wavSize() const uInt32 SoundSDL2::wavSize() const
{ {
return myWavBuffer ? myWavLen /*SDL_GetQueuedAudioSize(myWavDevice)*/ : 0; return myWavBuffer ? myWavLen : 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -18,7 +18,7 @@
#ifndef STATE_MANAGER_HXX #ifndef STATE_MANAGER_HXX
#define STATE_MANAGER_HXX #define STATE_MANAGER_HXX
#define STATE_HEADER "06070000state" #define STATE_HEADER "06070002state"
class OSystem; class OSystem;
class RewindManager; class RewindManager;

View File

@ -29,9 +29,9 @@ KidVid::KidVid(Jack jack, const Event& event, const System& system,
{ {
// Right now, there are only two games that use the KidVid // Right now, there are only two games that use the KidVid
if(romMd5 == "ee6665683ebdb539e89ba620981cb0f6") if(romMd5 == "ee6665683ebdb539e89ba620981cb0f6")
myGame = BBears; // Berenstain Bears myGame = Game::BBears; // Berenstain Bears
else if(romMd5 == "a204cd4fb1944c86e800120706512a64") else if(romMd5 == "a204cd4fb1944c86e800120706512a64")
myGame = Smurfs; // Smurfs Save the Day myGame = Game::Smurfs; // Smurfs Save the Day
else else
myEnabled = false; myEnabled = false;
} }
@ -58,12 +58,29 @@ void KidVid::update()
if(!myEnabled) if(!myEnabled)
return; return;
if(myEvent.get(Event::ConsoleReset)) if(myContinueSong)
{
// Continue playing song after state load
const uInt8 temp = ourSongPositions[mySongPointer - 1] & 0x7f;
const uInt32 songLength = ourSongStart[temp + 1] - ourSongStart[temp];
// Play the remaining WAV file
const string& fileName = myBaseDir + ((temp < 10) ? "KVSHARED.WAV" : getFileName());
mySound.playWav(fileName, ourSongStart[temp] + (songLength - mySongLength), mySongLength);
myContinueSong = false;
}
if(myGame == Game::Smurfs && myEvent.get(Event::ConsoleReset)) // Reset does not work with BBears!
{ {
myTape = 0; // rewind Kid Vid tape myTape = 0; // rewind Kid Vid tape
myFilesFound = mySongPlaying = false; myFilesFound = mySongPlaying = false;
mySound.stopWav(); mySound.stopWav();
} }
else if(myEvent.get(Event::RightKeyboard6))
{
mySound.stopWav();
}
if(!myTape) if(!myTape)
{ {
if(myEvent.get(Event::RightKeyboard1)) if(myEvent.get(Event::RightKeyboard1))
@ -71,10 +88,10 @@ void KidVid::update()
else if(myEvent.get(Event::RightKeyboard2)) else if(myEvent.get(Event::RightKeyboard2))
myTape = 3; myTape = 3;
else if(myEvent.get(Event::RightKeyboard3)) else if(myEvent.get(Event::RightKeyboard3))
myTape = myGame == BBears ? 4 : 1; // Berenstain Bears or Smurfs Save The Day? myTape = myGame == Game::BBears ? 4 : 1; // Berenstain Bears or Smurfs Save The Day?
if(myTape) if(myTape)
{ {
myIdx = myGame == BBears ? NumBlockBits : 0; myIdx = myGame == Game::BBears ? NumBlockBits : 0; // KVData48/KVData44
myBlockIdx = NumBlockBits; myBlockIdx = NumBlockBits;
myBlock = 0; myBlock = 0;
openSampleFiles(); openSampleFiles();
@ -94,17 +111,17 @@ void KidVid::update()
if(!myBlockIdx) if(!myBlockIdx)
{ {
if(!myBlock) if(!myBlock)
myIdx = ((myTape * 6) + 12 - NumBlocks) * 8; //KVData00-KVData=12 myIdx = ((myTape * 6) + 12 - NumBlocks) * 8; // KVData00 - ourData = 12 (2 * 6)
else else
{ {
const uInt32 lastBlock = myGame == Smurfs const uInt32 lastBlock = myGame == Game::Smurfs
? ourBlocks[myTape - 1] ? ourBlocks[myTape - 1]
: ourBlocks[myTape + 2 - 1]; : ourBlocks[myTape + 2 - 1];
if(myBlock >= lastBlock) if(myBlock >= lastBlock)
myIdx = 42 * 8; //KVData80-KVData=42 myIdx = 42 * 8; // KVData80 - ourData = 42 (7 * 6)
else else
{ {
myIdx = 36 * 8;//KVPause-KVData=36 myIdx = 36 * 8; // KVPause - ourData = 36 (6 * 6)
setNextSong(); setNextSong();
} }
} }
@ -117,9 +134,10 @@ void KidVid::update()
{ {
if(mySongPlaying) if(mySongPlaying)
{ {
myTapeBusy = (mySound.wavSize() > 262 * 48) || !myBeep; mySongLength = mySound.wavSize();
myTapeBusy = (mySongLength > 262 * 48) || !myBeep;
// Check for end of played sample // Check for end of played sample
if(mySound.wavSize() == 0) if(mySongLength == 0)
{ {
mySongPlaying = false; mySongPlaying = false;
myTapeBusy = !myBeep; myTapeBusy = !myBeep;
@ -139,12 +157,62 @@ void KidVid::update()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::openSampleFiles() bool KidVid::save(Serializer& out) const
{
// Save WAV player state
out.putInt(myTape);
out.putBool(myFilesFound);
out.putBool(myTapeBusy);
out.putBool(myBeep);
out.putBool(mySongPlaying);
out.putInt(mySongPointer);
out.putInt(mySongLength);
// Save tape input simulation state
out.putInt(myIdx);
out.putInt(myBlockIdx);
out.putInt(myBlock);
return Controller::save(out);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KidVid::load(Serializer& in)
{
// Load WAV player state
myTape = in.getInt();
myFilesFound = in.getBool();
myTapeBusy = in.getBool();
myBeep = in.getBool();
mySongPlaying = in.getBool();
mySongPointer = in.getInt();
mySongLength = in.getInt();
// Load tape input simulation state
myIdx = in.getInt();
myBlockIdx = in.getInt();
myBlock = in.getInt();
myContinueSong = myFilesFound && mySongPlaying;
return Controller::load(in);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* KidVid::getFileName() const
{ {
static constexpr const char* fileNames[6] = { static constexpr const char* fileNames[6] = {
"KVS3.WAV", "KVS1.WAV", "KVS2.WAV", "KVS3.WAV", "KVS1.WAV", "KVS2.WAV",
"KVB3.WAV", "KVB1.WAV", "KVB2.WAV" "KVB3.WAV", "KVB1.WAV", "KVB2.WAV"
}; };
int i = myGame == Game::Smurfs ? myTape - 1 : myTape + 2;
if(myTape == 4) i = 3;
return fileNames[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::openSampleFiles()
{
static constexpr uInt32 firstSongPointer[6] = { static constexpr uInt32 firstSongPointer[6] = {
44 + 38, 44 + 38,
0, 0,
@ -156,13 +224,11 @@ void KidVid::openSampleFiles()
if(!myFilesFound) if(!myFilesFound)
{ {
int i = myGame == Smurfs ? myTape - 1 : myTape + 2; int i = myGame == Game::Smurfs ? myTape - 1 : myTape + 2;
if(myTape == 4) i = 3; if(myTape == 4) i = 3;
mySampleFile = myBaseDir + fileNames[i];
std::ifstream f1, f2; std::ifstream f1, f2;
f1.open(mySampleFile); f1.open(myBaseDir + getFileName());
f2.open(myBaseDir + "KVSHARED.WAV"); f2.open(myBaseDir + "KVSHARED.WAV");
myFilesFound = f1.is_open() && f2.is_open(); myFilesFound = f1.is_open() && f2.is_open();
@ -170,7 +236,7 @@ void KidVid::openSampleFiles()
#ifdef DEBUG_BUILD #ifdef DEBUG_BUILD
if(myFilesFound) if(myFilesFound)
cerr << endl cerr << endl
<< "found file: " << fileNames[i] << endl << "found file: " << getFileName() << endl
<< "found file: " << "KVSHARED.WAV" << endl; << "found file: " << "KVSHARED.WAV" << endl;
#endif #endif
@ -191,8 +257,8 @@ void KidVid::setNextSong()
mySongLength = ourSongStart[temp + 1] - ourSongStart[temp]; mySongLength = ourSongStart[temp + 1] - ourSongStart[temp];
// Play the WAV file // Play the WAV file
const string& fileName = (temp < 10) ? myBaseDir + "KVSHARED.WAV" : mySampleFile; const string& fileName = (temp < 10) ? "KVSHARED.WAV" : getFileName();
mySound.playWav(fileName, ourSongStart[temp], mySongLength); mySound.playWav(myBaseDir + fileName, ourSongStart[temp], mySongLength);
#ifdef DEBUG_BUILD #ifdef DEBUG_BUILD
cerr << fileName << ": " << (ourSongPositions[mySongPointer] & 0x7f) << endl; cerr << fileName << ": " << (ourSongPositions[mySongPointer] & 0x7f) << endl;
#endif #endif
@ -216,7 +282,7 @@ const std::array<uInt8, KidVid::NumBlocks> KidVid::ourBlocks = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const std::array<uInt8, KidVid::NumBlockBits> KidVid::ourData = { const std::array<uInt8, KidVid::NumBlockBits> KidVid::ourData = {
/* KVData44 */ /* KVData44, Smurfs */
0x7b, // 0111 1011b ; (1)0 0x7b, // 0111 1011b ; (1)0
0x1e, // 0001 1110b ; 1 0x1e, // 0001 1110b ; 1
0xc6, // 1100 0110b ; 00 0xc6, // 1100 0110b ; 00
@ -224,7 +290,7 @@ const std::array<uInt8, KidVid::NumBlockBits> KidVid::ourData = {
0xec, // 1110 1100b ; 0 0xec, // 1110 1100b ; 0
0x60, // 0110 0000b ; 0+ 0x60, // 0110 0000b ; 0+
/* KVData48 */ /* KVData48, BBears */
0x7b, // 0111 1011b ; (1)0 0x7b, // 0111 1011b ; (1)0
0x1e, // 0001 1110b ; 1 0x1e, // 0001 1110b ; 1
0xc6, // 1100 0110b ; 00 0xc6, // 1100 0110b ; 00

View File

@ -67,12 +67,31 @@ class KidVid : public Controller
*/ */
void update() override; void update() override;
/**
Saves the current state of this controller to the given Serializer.
@param out The serializer device to save to.
@return The result of the save. True on success, false on failure.
*/
bool save(Serializer& out) const override;
/**
Loads the current state of this controller from the given Serializer.
@param in The serializer device to load from.
@return The result of the load. True on success, false on failure.
*/
bool load(Serializer& in) override;
/** /**
Returns the name of this controller. Returns the name of this controller.
*/ */
string name() const override { return "KidVid"; } string name() const override { return "KidVid"; }
private: private:
// Get name of the current sample file
const char* getFileName() const;
// Open/close a WAV sample file // Open/close a WAV sample file
void openSampleFiles(); void openSampleFiles();
@ -80,36 +99,38 @@ class KidVid : public Controller
void setNextSong(); void setNextSong();
private: private:
enum class Game {
Smurfs,
BBears
};
static constexpr uInt32 static constexpr uInt32
Smurfs = 0x44, NumBlocks = 6, // number of bytes / block
BBears = 0x48, NumBlockBits = NumBlocks * 8, // number of bits / block
NumBlocks = 6, // number of bytes / block SongPosSize = 44 + 38 + 42 + 62 + 80 + 62,
NumBlockBits = NumBlocks*8, // number of bits / block
SongPosSize = 44+38+42+62+80+62,
SongStartSize = 104 SongStartSize = 104
; ;
// Whether the KidVid device is enabled (only for games that it // Whether the KidVid device is enabled (only for games that it
// supports, and if it's plugged into the right port // supports, and if it's plugged into the right port)
bool myEnabled{false}; bool myEnabled{false};
string myBaseDir; string myBaseDir;
Sound& mySound; Sound& mySound;
// Path and name of the current sample file
string mySampleFile;
// Indicates if the sample files have been found // Indicates if the sample files have been found
bool myFilesFound{false}; bool myFilesFound{false};
uInt32 mySongPointer{0};
// Is the tape currently 'busy' / in use? // Is the tape currently 'busy' / in use?
bool myTapeBusy{false}; bool myTapeBusy{false};
bool mySongPlaying{false}; bool mySongPlaying{false};
// Continue song after loading state?
bool myContinueSong{false};
uInt32 mySongPointer{0};
uInt32 mySongLength{0}; uInt32 mySongLength{0};
bool myBeep{false}; bool myBeep{false};
uInt32 myGame{0}, myTape{0}; Game myGame{Game::Smurfs};
uInt32 myTape{0};
uInt32 myIdx{0}, myBlock{0}, myBlockIdx{0}; uInt32 myIdx{0}, myBlock{0}, myBlockIdx{0};
// Number of blocks and data on tape // Number of blocks and data on tape