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)));
bufUsage = new QProgressBar();
bufUsage->setOrientation( Qt::Horizontal );
bufUsage->setMinimum( 0 );
bufUsage->setMaximum( 100 );
bufUsage->setValue( 0 );
vbox1->addWidget(bufUsage);
// Use Global Focus
useGlobalFocus = new QCheckBox(tr("Use Global Focus"));
useGlobalFocus->setToolTip( tr("Mute sound when window is not in focus") );
@ -262,11 +269,16 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent)
setLayout(mainLayout);
setSliderEnables();
updateTimer = new QTimer(this);
connect( updateTimer, &QTimer::timeout, this, &ConsoleSndConfDialog_t::periodicUpdate );
updateTimer->start(1000);
}
//----------------------------------------------------
ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void)
{
printf("Destroy Sound Config Window\n");
updateTimer->stop();
}
//----------------------------------------------------------------------------
void ConsoleSndConfDialog_t::closeEvent(QCloseEvent *event)
@ -284,6 +296,20 @@ void ConsoleSndConfDialog_t::closeWindow(void)
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)
{
// For now, always leave all sliders enabled.

View File

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

View File

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

View File

@ -25,7 +25,8 @@
#include "common/configSys.h"
#include "utils/memory.h"
#include "nes_shm.h"
#include "Qt/nes_shm.h"
#include "Qt/throttle.h"
#include <cstdio>
#include <cstring>
@ -38,47 +39,106 @@ static unsigned int s_BufferSize;
static unsigned int s_BufferRead;
static unsigned int s_BufferWrite;
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;
extern int EmulationPaused;
extern double frmRateAdjRatio;
/**
* Callback from the SDL to get and play audio data.
*/
static void
fillaudio(void *udata,
uint8 *stream,
int len)
uint8 *stream,
int len)
{
char bufStarveDetected = 0;
static int16_t sample = 0;
//unsigned int starve_lp = nes_shm->sndBuf.starveCounter;
int16 *tmps = (int16*)stream;
len >>= 1;
while (len)
if ( EmulationPaused || noiseGateActive )
{
//int16 sample = 0;
if (s_BufferIn)
// This noise gate helps avoid abrupt snaps in audio
// when pausing emulation.
while (len)
{
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++;
if (EmulationPaused)
{
noiseGate -= noiseGateRate;
if ( noiseGate < 0.0 )
{
noiseGate = 0.0;
}
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++;
len--;
*tmps = sample;
tmps++;
len--;
}
}
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;
SDL_AudioSpec spec;
const char *driverName;
int frmRateSampleAdj = 0;
g_config->getOption("SDL.Sound", &sound);
if (!sound)
@ -117,10 +178,11 @@ InitSound()
g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume);
g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume);
spec.freq = soundrate;
spec.freq = s_SampleRate = soundrate;
spec.format = AUDIO_S16SYS;
spec.channels = 1;
spec.samples = 512;
//spec.samples = 512;
spec.samples = (int)( ( (double)s_SampleRate / getBaseFrameRate() ) );
spec.callback = fillaudio;
spec.userdata = 0;
@ -131,6 +193,9 @@ InitSound()
{
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);
@ -145,7 +210,7 @@ InitSound()
puts(SDL_GetError());
KillSound();
return 0;
}
}
SDL_PauseAudio(0);
driverName = SDL_GetCurrentAudioDriver();
@ -154,10 +219,14 @@ InitSound()
{
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_SetSoundQuality(soundq);
FCEUI_Sound(soundrate);
FCEUI_Sound(soundrate + frmRateSampleAdj);
FCEUI_SetTriangleVolume(soundtrianglevolume);
FCEUI_SetSquare1Volume(soundsquare1volume);
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 double Lasttime=0, Nexttime=0, Latetime=0;
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 frameDeltaMin = 1.0;
static double frameDeltaMax = 0.0;
@ -53,6 +55,7 @@ static int InFrame = 0;
double g_fpsScale = Normal; // used by sdl.cpp
bool MaxSpeed = false;
bool useIntFrameRate = false;
static double frmRateAdjRatio = 1.000000f; // Frame Rate Adjustment Ratio
double getHighPrecTimeStamp(void)
{
@ -242,11 +245,23 @@ RefreshThrottleFPS(void)
hz = ( ((double)fps) / 16777216.0 );
desired_frametime = 1.0 / ( hz * g_fpsScale );
if ( useIntFrameRate )
{
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_frameRate = ( hz * g_fpsScale );
baseframeRate = hz;
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 ret = 0;

View File

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