Qt sound fix for integer frame rates. Now computes the proper expected number of samples per frame.
This commit is contained in:
parent
728a7c3580
commit
ebec5422bf
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -721,6 +721,8 @@ void ConsoleVideoConfDialog_t::intFrameRate_changed( int value )
|
||||||
|
|
||||||
fceuWrapperLock();
|
fceuWrapperLock();
|
||||||
RefreshThrottleFPS();
|
RefreshThrottleFPS();
|
||||||
|
KillSound();
|
||||||
|
InitSound();
|
||||||
fceuWrapperUnLock();
|
fceuWrapperUnLock();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue