Qt sound fix for integer frame rates. Now computes the proper expected number of samples per frame.

This commit is contained in:
mjbudd77 2021-08-06 22:27:59 -04:00
parent 728a7c3580
commit ebec5422bf
6 changed files with 159 additions and 24 deletions

View File

@ -131,6 +131,13 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
connect(bufSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(bufSizeChanged(int))); connect(bufSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(bufSizeChanged(int)));
bufUsage = new QProgressBar();
bufUsage->setOrientation( Qt::Horizontal );
bufUsage->setMinimum( 0 );
bufUsage->setMaximum( 100 );
bufUsage->setValue( 0 );
vbox1->addWidget(bufUsage);
// Use Global Focus // Use Global Focus
useGlobalFocus = new QCheckBox(tr("Use Global Focus")); useGlobalFocus = new QCheckBox(tr("Use Global Focus"));
useGlobalFocus->setToolTip( tr("Mute sound when window is not in focus") ); useGlobalFocus->setToolTip( tr("Mute sound when window is not in focus") );
@ -262,11 +269,16 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
setLayout(mainLayout); setLayout(mainLayout);
setSliderEnables(); setSliderEnables();
updateTimer = new QTimer(this);
connect( updateTimer, &QTimer::timeout, this, &ConsoleSndConfDialog_t::periodicUpdate );
updateTimer->start(1000);
} }
//---------------------------------------------------- //----------------------------------------------------
ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void) ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void)
{ {
printf("Destroy Sound Config Window\n"); printf("Destroy Sound Config Window\n");
updateTimer->stop();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void ConsoleSndConfDialog_t::closeEvent(QCloseEvent *event) void ConsoleSndConfDialog_t::closeEvent(QCloseEvent *event)
@ -284,6 +296,20 @@ void ConsoleSndConfDialog_t::closeWindow(void)
deleteLater(); deleteLater();
} }
//---------------------------------------------------- //----------------------------------------------------
void ConsoleSndConfDialog_t::periodicUpdate(void)
{
uint32_t c, m;
double percBufUse;
c = GetWriteSound();
m = GetMaxSound();
percBufUse = 100.0f - (100.0f * (double)c / (double)m );
bufUsage->setValue( (int)(percBufUse) );
}
//----------------------------------------------------
void ConsoleSndConfDialog_t::setSliderEnables(void) void ConsoleSndConfDialog_t::setSliderEnables(void)
{ {
// For now, always leave all sliders enabled. // For now, always leave all sliders enabled.

View File

@ -15,6 +15,8 @@
#include <QSlider> #include <QSlider>
#include <QFrame> #include <QFrame>
#include <QGroupBox> #include <QGroupBox>
#include <QProgressBar>
#include <QTimer>
class ConsoleSndConfDialog_t : public QDialog class ConsoleSndConfDialog_t : public QDialog
{ {
@ -45,6 +47,8 @@ protected:
QSlider *sqr2Slider; QSlider *sqr2Slider;
QSlider *nseSlider; QSlider *nseSlider;
QSlider *pcmSlider; QSlider *pcmSlider;
QProgressBar *bufUsage;
QTimer *updateTimer;
void setCheckBoxFromProperty(QCheckBox *cbx, const char *property); void setCheckBoxFromProperty(QCheckBox *cbx, const char *property);
void setComboBoxFromProperty(QComboBox *cbx, const char *property); void setComboBoxFromProperty(QComboBox *cbx, const char *property);
@ -53,6 +57,7 @@ protected:
private slots: private slots:
void closeWindow(void); void closeWindow(void);
void periodicUpdate(void);
void bufSizeChanged(int value); void bufSizeChanged(int value);
void volumeChanged(int value); void volumeChanged(int value);
void triangleChanged(int value); void triangleChanged(int value);

View File

@ -721,6 +721,8 @@ void ConsoleVideoConfDialog_t::intFrameRate_changed( int value )
fceuWrapperLock(); fceuWrapperLock();
RefreshThrottleFPS(); RefreshThrottleFPS();
KillSound();
InitSound();
fceuWrapperUnLock(); fceuWrapperUnLock();
} }
//---------------------------------------------------- //----------------------------------------------------

View File

@ -25,7 +25,8 @@
#include "common/configSys.h" #include "common/configSys.h"
#include "utils/memory.h" #include "utils/memory.h"
#include "nes_shm.h" #include "Qt/nes_shm.h"
#include "Qt/throttle.h"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -38,47 +39,106 @@ static unsigned int s_BufferSize;
static unsigned int s_BufferRead; static unsigned int s_BufferRead;
static unsigned int s_BufferWrite; static unsigned int s_BufferWrite;
static volatile unsigned int s_BufferIn; static volatile unsigned int s_BufferIn;
static unsigned int s_SampleRate = 44100;
static double noiseGate = 0.0;
static double noiseGateRate = 0.010;
static bool noiseGateActive = true;
static int s_mute = 0; static int s_mute = 0;
extern int EmulationPaused;
extern double frmRateAdjRatio;
/** /**
* Callback from the SDL to get and play audio data. * Callback from the SDL to get and play audio data.
*/ */
static void static void
fillaudio(void *udata, fillaudio(void *udata,
uint8 *stream, uint8 *stream,
int len) int len)
{ {
char bufStarveDetected = 0; char bufStarveDetected = 0;
static int16_t sample = 0; static int16_t sample = 0;
//unsigned int starve_lp = nes_shm->sndBuf.starveCounter;
int16 *tmps = (int16*)stream; int16 *tmps = (int16*)stream;
len >>= 1; len >>= 1;
while (len)
if ( EmulationPaused || noiseGateActive )
{ {
//int16 sample = 0; // This noise gate helps avoid abrupt snaps in audio
if (s_BufferIn) // when pausing emulation.
while (len)
{ {
sample = s_Buffer[s_BufferRead]; if (EmulationPaused)
s_BufferRead = (s_BufferRead + 1) % s_BufferSize; {
s_BufferIn--; noiseGate -= noiseGateRate;
} else {
// Retain last known sample value, helps avoid clicking if ( noiseGate < 0.0 )
// noise when sound system is starved of audio data. {
//sample = 0; noiseGate = 0.0;
bufStarveDetected = 1; }
nes_shm->sndBuf.starveCounter++; noiseGateActive = 1;
}
else
{
if ( s_BufferIn )
{
noiseGate += noiseGateRate;
if ( noiseGate > 1.0 )
{
noiseGate = 1.0;
noiseGateActive = 0;
}
}
}
if (s_BufferIn)
{
sample = s_Buffer[s_BufferRead] * noiseGate;
s_BufferRead = (s_BufferRead + 1) % s_BufferSize;
s_BufferIn--;
*tmps = sample;
}
else
{
// Retain last known sample value, helps avoid clicking
// noise when sound system is starved of audio data.
*tmps = sample * noiseGate;
}
tmps++;
len--;
} }
}
else
{
while (len)
{
if (s_BufferIn)
{
sample = s_Buffer[s_BufferRead];
s_BufferRead = (s_BufferRead + 1) % s_BufferSize;
s_BufferIn--;
} else {
// Retain last known sample value, helps avoid clicking
// noise when sound system is starved of audio data.
//sample = 0;
bufStarveDetected = 1;
nes_shm->sndBuf.starveCounter++;
}
nes_shm->push_sound_sample( sample ); nes_shm->push_sound_sample( sample );
*tmps = sample; *tmps = sample;
tmps++; tmps++;
len--; len--;
}
} }
if ( bufStarveDetected ) if ( bufStarveDetected )
{ {
//printf("Starve:%u\n", nes_shm->sndBuf.starveCounter ); //s_StarveCounter = nes_shm->sndBuf.starveCounter - starve_lp;
//printf("Starve:%u\n", s_StarveCounter );
} }
} }
@ -91,6 +151,7 @@ InitSound()
int sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, soundsquare1volume, soundsquare2volume, soundnoisevolume, soundpcmvolume, soundq; int sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, soundsquare1volume, soundsquare2volume, soundnoisevolume, soundpcmvolume, soundq;
SDL_AudioSpec spec; SDL_AudioSpec spec;
const char *driverName; const char *driverName;
int frmRateSampleAdj = 0;
g_config->getOption("SDL.Sound", &sound); g_config->getOption("SDL.Sound", &sound);
if (!sound) if (!sound)
@ -117,10 +178,11 @@ InitSound()
g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume); g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume);
g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume); g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume);
spec.freq = soundrate; spec.freq = s_SampleRate = soundrate;
spec.format = AUDIO_S16SYS; spec.format = AUDIO_S16SYS;
spec.channels = 1; spec.channels = 1;
spec.samples = 512; //spec.samples = 512;
spec.samples = (int)( ( (double)s_SampleRate / getBaseFrameRate() ) );
spec.callback = fillaudio; spec.callback = fillaudio;
spec.userdata = 0; spec.userdata = 0;
@ -131,6 +193,9 @@ InitSound()
{ {
s_BufferSize = spec.samples * 2; s_BufferSize = spec.samples * 2;
} }
noiseGate = 0.0;
noiseGateRate = 1.0 / (double)spec.samples;
noiseGateActive = true;
s_Buffer = (int *)FCEU_dmalloc(sizeof(int) * s_BufferSize); s_Buffer = (int *)FCEU_dmalloc(sizeof(int) * s_BufferSize);
@ -145,7 +210,7 @@ InitSound()
puts(SDL_GetError()); puts(SDL_GetError());
KillSound(); KillSound();
return 0; return 0;
} }
SDL_PauseAudio(0); SDL_PauseAudio(0);
driverName = SDL_GetCurrentAudioDriver(); driverName = SDL_GetCurrentAudioDriver();
@ -154,10 +219,14 @@ InitSound()
{ {
fprintf(stderr, "Loading SDL sound with %s driver...\n", driverName); fprintf(stderr, "Loading SDL sound with %s driver...\n", driverName);
} }
frmRateSampleAdj = (int)( ( ((double)soundrate) * getFrameRateAdjustmentRatio()) - ((double)soundrate) );
//frmRateSampleAdj = 0;
//printf("Sample Rate Adjustment: %+i\n", frmRateSampleAdj );
FCEUI_SetSoundVolume(soundvolume); FCEUI_SetSoundVolume(soundvolume);
FCEUI_SetSoundQuality(soundq); FCEUI_SetSoundQuality(soundq);
FCEUI_Sound(soundrate); FCEUI_Sound(soundrate + frmRateSampleAdj);
FCEUI_SetTriangleVolume(soundtrianglevolume); FCEUI_SetTriangleVolume(soundtrianglevolume);
FCEUI_SetSquare1Volume(soundsquare1volume); FCEUI_SetSquare1Volume(soundsquare1volume);
FCEUI_SetSquare2Volume(soundsquare2volume); FCEUI_SetSquare2Volume(soundsquare2volume);

