Added snap by number of frames (instead of by time) option for Qt state recorder.

This commit is contained in:
harry 2023-04-22 15:56:31 -04:00
parent 0942d160ca
commit 084b2b9ccc
6 changed files with 135 additions and 11 deletions

View File

@ -35,6 +35,7 @@
#include "../../fceu.h"
#include "../../state.h"
#include "../../driver.h"
#include "../../emufile.h"
//----------------------------------------------------------------------------
@ -54,14 +55,19 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
grid = new QGridLayout();
recorderEnable = new QCheckBox(tr("Auto Start Recorder at ROM Load"));
snapFrames = new QSpinBox();
snapMinutes = new QSpinBox();
snapSeconds = new QSpinBox();
historyDuration = new QSpinBox();
snapFrameSelBtn = new QRadioButton( tr("By Frames") );
snapTimeSelBtn = new QRadioButton( tr("By Time") );
recorderEnable->setChecked( FCEU_StateRecorderIsEnabled() );
connect( recorderEnable, SIGNAL(stateChanged(int)), this, SLOT(enableChanged(int)) );
snapFrames->setMinimum(1);
snapFrames->setMaximum(10000);
snapSeconds->setMinimum(0);
snapSeconds->setMaximum(60);
snapMinutes->setMinimum(0);
@ -69,6 +75,10 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
historyDuration->setMinimum(1);
historyDuration->setMaximum(180);
opt = 10;
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &opt);
snapFrames->setValue(opt);
opt = 15;
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &opt );
historyDuration->setValue(opt);
@ -81,6 +91,14 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &opt);
snapSeconds->setValue(opt);
opt = 0;
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
snapFrameSelBtn->setChecked(opt == 0);
snapTimeSelBtn->setChecked(opt == 1);
snapUseTime = opt ? true : false;
connect( snapFrames , SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
connect( snapSeconds, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
connect( snapMinutes, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
connect( historyDuration, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
@ -122,11 +140,31 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
frame->setLayout(hbox);
grid->addWidget( frame, 1, 1 );
frame1 = new QGroupBox(tr("Time Between Snapshots:"));
frame1 = new QGroupBox(tr("Snapshot Timing Setting:"));
hbox1 = new QHBoxLayout();
frame1->setLayout(hbox1);
grid->addWidget( frame1, 2, 0, 1, 2 );
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
hbox1->addWidget( snapFrameSelBtn );
hbox1->addWidget( snapTimeSelBtn );
snapFramesGroup = new QGroupBox(tr("Frames Between Snapshots:"));
hbox1 = new QHBoxLayout();
snapFramesGroup->setLayout(hbox1);
snapFramesGroup->setEnabled(snapFrameSelBtn->isChecked());
grid->addWidget( snapFramesGroup, 3, 0, 1, 2 );
hbox1->addWidget( snapFrames);
hbox1->addWidget( new QLabel( tr("Range (1 - 10000)") ) );
snapTimeGroup = new QGroupBox(tr("Time Between Snapshots:"));
hbox1 = new QHBoxLayout();
snapTimeGroup->setLayout(hbox1);
snapTimeGroup->setEnabled(snapTimeSelBtn->isChecked());
grid->addWidget( snapTimeGroup, 4, 0, 1, 2 );
frame = new QGroupBox();
hbox = new QHBoxLayout();
@ -178,7 +216,7 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
frame->setLayout(hbox);
grid->addWidget(frame1, 3, 0, 2, 1);
grid->addWidget(frame1, 4, 3, 2, 1);
frame = new QGroupBox( tr("Memory Usage:") );
memStatsGrid = new QGridLayout();
@ -236,6 +274,8 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
updateRecorderStatusLabel();
connect(startStopButton, SIGNAL(clicked(void)), this, SLOT(startStopClicked(void)));
connect(snapFrameSelBtn, SIGNAL(clicked(void)), this, SLOT(snapFrameModeClicked(void)));
connect(snapTimeSelBtn , SIGNAL(clicked(void)), this, SLOT(snapTimeModeClicked(void)));
frame = new QGroupBox();
hbox = new QHBoxLayout();
@ -288,6 +328,7 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
restoreGeometry(settings.value("stateRecorderWindow/geometry").toByteArray());
recalcMemoryUsage();
pauseOnLoadChanged( pauseOnLoadCbox->currentIndex() );
updateTimer = new QTimer(this);
@ -329,6 +370,10 @@ void StateRecorderDialog_t::closeWindow(void)
//----------------------------------------------------------------------------
void StateRecorderDialog_t::packConfig( StateRecorderConfigData &config )
{
config.timingMode = snapTimeSelBtn->isChecked() ?
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
config.framesBetweenSnaps = snapFrames->value();
config.historyDurationMinutes = static_cast<float>( historyDuration->value() );
config.timeBetweenSnapsMinutes = static_cast<float>( snapMinutes->value() ) +
( static_cast<float>( snapSeconds->value() ) / 60.0f );
@ -393,6 +438,8 @@ void StateRecorderDialog_t::applyChanges(void)
FCEU_WRAPPER_UNLOCK();
g_config->setOption("SDL.StateRecorderHistoryDurationMin", historyDuration->value() );
g_config->setOption("SDL.StateRecorderTimingMode", snapTimeSelBtn->isChecked() ? 1 : 0);
g_config->setOption("SDL.StateRecorderFramesBetweenSnaps", snapFrames->value() );
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsMin", snapMinutes->value() );
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsSec", snapSeconds->value() );
g_config->setOption("SDL.StateRecorderCompressionLevel", config.compressionLevel);
@ -420,6 +467,24 @@ void StateRecorderDialog_t::startStopClicked(void)
FCEU_WRAPPER_UNLOCK();
}
//----------------------------------------------------------------------------
void StateRecorderDialog_t::snapFrameModeClicked(void)
{
snapUseTime = false;
snapTimeGroup->setEnabled(false);
snapFramesGroup->setEnabled(true);
recalcMemoryUsage();
}
//----------------------------------------------------------------------------
void StateRecorderDialog_t::snapTimeModeClicked(void)
{
snapUseTime = true;
snapFramesGroup->setEnabled(false);
snapTimeGroup->setEnabled(true);
recalcMemoryUsage();
}
//----------------------------------------------------------------------------
void StateRecorderDialog_t::updateStartStopBuffon(void)
{
bool isRunning = FCEU_StateRecorderRunning();
@ -517,9 +582,21 @@ void StateRecorderDialog_t::recalcMemoryUsage(void)
{
char stmp[64];
float fsnapMin = 1.0;
float fhistMin = static_cast<float>( historyDuration->value() );
float fsnapMin = static_cast<float>( snapMinutes->value() ) +
if (snapUseTime)
{
fsnapMin = static_cast<float>( snapMinutes->value() ) +
( static_cast<float>( snapSeconds->value() ) / 60.0f );
}
else
{
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
double hz = ( ((double)fps) / 16777216.0 );
fsnapMin = static_cast<double>(snapFrames->value()) / (hz * 60.0);
}
float fnumSnaps = fhistMin / fsnapMin;
float fsnapSize = 10.0f * 1024.0f;

View File

@ -12,6 +12,7 @@
#include <QSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QRadioButton>
#include <QProgressBar>
#include <QLineEdit>
#include <QLabel>
@ -34,6 +35,7 @@ protected:
QSpinBox *snapMinutes;
QSpinBox *snapSeconds;
QSpinBox *snapFrames;
QSpinBox *historyDuration;
QSpinBox *pauseDuration;
QCheckBox *recorderEnable;
@ -45,6 +47,10 @@ protected:
QPushButton *closeButton;
QComboBox *cmprLvlCbox;
QComboBox *pauseOnLoadCbox;
QGroupBox *snapTimeGroup;
QGroupBox *snapFramesGroup;
QRadioButton *snapFrameSelBtn;
QRadioButton *snapTimeSelBtn;
QLineEdit *recStatusLbl;
QLineEdit *recBufSizeLbl;
QPushButton *startStopButton;
@ -52,6 +58,7 @@ protected:
QTimer *updateTimer;
double saveTimeMs;
bool snapUseTime;
bool dataSavedCheck(void);
void recalcMemoryUsage(void);
@ -67,6 +74,8 @@ private slots:
void applyChanges(void);
void updatePeriodic(void);
void startStopClicked(void);
void snapTimeModeClicked(void);
void snapFrameModeClicked(void);
void spinBoxValueChanged(int newValue);
void enableChanged(int);
void compressionLevelChanged(int newValue);

View File

@ -756,6 +756,8 @@ InitConfig()
config->addOption("SDL.StateRecorderEnable", false);
config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
config->addOption("SDL.StateRecorderTimingMode", 0);
config->addOption("SDL.StateRecorderFramesBetweenSnaps", 60);
config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
config->addOption("SDL.StateRecorderCompressionLevel", 0);

View File

@ -976,7 +976,9 @@ int fceuWrapperInit( int argc, char *argv[] )
// Initialize the State Recorder
{
bool srEnable = false;
bool srUseTimeMode = false;
int srHistDurMin = 15;
int srFramesBtwSnaps = 60;
int srTimeBtwSnapsMin = 0;
int srTimeBtwSnapsSec = 3;
int srCompressionLevel = 0;
@ -984,7 +986,9 @@ int fceuWrapperInit( int argc, char *argv[] )
int pauseOnLoad = StateRecorderConfigData::TEMPORARY_PAUSE;
g_config->getOption("SDL.StateRecorderEnable", &srEnable);
g_config->getOption("SDL.StateRecorderTimingMode", &srUseTimeMode);
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &srHistDurMin);
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &srFramesBtwSnaps);
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &srTimeBtwSnapsMin);
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &srTimeBtwSnapsSec);
g_config->getOption("SDL.StateRecorderCompressionLevel", &srCompressionLevel);
@ -994,8 +998,11 @@ int fceuWrapperInit( int argc, char *argv[] )
StateRecorderConfigData srConfig;
srConfig.historyDurationMinutes = srHistDurMin;
srConfig.timingMode = srUseTimeMode ?
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
srConfig.timeBetweenSnapsMinutes = static_cast<float>( srTimeBtwSnapsMin ) +
( static_cast<float>( srTimeBtwSnapsSec ) / 60.0f );
srConfig.framesBetweenSnaps = srFramesBtwSnaps;
srConfig.compressionLevel = srCompressionLevel;
srConfig.loadPauseTimeSeconds = pauseOnLoadTime;
srConfig.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>(pauseOnLoad);

View File

@ -1218,6 +1218,10 @@ class StateRecorder
void loadConfig( StateRecorderConfigData &config )
{
if (config.framesBetweenSnaps < 1)
{
config.framesBetweenSnaps = 1;
}
if (config.timeBetweenSnapsMinutes < 0.0)
{
config.timeBetweenSnapsMinutes = 3.0f / 60.0f;
@ -1226,19 +1230,35 @@ class StateRecorder
{
config.historyDurationMinutes = config.timeBetweenSnapsMinutes;
}
const double fhistMin = config.historyDurationMinutes;
const double fsnapMin = config.timeBetweenSnapsMinutes;
const double fnumSnaps = fhistMin / fsnapMin;
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
if (config.timingMode)
{
const double fhistMin = config.historyDurationMinutes;
const double fsnapMin = config.timeBetweenSnapsMinutes;
const double fnumSnaps = fhistMin / fsnapMin;
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
double hz = ( ((double)fps) / 16777216.0 );
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
double framesPerSnapf = hz * fsnapMin * 60.0;
double hz = ( ((double)fps) / 16777216.0 );
framesPerSnap = static_cast<unsigned int>( framesPerSnapf + 0.50 );
double framesPerSnapf = hz * fsnapMin * 60.0;
framesPerSnap = static_cast<unsigned int>( framesPerSnapf + 0.50 );
}
else
{
const double fhistMin = config.historyDurationMinutes;
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
double hz = ( ((double)fps) / 16777216.0 );
const double fsnapMin = static_cast<double>(config.framesBetweenSnaps) / (hz * 60.0);
const double fnumSnaps = fhistMin / fsnapMin;
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
framesPerSnap = config.framesBetweenSnaps;
}
printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap );

View File

@ -84,9 +84,16 @@ struct StateRecorderConfigData
{
float historyDurationMinutes;
float timeBetweenSnapsMinutes;
int framesBetweenSnaps;
int compressionLevel;
int loadPauseTimeSeconds;
enum TimingType
{
FRAMES = 0,
TIME,
} timingMode;
enum PauseType
{
NO_PAUSE = 0,
@ -96,11 +103,13 @@ struct StateRecorderConfigData
StateRecorderConfigData(void)
{
framesBetweenSnaps = 60;
historyDurationMinutes = 15.0f;
timeBetweenSnapsMinutes = 3.0f / 60.0f;
compressionLevel = 0;
loadPauseTimeSeconds = 3;
pauseOnLoad = TEMPORARY_PAUSE;
timingMode = FRAMES;
}
bool compare( const StateRecorderConfigData &other )