Audio: Improve sound latency - can be set 4-5x lower than before without crackling sounds
This commit is contained in:
parent
cad8995696
commit
3f3b3ffb3c
10 changed files with 81 additions and 36 deletions
|
@ -14,7 +14,7 @@
|
|||
class SoundMixer : public Snapshotable
|
||||
{
|
||||
public:
|
||||
static const uint32_t CycleLength = 10000;
|
||||
static const uint32_t CycleLength = 1000;
|
||||
static const uint32_t BitsPerSample = 16;
|
||||
|
||||
private:
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Control ID="chkEnableAudio">Activar el sonido</Control>
|
||||
<Control ID="lblSampleRate">Frecuencia de muestreo:</Control>
|
||||
<Control ID="lblLatencyMs">ms</Control>
|
||||
<Control ID="lblLatencyWarning">Low values may cause sound problems</Control>
|
||||
<Control ID="lblAudioLatency">Latencia:</Control>
|
||||
<Control ID="lblAudioDevice">Dispositivo:</Control>
|
||||
<Control ID="tpgVolume">Volumen</Control>
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Control ID="chkEnableAudio">Activer le son</Control>
|
||||
<Control ID="lblSampleRate">Taux d'échantillonnage:</Control>
|
||||
<Control ID="lblLatencyMs">ms</Control>
|
||||
<Control ID="lblLatencyWarning">Une latence trop faible peut causer des problèmes</Control>
|
||||
<Control ID="lblAudioLatency">Latence:</Control>
|
||||
<Control ID="lblAudioDevice">Périphérique:</Control>
|
||||
<Control ID="tpgVolume">Volume</Control>
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Control ID="chkEnableAudio">音声オン</Control>
|
||||
<Control ID="lblSampleRate">サンプルレート:</Control>
|
||||
<Control ID="lblLatencyMs">ミリ秒</Control>
|
||||
<Control ID="lblLatencyWarning">低すぎる場合は、音声にノイズが発生することがある</Control>
|
||||
<Control ID="lblAudioLatency">レイテンシ:</Control>
|
||||
<Control ID="lblAudioDevice">デバイス:</Control>
|
||||
<Control ID="tpgVolume">音量ミキサー</Control>
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Control ID="chkEnableAudio">Включить звук</Control>
|
||||
<Control ID="lblSampleRate">Частота дискретизации:</Control>
|
||||
<Control ID="lblLatencyMs">мс</Control>
|
||||
<Control ID="lblLatencyWarning">Low values may cause sound problems</Control>
|
||||
<Control ID="lblAudioLatency">Задержка:</Control>
|
||||
<Control ID="lblAudioDevice">Устройство:</Control>
|
||||
<Control ID="tpgVolume">Громкость</Control>
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
<Control ID="chkEnableAudio">Увімкнути звук</Control>
|
||||
<Control ID="lblSampleRate">Частота дискретизації:</Control>
|
||||
<Control ID="lblLatencyMs">мс</Control>
|
||||
<Control ID="lblLatencyWarning">Low values may cause sound problems</Control>
|
||||
<Control ID="lblAudioLatency">Затримка:</Control>
|
||||
<Control ID="lblAudioDevice">Пристрій:</Control>
|
||||
<Control ID="tpgVolume">Гучність</Control>
|
||||
|
|
36
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
36
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
|
@ -49,6 +49,8 @@
|
|||
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.nudLatency = new System.Windows.Forms.NumericUpDown();
|
||||
this.lblLatencyMs = new System.Windows.Forms.Label();
|
||||
this.picLatencyWarning = new System.Windows.Forms.PictureBox();
|
||||
this.lblLatencyWarning = new System.Windows.Forms.Label();
|
||||
this.lblAudioLatency = new System.Windows.Forms.Label();
|
||||
this.cboSampleRate = new System.Windows.Forms.ComboBox();
|
||||
this.lblAudioDevice = new System.Windows.Forms.Label();
|
||||
|
@ -88,6 +90,7 @@
|
|||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.flowLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudLatency)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picLatencyWarning)).BeginInit();
|
||||
this.tabMain.SuspendLayout();
|
||||
this.tpgGeneral.SuspendLayout();
|
||||
this.tpgVolume.SuspendLayout();
|
||||
|
@ -401,10 +404,13 @@
|
|||
//
|
||||
this.flowLayoutPanel2.Controls.Add(this.nudLatency);
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblLatencyMs);
|
||||
this.flowLayoutPanel2.Controls.Add(this.picLatencyWarning);
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblLatencyWarning);
|
||||
this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel2.Location = new System.Drawing.Point(77, 80);
|
||||
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
|
||||
this.flowLayoutPanel2.Size = new System.Drawing.Size(78, 24);
|
||||
this.flowLayoutPanel2.Size = new System.Drawing.Size(386, 24);
|
||||
this.flowLayoutPanel2.TabIndex = 4;
|
||||
//
|
||||
// nudLatency
|
||||
|
@ -416,7 +422,7 @@
|
|||
0,
|
||||
0});
|
||||
this.nudLatency.Minimum = new decimal(new int[] {
|
||||
100,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
|
@ -428,6 +434,7 @@
|
|||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudLatency.ValueChanged += new System.EventHandler(this.nudLatency_ValueChanged);
|
||||
//
|
||||
// lblLatencyMs
|
||||
//
|
||||
|
@ -439,6 +446,28 @@
|
|||
this.lblLatencyMs.TabIndex = 2;
|
||||
this.lblLatencyMs.Text = "ms";
|
||||
//
|
||||
// picLatencyWarning
|
||||
//
|
||||
this.picLatencyWarning.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.picLatencyWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
|
||||
this.picLatencyWarning.Location = new System.Drawing.Point(82, 5);
|
||||
this.picLatencyWarning.Margin = new System.Windows.Forms.Padding(5, 3, 0, 3);
|
||||
this.picLatencyWarning.Name = "picLatencyWarning";
|
||||
this.picLatencyWarning.Size = new System.Drawing.Size(16, 16);
|
||||
this.picLatencyWarning.TabIndex = 3;
|
||||
this.picLatencyWarning.TabStop = false;
|
||||
//
|
||||
// lblLatencyWarning
|
||||
//
|
||||
this.lblLatencyWarning.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblLatencyWarning.AutoSize = true;
|
||||
this.lblLatencyWarning.Location = new System.Drawing.Point(98, 6);
|
||||
this.lblLatencyWarning.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||
this.lblLatencyWarning.Name = "lblLatencyWarning";
|
||||
this.lblLatencyWarning.Size = new System.Drawing.Size(192, 13);
|
||||
this.lblLatencyWarning.TabIndex = 4;
|
||||
this.lblLatencyWarning.Text = "Low values may cause sound problems";
|
||||
//
|
||||
// lblAudioLatency
|
||||
//
|
||||
this.lblAudioLatency.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
|
@ -860,6 +889,7 @@
|
|||
this.flowLayoutPanel2.ResumeLayout(false);
|
||||
this.flowLayoutPanel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudLatency)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picLatencyWarning)).EndInit();
|
||||
this.tabMain.ResumeLayout(false);
|
||||
this.tpgGeneral.ResumeLayout(false);
|
||||
this.tpgVolume.ResumeLayout(false);
|
||||
|
@ -943,5 +973,7 @@
|
|||
private System.Windows.Forms.TrackBar trkReverbStrength;
|
||||
private System.Windows.Forms.CheckBox chkSilenceTriangleHighFreq;
|
||||
private System.Windows.Forms.CheckBox chkReduceDmcPopping;
|
||||
private System.Windows.Forms.PictureBox picLatencyWarning;
|
||||
private System.Windows.Forms.Label lblLatencyWarning;
|
||||
}
|
||||
}
|
|
@ -86,5 +86,11 @@ namespace Mesen.GUI.Forms.Config
|
|||
{
|
||||
chkReduceSoundInBackground.Enabled = !chkMuteSoundInBackground.Checked;
|
||||
}
|
||||
|
||||
private void nudLatency_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
picLatencyWarning.Visible = nudLatency.Value <= 30;
|
||||
lblLatencyWarning.Visible = nudLatency.Value <= 30;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,15 @@ namespace Mesen.GUI.Forms
|
|||
Version oldVersion = new Version(ConfigManager.Config.MesenVersion);
|
||||
if(oldVersion < newVersion) {
|
||||
//Upgrade
|
||||
if(oldVersion <= new Version("5.3.0")) {
|
||||
//Version 0.5.3-
|
||||
//Reduce sound latency if still using default
|
||||
if(ConfigManager.Config.AudioInfo.AudioLatency == 100) {
|
||||
//50ms is a fairly safe number - seems to work fine as low as 20ms (varies by computer)
|
||||
ConfigManager.Config.AudioInfo.AudioLatency = 50;
|
||||
}
|
||||
}
|
||||
|
||||
if(oldVersion <= new Version("0.4.1")) {
|
||||
//Version 0.4.1-
|
||||
//Remove all old cheats (Game matching/CRC logic has been changed and no longer compatible)
|
||||
|
|
|
@ -241,44 +241,37 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32
|
|||
uint32_t soundBufferSize = sampleCount * bytesPerSample;
|
||||
|
||||
int32_t byteLatency = (int32_t)((float)(sampleRate * EmulationSettings::GetAudioLatency()) / 1000.0f * bytesPerSample);
|
||||
DWORD currentPlayCursor;
|
||||
DWORD safeWriteCursor;
|
||||
_secondaryBuffer->GetCurrentPosition(¤tPlayCursor, &safeWriteCursor);
|
||||
|
||||
if(safeWriteCursor > _lastWriteOffset && safeWriteCursor - _lastWriteOffset < 10000) {
|
||||
_lastWriteOffset = (uint16_t)safeWriteCursor;
|
||||
}
|
||||
|
||||
int32_t playWriteByteLatency = (_lastWriteOffset - currentPlayCursor);
|
||||
if(playWriteByteLatency < 0) {
|
||||
playWriteByteLatency = 0xFFFF + playWriteByteLatency;
|
||||
}
|
||||
|
||||
if(byteLatency != _previousLatency) {
|
||||
Stop();
|
||||
_previousLatency = byteLatency;
|
||||
} else if(playWriteByteLatency > byteLatency * 3) {
|
||||
_secondaryBuffer->SetCurrentPosition(_lastWriteOffset - byteLatency);
|
||||
}
|
||||
|
||||
uint32_t targetRate = sampleRate;
|
||||
if(EmulationSettings::GetEmulationSpeed() > 0 && EmulationSettings::GetEmulationSpeed() < 100) {
|
||||
targetRate = (uint32_t)(targetRate * ((double)EmulationSettings::GetEmulationSpeed() / 100.0));
|
||||
}
|
||||
_secondaryBuffer->SetFrequency(targetRate);
|
||||
|
||||
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
|
||||
|
||||
DWORD status;
|
||||
_secondaryBuffer->GetStatus(&status);
|
||||
|
||||
if(!(status & DSBSTATUS_PLAYING)) {
|
||||
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
|
||||
if(_lastWriteOffset >= byteLatency) {
|
||||
Play();
|
||||
}
|
||||
} else {
|
||||
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
|
||||
DWORD currentPlayCursor;
|
||||
_secondaryBuffer->GetCurrentPosition(¤tPlayCursor, nullptr);
|
||||
|
||||
int32_t playWriteByteLatency = (_lastWriteOffset - currentPlayCursor);
|
||||
if(playWriteByteLatency < 0) {
|
||||
playWriteByteLatency = 0xFFFF - currentPlayCursor + _lastWriteOffset;
|
||||
}
|
||||
|
||||
int32_t latencyGap = playWriteByteLatency - byteLatency;
|
||||
int32_t tolerance = byteLatency / 35;
|
||||
uint32_t targetRate = sampleRate;
|
||||
if(EmulationSettings::GetEmulationSpeed() > 0 && EmulationSettings::GetEmulationSpeed() < 100) {
|
||||
targetRate = (uint32_t)(targetRate * ((double)EmulationSettings::GetEmulationSpeed() / 100.0));
|
||||
}
|
||||
if(abs(latencyGap) > byteLatency / 2) {
|
||||
//Out of sync, move back to where we should be (start of the latency buffer)
|
||||
_secondaryBuffer->SetCurrentPosition(_lastWriteOffset - byteLatency);
|
||||
} else if(latencyGap < -tolerance) {
|
||||
//Playing too fast, slow down playing
|
||||
targetRate = (uint32_t)(targetRate * 0.9975);
|
||||
} else if(latencyGap > tolerance) {
|
||||
//Playing too slow, speed up
|
||||
targetRate = (uint32_t)(targetRate * 1.0025);
|
||||
}
|
||||
_secondaryBuffer->SetFrequency((DWORD)targetRate);
|
||||
if(!(status & DSBSTATUS_PLAYING) && _lastWriteOffset >= byteLatency) {
|
||||
Play();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue