+  |
+ |
+
+
+ Item | Description |
+ Top row | Displays the current game's name. |
+ Variation | By default the current game's variation is
+ selected. By changing the variation, the high scores of other
+ variations can be reviewed. |
+ High scores table | This table displays up to ten high scores
+ for the current game variation.
+
+ - Besides 'Rank' and 'Score' an optional special value (e.g.
+ 'Level', 'Wave' or 'Round') is displayed.
+ - In the 'Name' column, the player's initials are displayed.
+ These can be entered when a new high score is added to the list.
+ - 'Date' and 'Time' record when the high score was added.
+ - The buttons at the right allow deleting individual high
+ scores from the list.
+
+ |
+ MD5/Props | Display the checksums of the current ROM and the
+ high score properties defined for it. This can be useful for
+ comparing and verifying high scores. |
+ Reset | Resets all high scores of the currently selected
+ variation. |
+ Save | Saves the updated high scores and closes the dialog.
+ |
+ Cancel | Closes the dialog without saving. |
+
- This dialog can be opened by pressing 'Insert' any time while a game is
- played. It will provide the current variation and score and allow the user
- to add this as a new high score. Of course this makes most sense when a game
- is over. Note: In multiplayer games, only the score of the first player can be
- saved.
- The dialog items are explained in the following two tables.
-
-
- Item | Description |
- Top row | Displays the current game's name. |
- Variation | By default the current game's variation is
- selected. By changing the variation, the high scores of other
- variations can be reviewed. |
- High scores table | This table displays up to ten high scores
- for the current game variation.
-
- - Besides 'Rank' and 'Score' an optional special value (e.g.
- 'Level', 'Wave' or 'Round') is displayed.
- - In the 'Name' column, the player's initials are displayed.
- These can be entered when a new high score is added to the list.
- - 'Date' and 'Time' record when the high score was added.
- - The buttons at the right allow deleting individual high
- scores from the list.
-
- |
- MD5/Props | Display the checksums of the current ROM and the
- high score properties defined for it. This can be useful for
- comparing and verifying high scores. |
- Reset | Resets all high scores of the currently selected
- variation. |
- Save | Saves the updated high scores and closes the dialog.
- |
- Cancel | Closes the dialog without saving. |
+
+
+
For details how to configure high scores definintions for a game see
High Scores Properties.
@@ -3511,7 +3518,7 @@
User Interface Settings dialog (2 tabs):
- 
|
+  |
|
@@ -3530,12 +3537,13 @@
-  |
+  |
|
-  |
+  |
-  |
+  |
+
diff --git a/src/common/HighScoresManager.cxx b/src/common/HighScoresManager.cxx
index 6c16d589a..59946b29b 100644
--- a/src/common/HighScoresManager.cxx
+++ b/src/common/HighScoresManager.cxx
@@ -422,33 +422,28 @@ string HighScoresManager::md5Props() const
bool HighScoresManager::scoreInvert() const
{
json jprops;
+
return scoreInvert(properties(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::special() const
{
+ if(!myOSystem.hasConsole())
+ return NO_VALUE;
+
json jprops;
uInt16 addr = specialAddress(properties(jprops));
if (addr == DEFAULT_ADDRESS)
return NO_VALUE;
- return special(addr, specialBCD(jprops), specialZeroBased(jprops));
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Int32 HighScoresManager::special(uInt16 addr, bool varBCD, bool zeroBased) const
-{
- if (!myOSystem.hasConsole())
- return NO_VALUE;
-
Int32 var = peek(addr);
- if (varBCD)
+ if(specialBCD(jprops))
var = fromBCD(var);
- var += zeroBased ? 1 : 0;
+ var += specialZeroBased(jprops) ? 1 : 0;
return var;
}
diff --git a/src/common/HighScoresManager.hxx b/src/common/HighScoresManager.hxx
index 19b1ee2f2..6768840c4 100644
--- a/src/common/HighScoresManager.hxx
+++ b/src/common/HighScoresManager.hxx
@@ -131,9 +131,6 @@ class HighScoresManager
*/
uInt32 numAddrBytes(Int32 digits, Int32 trailing) const;
-
- Int32 special(uInt16 addr, bool varBCD, bool zeroBased) const;
-
// Retrieve current values (using game's properties)
Int32 numVariations() const;
const string specialLabel() const;
diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx
index d908cd82c..94ae7c82c 100644
--- a/src/emucore/EventHandler.cxx
+++ b/src/emucore/EventHandler.cxx
@@ -2388,7 +2388,6 @@ void EventHandler::enterPlayBackMode()
{
#ifdef GUI_SUPPORT
setState(EventHandlerState::PLAYBACK);
- myOSystem.sound().mute(true); // sound does not work in playback mode
#endif
}
diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx
index 3ee961795..a1b1ba294 100644
--- a/src/emucore/FrameBuffer.cxx
+++ b/src/emucore/FrameBuffer.cxx
@@ -25,6 +25,7 @@
#include "Settings.hxx"
#include "TIA.hxx"
#include "Sound.hxx"
+#include "AudioSettings.hxx"
#include "MediaFactory.hxx"
#include "FBSurface.hxx"
@@ -440,23 +441,24 @@ void FrameBuffer::update(UpdateMode mode)
case EventHandlerState::PLAYBACK:
{
static Int32 frames = 0;
- RewindManager& r = myOSystem.state().rewindManager();
bool success = true;
- Int64 frameCycles = 76 * std::max(myOSystem.console().tia().scanlinesLastFrame(), 240);
if(--frames <= 0)
{
- r.unwindStates(1);
- // get time between current and next state
- uInt64 startCycles = r.getCurrentCycles();
+ RewindManager& r = myOSystem.state().rewindManager();
+ uInt64 prevCycles = r.getCurrentCycles();
+
success = r.unwindStates(1);
- // display larger state gaps faster
- frames = std::sqrt((myOSystem.console().tia().cycles() - startCycles) / frameCycles);
- if(success)
- r.rewindStates(1);
+ Int64 frameCycles = 76 * std::max(myOSystem.console().tia().scanlinesLastFrame(), 240);
+
+ // Use time between previous and current state
+ // to playback larger state gaps faster
+ frames = std::sqrt((r.getCurrentCycles() - prevCycles) / frameCycles);
+
+ // TODO: test and verify with CS
+ //myOSystem.sound().mute(uInt32(frames) > myOSystem.audioSettings().headroom() / 2 + 1);
}
-
redraw |= success;
if(redraw)
myTIASurface->render();
diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx
index 4ad8b035e..40271748c 100644
--- a/src/emucore/OSystem.cxx
+++ b/src/emucore/OSystem.cxx
@@ -839,7 +839,15 @@ void OSystem::mainLoop()
if (myEventHandler->state() == EventHandlerState::EMULATION)
// Dispatch emulation and render frame (if applicable)
timesliceSeconds = dispatchEmulation(emulationWorker);
- else {
+ else if(myEventHandler->state() == EventHandlerState::PLAYBACK)
+ {
+ // Playback at emulation speed
+ timesliceSeconds = static_cast(myConsole->tia().scanlinesLastFrame() * 76) /
+ static_cast(myConsole->emulationTiming().cyclesPerSecond());
+ myFrameBuffer->update();
+ }
+ else
+ {
// Render the GUI with 60 Hz in all other modes
timesliceSeconds = 1. / 60.;
myFrameBuffer->update();
diff --git a/src/emucore/tia/Audio.cxx b/src/emucore/tia/Audio.cxx
index 4ddb78179..bbf3e2071 100644
--- a/src/emucore/tia/Audio.cxx
+++ b/src/emucore/tia/Audio.cxx
@@ -86,16 +86,26 @@ void Audio::phase1()
uInt8 sample0 = myChannel0.phase1();
uInt8 sample1 = myChannel1.phase1();
- if (!myAudioQueue) return;
+ addSample(sample0, sample1);
+#ifdef GUI_SUPPORT
+ mySamples.push_back(sample0 | (sample1 << 4));
+#endif
+}
- if (myAudioQueue->isStereo()) {
- myCurrentFragment[2*mySampleIndex] = myMixingTableIndividual[sample0];
- myCurrentFragment[2*mySampleIndex + 1] = myMixingTableIndividual[sample1];
- } else {
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void Audio::addSample(uInt8 sample0, uInt8 sample1)
+{
+ if(!myAudioQueue) return;
+
+ if(myAudioQueue->isStereo()) {
+ myCurrentFragment[2 * mySampleIndex] = myMixingTableIndividual[sample0];
+ myCurrentFragment[2 * mySampleIndex + 1] = myMixingTableIndividual[sample1];
+ }
+ else {
myCurrentFragment[mySampleIndex] = myMixingTableSum[sample0 + sample1];
}
- if (++mySampleIndex == myAudioQueue->fragmentSize()) {
+ if(++mySampleIndex == myAudioQueue->fragmentSize()) {
mySampleIndex = 0;
myCurrentFragment = myAudioQueue->enqueue(myCurrentFragment);
}
@@ -125,6 +135,16 @@ bool Audio::save(Serializer& out) const
if (!myChannel0.save(out)) return false;
if (!myChannel1.save(out)) return false;
+ #ifdef GUI_SUPPORT
+ out.putLong(uInt64(mySamples.size()));
+ out.putByteArray(mySamples.data(), mySamples.size());
+
+ // TODO: check if this improves sound of playback for larger state gaps
+ //out.putInt(mySampleIndex);
+ //out.putShortArray((uInt16*)myCurrentFragment, myAudioQueue->fragmentSize());
+
+ mySamples.clear();
+ #endif
}
catch(...)
{
@@ -144,6 +164,24 @@ bool Audio::load(Serializer& in)
if (!myChannel0.load(in)) return false;
if (!myChannel1.load(in)) return false;
+ #ifdef GUI_SUPPORT
+ uInt64 sampleSize = in.getLong();
+ unique_ptr samples = make_unique(sampleSize);
+ in.getByteArray(samples.get(), sampleSize);
+
+ //mySampleIndex = in.getInt();
+ //in.getShortArray((uInt16*)myCurrentFragment, myAudioQueue->fragmentSize());
+
+ // Feed all loaded samples into the audio queue
+ for(size_t i = 0; i < sampleSize; i++)
+ {
+ uInt8 sample = samples[i];
+ uInt8 sample0 = sample & 0x0f;
+ uInt8 sample1 = sample >> 4;
+
+ addSample(sample0, sample1);
+ }
+ #endif
}
catch(...)
{
diff --git a/src/emucore/tia/Audio.hxx b/src/emucore/tia/Audio.hxx
index 5ab53ecae..d4158bf72 100644
--- a/src/emucore/tia/Audio.hxx
+++ b/src/emucore/tia/Audio.hxx
@@ -47,6 +47,7 @@ class Audio : public Serializable
private:
void phase1();
+ void addSample(uInt8 sample0, uInt8 sample1);
private:
shared_ptr myAudioQueue;
@@ -61,6 +62,9 @@ class Audio : public Serializable
Int16* myCurrentFragment{nullptr};
uInt32 mySampleIndex{0};
+ #ifdef GUI_SUPPORT
+ mutable ByteArray mySamples;
+ #endif
private:
Audio(const Audio&) = delete;
diff --git a/src/gui/WhatsNewDialog.cxx b/src/gui/WhatsNewDialog.cxx
index 07914b894..aac4171f2 100644
--- a/src/gui/WhatsNewDialog.cxx
+++ b/src/gui/WhatsNewDialog.cxx
@@ -53,6 +53,7 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const
add(ypos, "added wildcard support to launcher dialog filter");
add(ypos, "added option to search subdirectories in launcher");
add(ypos, "added tooltips to many UI items");
+ add(ypos, "added sound to Time Machine playback");
add(ypos, "increased sample size for CDFJ+");
add(ypos, ELLIPSIS + " (for a complete list see 'docs/Changes.txt')");
#endif
| |