summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2022-07-05 11:37:30 +0200
committerGitHub <noreply@github.com>2022-07-05 11:37:30 +0200
commitde3d1344d5ed939faedae9c19e2e340a83038aba (patch)
tree40d2efd3dbe7c8ad2d7303539a7a48264be00005 /Source/Core/AudioCommon
parentd625c612c4a40a8c8db3d90b313f5643aec9c890 (diff)
parent4234b25682ddfab6018c3c7bf410e568f527b1cd (diff)
Merge pull request #10762 from CasualPokePlayer/fix_slow_audio_desyncs
Reduce gradual audio desyncing in dumps and apply the correct sample rate for GameCube audio
Diffstat (limited to 'Source/Core/AudioCommon')
-rw-r--r--Source/Core/AudioCommon/Mixer.cpp51
-rw-r--r--Source/Core/AudioCommon/Mixer.h34
-rw-r--r--Source/Core/AudioCommon/WaveFile.cpp17
-rw-r--r--Source/Core/AudioCommon/WaveFile.h22
4 files changed, 69 insertions, 55 deletions
diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp
index e0b7f28768..5baa02d25e 100644
--- a/Source/Core/AudioCommon/Mixer.cpp
+++ b/Source/Core/AudioCommon/Mixer.cpp
@@ -76,16 +76,18 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples,
// advance indexR with sample position
// remember fractional offset
- float aid_sample_rate = static_cast<float>(m_input_sample_rate);
+ float aid_sample_rate =
+ FIXED_SAMPLE_RATE_DIVIDEND / static_cast<float>(m_input_sample_rate_divisor);
if (consider_framelimit && emulationspeed > 0.0f)
{
float numLeft = static_cast<float>(((indexW - indexR) & INDEX_MASK) / 2);
- u32 low_waterwark = m_input_sample_rate * timing_variance / 1000;
- low_waterwark = std::min(low_waterwark, MAX_SAMPLES / 2);
+ u32 low_watermark = (FIXED_SAMPLE_RATE_DIVIDEND * timing_variance) /
+ (static_cast<u64>(m_input_sample_rate_divisor) * 1000);
+ low_watermark = std::min(low_watermark, MAX_SAMPLES / 2);
m_numLeftI = (numLeft + m_numLeftI * (CONTROL_AVG - 1)) / CONTROL_AVG;
- float offset = (m_numLeftI - low_waterwark) * CONTROL_FACTOR;
+ float offset = (m_numLeftI - low_watermark) * CONTROL_FACTOR;
if (offset > MAX_FREQ_SHIFT)
offset = MAX_FREQ_SHIFT;
if (offset < -MAX_FREQ_SHIFT)
@@ -258,9 +260,9 @@ void Mixer::PushSamples(const short* samples, unsigned int num_samples)
m_dma_mixer.PushSamples(samples, num_samples);
if (m_log_dsp_audio)
{
- int sample_rate = m_dma_mixer.GetInputSampleRate();
+ int sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor();
auto volume = m_dma_mixer.GetVolume();
- m_wave_writer_dsp.AddStereoSamplesBE(samples, num_samples, sample_rate, volume.first,
+ m_wave_writer_dsp.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first,
volume.second);
}
}
@@ -270,21 +272,21 @@ void Mixer::PushStreamingSamples(const short* samples, unsigned int num_samples)
m_streaming_mixer.PushSamples(samples, num_samples);
if (m_log_dtk_audio)
{
- int sample_rate = m_streaming_mixer.GetInputSampleRate();
+ int sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor();
auto volume = m_streaming_mixer.GetVolume();
- m_wave_writer_dtk.AddStereoSamplesBE(samples, num_samples, sample_rate, volume.first,
+ m_wave_writer_dtk.AddStereoSamplesBE(samples, num_samples, sample_rate_divisor, volume.first,
volume.second);
}
}
void Mixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples,
- unsigned int sample_rate)
+ unsigned int sample_rate_divisor)
{
short samples_stereo[MAX_SAMPLES * 2];
if (num_samples < MAX_SAMPLES)
{
- m_wiimote_speaker_mixer.SetInputSampleRate(sample_rate);
+ m_wiimote_speaker_mixer.SetInputSampleRateDivisor(sample_rate_divisor);
for (unsigned int i = 0; i < num_samples; ++i)
{
@@ -301,19 +303,19 @@ void Mixer::PushGBASamples(int device_number, const short* samples, unsigned int
m_gba_mixers[device_number].PushSamples(samples, num_samples);
}
-void Mixer::SetDMAInputSampleRate(unsigned int rate)
+void Mixer::SetDMAInputSampleRateDivisor(unsigned int rate_divisor)
{
- m_dma_mixer.SetInputSampleRate(rate);
+ m_dma_mixer.SetInputSampleRateDivisor(rate_divisor);
}
-void Mixer::SetStreamInputSampleRate(unsigned int rate)
+void Mixer::SetStreamInputSampleRateDivisor(unsigned int rate_divisor)
{
- m_streaming_mixer.SetInputSampleRate(rate);
+ m_streaming_mixer.SetInputSampleRateDivisor(rate_divisor);
}
-void Mixer::SetGBAInputSampleRates(int device_number, unsigned int rate)
+void Mixer::SetGBAInputSampleRateDivisors(int device_number, unsigned int rate_divisor)
{
- m_gba_mixers[device_number].SetInputSampleRate(rate);
+ m_gba_mixers[device_number].SetInputSampleRateDivisor(rate_divisor);
}
void Mixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume)
@@ -335,7 +337,7 @@ void Mixer::StartLogDTKAudio(const std::string& filename)
{
if (!m_log_dtk_audio)
{
- bool success = m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRate());
+ bool success = m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor());
if (success)
{
m_log_dtk_audio = true;
@@ -372,7 +374,7 @@ void Mixer::StartLogDSPAudio(const std::string& filename)
{
if (!m_log_dsp_audio)
{
- bool success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRate());
+ bool success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor());
if (success)
{
m_log_dsp_audio = true;
@@ -414,19 +416,19 @@ void Mixer::RefreshConfig()
void Mixer::MixerFifo::DoState(PointerWrap& p)
{
- p.Do(m_input_sample_rate);
+ p.Do(m_input_sample_rate_divisor);
p.Do(m_LVolume);
p.Do(m_RVolume);
}
-void Mixer::MixerFifo::SetInputSampleRate(unsigned int rate)
+void Mixer::MixerFifo::SetInputSampleRateDivisor(unsigned int rate_divisor)
{
- m_input_sample_rate = rate;
+ m_input_sample_rate_divisor = rate_divisor;
}
-unsigned int Mixer::MixerFifo::GetInputSampleRate() const
+unsigned int Mixer::MixerFifo::GetInputSampleRateDivisor() const
{
- return m_input_sample_rate;
+ return m_input_sample_rate_divisor;
}
void Mixer::MixerFifo::SetVolume(unsigned int lvolume, unsigned int rvolume)
@@ -445,5 +447,6 @@ unsigned int Mixer::MixerFifo::AvailableSamples() const
unsigned int samples_in_fifo = ((m_indexW.load() - m_indexR.load()) & INDEX_MASK) / 2;
if (samples_in_fifo <= 1)
return 0; // Mixer::MixerFifo::Mix always keeps one sample in the buffer.
- return (samples_in_fifo - 1) * m_mixer->m_sampleRate / m_input_sample_rate;
+ return (samples_in_fifo - 1) * static_cast<u64>(m_mixer->m_sampleRate) *
+ m_input_sample_rate_divisor / FIXED_SAMPLE_RATE_DIVIDEND;
}
diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h
index f58c25f98a..7191fd6ab0 100644
--- a/Source/Core/AudioCommon/Mixer.h
+++ b/Source/Core/AudioCommon/Mixer.h
@@ -29,14 +29,14 @@ public:
void PushSamples(const short* samples, unsigned int num_samples);
void PushStreamingSamples(const short* samples, unsigned int num_samples);
void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples,
- unsigned int sample_rate);
+ unsigned int sample_rate_divisor);
void PushGBASamples(int device_number, const short* samples, unsigned int num_samples);
unsigned int GetSampleRate() const { return m_sampleRate; }
- void SetDMAInputSampleRate(unsigned int rate);
- void SetStreamInputSampleRate(unsigned int rate);
- void SetGBAInputSampleRates(int device_number, unsigned int rate);
+ void SetDMAInputSampleRateDivisor(unsigned int rate_divisor);
+ void SetStreamInputSampleRateDivisor(unsigned int rate_divisor);
+ void SetGBAInputSampleRateDivisors(int device_number, unsigned int rate_divisor);
void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume);
void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume);
@@ -51,6 +51,9 @@ public:
float GetCurrentSpeed() const { return m_speed.load(); }
void UpdateSpeed(float val) { m_speed.store(val); }
+ // 54000000 doesn't work here as it doesn't evenly divide with 32000, but 108000000 does
+ static constexpr u64 FIXED_SAMPLE_RATE_DIVIDEND = 54000000 * 2;
+
private:
static constexpr u32 MAX_SAMPLES = 1024 * 4; // 128 ms
static constexpr u32 INDEX_MASK = MAX_SAMPLES * 2 - 1;
@@ -63,23 +66,24 @@ private:
class MixerFifo final
{
public:
- MixerFifo(Mixer* mixer, unsigned sample_rate, bool little_endian)
- : m_mixer(mixer), m_input_sample_rate(sample_rate), m_little_endian(little_endian)
+ MixerFifo(Mixer* mixer, unsigned sample_rate_divisor, bool little_endian)
+ : m_mixer(mixer), m_input_sample_rate_divisor(sample_rate_divisor),
+ m_little_endian(little_endian)
{
}
void DoState(PointerWrap& p);
void PushSamples(const short* samples, unsigned int num_samples);
unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit,
float emulationspeed, int timing_variance);
- void SetInputSampleRate(unsigned int rate);
- unsigned int GetInputSampleRate() const;
+ void SetInputSampleRateDivisor(unsigned int rate_divisor);
+ unsigned int GetInputSampleRateDivisor() const;
void SetVolume(unsigned int lvolume, unsigned int rvolume);
std::pair<s32, s32> GetVolume() const;
unsigned int AvailableSamples() const;
private:
Mixer* m_mixer;
- unsigned m_input_sample_rate;
+ unsigned m_input_sample_rate_divisor;
bool m_little_endian;
std::array<short, MAX_SAMPLES * 2> m_buffer{};
std::atomic<u32> m_indexW{0};
@@ -93,11 +97,13 @@ private:
void RefreshConfig();
- MixerFifo m_dma_mixer{this, 32000, false};
- MixerFifo m_streaming_mixer{this, 48000, false};
- MixerFifo m_wiimote_speaker_mixer{this, 3000, true};
- std::array<MixerFifo, 4> m_gba_mixers{MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true},
- MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true}};
+ MixerFifo m_dma_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 32000, false};
+ MixerFifo m_streaming_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, false};
+ MixerFifo m_wiimote_speaker_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 3000, true};
+ std::array<MixerFifo, 4> m_gba_mixers{MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true},
+ MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true},
+ MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true},
+ MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true}};
unsigned int m_sampleRate;
bool m_is_stretching = false;
diff --git a/Source/Core/AudioCommon/WaveFile.cpp b/Source/Core/AudioCommon/WaveFile.cpp
index befcf6bfbd..dc689e74dd 100644
--- a/Source/Core/AudioCommon/WaveFile.cpp
+++ b/Source/Core/AudioCommon/WaveFile.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "AudioCommon/WaveFile.h"
+#include "AudioCommon/Mixer.h"
#include <string>
@@ -26,7 +27,7 @@ WaveFileWriter::~WaveFileWriter()
Stop();
}
-bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRate)
+bool WaveFileWriter::Start(const std::string& filename, u32 sample_rate_divisor)
{
// Ask to delete file
if (File::Exists(filename))
@@ -65,7 +66,7 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa
if (basename.empty())
SplitPath(filename, nullptr, &basename, nullptr);
- current_sample_rate = HLESampleRate;
+ current_sample_rate_divisor = sample_rate_divisor;
// -----------------
// Write file header
@@ -78,7 +79,7 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa
Write(16); // size of fmt block
Write(0x00020001); // two channels, uncompressed
- const u32 sample_rate = HLESampleRate;
+ const u32 sample_rate = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / sample_rate_divisor;
Write(sample_rate);
Write(sample_rate * 2 * 2); // two channels, 16bit
@@ -114,8 +115,8 @@ void WaveFileWriter::Write4(const char* ptr)
file.WriteBytes(ptr, 4);
}
-void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count, int sample_rate,
- int l_volume, int r_volume)
+void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count,
+ u32 sample_rate_divisor, int l_volume, int r_volume)
{
if (!file)
ERROR_LOG_FMT(AUDIO, "WaveFileWriter - file not open.");
@@ -148,14 +149,14 @@ void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count, int
conv_buffer[2 * i + 1] = conv_buffer[2 * i + 1] * r_volume / 256;
}
- if (sample_rate != current_sample_rate)
+ if (sample_rate_divisor != current_sample_rate_divisor)
{
Stop();
file_index++;
std::ostringstream filename;
filename << File::GetUserPath(D_DUMPAUDIO_IDX) << basename << file_index << ".wav";
- Start(filename.str(), sample_rate);
- current_sample_rate = sample_rate;
+ Start(filename.str(), sample_rate_divisor);
+ current_sample_rate_divisor = sample_rate_divisor;
}
file.WriteBytes(conv_buffer.data(), count * 4);
diff --git a/Source/Core/AudioCommon/WaveFile.h b/Source/Core/AudioCommon/WaveFile.h
index e95ed8eb73..350e1da9af 100644
--- a/Source/Core/AudioCommon/WaveFile.h
+++ b/Source/Core/AudioCommon/WaveFile.h
@@ -30,24 +30,28 @@ public:
WaveFileWriter(WaveFileWriter&&) = delete;
WaveFileWriter& operator=(WaveFileWriter&&) = delete;
- bool Start(const std::string& filename, unsigned int HLESampleRate);
+ bool Start(const std::string& filename, u32 sample_rate_divisor);
void Stop();
void SetSkipSilence(bool skip) { skip_silence = skip; }
- void AddStereoSamplesBE(const short* sample_data, u32 count, int sample_rate, int l_volume,
- int r_volume); // big endian
+ // big endian
+ void AddStereoSamplesBE(const short* sample_data, u32 count, u32 sample_rate_divisor,
+ int l_volume, int r_volume);
u32 GetAudioSize() const { return audio_size; }
private:
static constexpr size_t BUFFER_SIZE = 32 * 1024;
- File::IOFile file;
- bool skip_silence = false;
- u32 audio_size = 0;
- std::array<short, BUFFER_SIZE> conv_buffer{};
void Write(u32 value);
void Write4(const char* ptr);
+
+ File::IOFile file;
std::string basename;
- int current_sample_rate;
- int file_index = 0;
+ u32 file_index = 0;
+ u32 audio_size = 0;
+
+ u32 current_sample_rate_divisor;
+ std::array<short, BUFFER_SIZE> conv_buffer{};
+
+ bool skip_silence = false;
};