View File

@ -38,6 +38,8 @@ static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC)
static uint32 frameLateCounter = 0; static uint32 frameLateCounter = 0;
static double Lasttime=0, Nexttime=0, Latetime=0; static double Lasttime=0, Nexttime=0, Latetime=0;
static double desired_frametime = (1.0 / 60.099823); static double desired_frametime = (1.0 / 60.099823);
static double desired_frameRate = (60.099823);
static double baseframeRate = (60.099823);
static double frameDeltaCur = 0.0; static double frameDeltaCur = 0.0;
static double frameDeltaMin = 1.0; static double frameDeltaMin = 1.0;
static double frameDeltaMax = 0.0; static double frameDeltaMax = 0.0;
@ -53,6 +55,7 @@ static int InFrame = 0;
double g_fpsScale = Normal; // used by sdl.cpp double g_fpsScale = Normal; // used by sdl.cpp
bool MaxSpeed = false; bool MaxSpeed = false;
bool useIntFrameRate = false; bool useIntFrameRate = false;
static double frmRateAdjRatio = 1.000000f; // Frame Rate Adjustment Ratio
double getHighPrecTimeStamp(void) double getHighPrecTimeStamp(void)
{ {
@ -242,11 +245,23 @@ RefreshThrottleFPS(void)
hz = ( ((double)fps) / 16777216.0 ); hz = ( ((double)fps) / 16777216.0 );
desired_frametime = 1.0 / ( hz * g_fpsScale );
if ( useIntFrameRate ) if ( useIntFrameRate )
{ {
hz = (double)( (int)(hz) ); hz = (double)( (int)(hz) );
frmRateAdjRatio = (1.0 / ( hz * g_fpsScale )) / desired_frametime;
printf("frameAdjRatio:%f \n", frmRateAdjRatio );
}
else
{
frmRateAdjRatio = 1.000000f;
} }
desired_frametime = 1.0 / ( hz * g_fpsScale ); desired_frametime = 1.0 / ( hz * g_fpsScale );
desired_frameRate = ( hz * g_fpsScale );
baseframeRate = hz;
T = (int32_t)( desired_frametime * 1000.0 ); T = (int32_t)( desired_frametime * 1000.0 );
@ -264,6 +279,21 @@ RefreshThrottleFPS(void)
} }
double getBaseFrameRate(void)
{
return baseframeRate;
}
double getFrameRate(void)
{
return desired_frameRate;
}
double getFrameRateAdjustmentRatio(void)
{
return frmRateAdjRatio;
}
int highPrecSleep( double timeSeconds ) int highPrecSleep( double timeSeconds )
{ {
int ret = 0; int ret = 0;

View File

@ -53,5 +53,8 @@ void setFrameTimingEnable( bool enable );
int getFrameTimingStats( struct frameTimingStat_t *stats ); int getFrameTimingStats( struct frameTimingStat_t *stats );
void videoBufferSwapMark(void); void videoBufferSwapMark(void);
double getHighPrecTimeStamp(void); double getHighPrecTimeStamp(void);
double getFrameRate(void);
double getFrameRateAdjustmentRatio(void);
double getBaseFrameRate(void);
extern bool useIntFrameRate; extern bool useIntFrameRate;