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
This commit is contained in:
Admiral H. Curtiss 2022-07-05 11:37:30 +02:00 committed by GitHub
commit de3d1344d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 121 additions and 93 deletions

View File

@ -76,16 +76,18 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples,
// advance indexR with sample position // advance indexR with sample position
// remember fractional offset // 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) if (consider_framelimit && emulationspeed > 0.0f)
{ {
float numLeft = static_cast<float>(((indexW - indexR) & INDEX_MASK) / 2); float numLeft = static_cast<float>(((indexW - indexR) & INDEX_MASK) / 2);
u32 low_waterwark = m_input_sample_rate * timing_variance / 1000; u32 low_watermark = (FIXED_SAMPLE_RATE_DIVIDEND * timing_variance) /
low_waterwark = std::min(low_waterwark, MAX_SAMPLES / 2); (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; 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) if (offset > MAX_FREQ_SHIFT)
offset = MAX_FREQ_SHIFT; offset = MAX_FREQ_SHIFT;
if (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); m_dma_mixer.PushSamples(samples, num_samples);
if (m_log_dsp_audio) 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(); 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); volume.second);
} }
} }
@ -270,21 +272,21 @@ void Mixer::PushStreamingSamples(const short* samples, unsigned int num_samples)
m_streaming_mixer.PushSamples(samples, num_samples); m_streaming_mixer.PushSamples(samples, num_samples);
if (m_log_dtk_audio) 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(); 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); volume.second);
} }
} }
void Mixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, 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]; short samples_stereo[MAX_SAMPLES * 2];
if (num_samples < MAX_SAMPLES) 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) 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); 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) 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) 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) if (success)
{ {
m_log_dtk_audio = true; m_log_dtk_audio = true;
@ -372,7 +374,7 @@ void Mixer::StartLogDSPAudio(const std::string& filename)
{ {
if (!m_log_dsp_audio) 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) if (success)
{ {
m_log_dsp_audio = true; m_log_dsp_audio = true;
@ -414,19 +416,19 @@ void Mixer::RefreshConfig()
void Mixer::MixerFifo::DoState(PointerWrap& p) 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_LVolume);
p.Do(m_RVolume); 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) 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; unsigned int samples_in_fifo = ((m_indexW.load() - m_indexR.load()) & INDEX_MASK) / 2;
if (samples_in_fifo <= 1) if (samples_in_fifo <= 1)
return 0; // Mixer::MixerFifo::Mix always keeps one sample in the buffer. 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;
} }

View File

@ -29,14 +29,14 @@ public:
void PushSamples(const short* samples, unsigned int num_samples); void PushSamples(const short* samples, unsigned int num_samples);
void PushStreamingSamples(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, 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); void PushGBASamples(int device_number, const short* samples, unsigned int num_samples);
unsigned int GetSampleRate() const { return m_sampleRate; } unsigned int GetSampleRate() const { return m_sampleRate; }
void SetDMAInputSampleRate(unsigned int rate); void SetDMAInputSampleRateDivisor(unsigned int rate_divisor);
void SetStreamInputSampleRate(unsigned int rate); void SetStreamInputSampleRateDivisor(unsigned int rate_divisor);
void SetGBAInputSampleRates(int device_number, unsigned int rate); void SetGBAInputSampleRateDivisors(int device_number, unsigned int rate_divisor);
void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume); void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume);
void SetWiimoteSpeakerVolume(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(); } float GetCurrentSpeed() const { return m_speed.load(); }
void UpdateSpeed(float val) { m_speed.store(val); } 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: private:
static constexpr u32 MAX_SAMPLES = 1024 * 4; // 128 ms static constexpr u32 MAX_SAMPLES = 1024 * 4; // 128 ms
static constexpr u32 INDEX_MASK = MAX_SAMPLES * 2 - 1; static constexpr u32 INDEX_MASK = MAX_SAMPLES * 2 - 1;
@ -63,23 +66,24 @@ private:
class MixerFifo final class MixerFifo final
{ {
public: public:
MixerFifo(Mixer* mixer, unsigned sample_rate, bool little_endian) MixerFifo(Mixer* mixer, unsigned sample_rate_divisor, bool little_endian)
: m_mixer(mixer), m_input_sample_rate(sample_rate), m_little_endian(little_endian) : m_mixer(mixer), m_input_sample_rate_divisor(sample_rate_divisor),
m_little_endian(little_endian)
{ {
} }
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
void PushSamples(const short* samples, unsigned int num_samples); void PushSamples(const short* samples, unsigned int num_samples);
unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit, unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit,
float emulationspeed, int timing_variance); float emulationspeed, int timing_variance);
void SetInputSampleRate(unsigned int rate); void SetInputSampleRateDivisor(unsigned int rate_divisor);
unsigned int GetInputSampleRate() const; unsigned int GetInputSampleRateDivisor() const;
void SetVolume(unsigned int lvolume, unsigned int rvolume); void SetVolume(unsigned int lvolume, unsigned int rvolume);
std::pair<s32, s32> GetVolume() const; std::pair<s32, s32> GetVolume() const;
unsigned int AvailableSamples() const; unsigned int AvailableSamples() const;
private: private:
Mixer* m_mixer; Mixer* m_mixer;
unsigned m_input_sample_rate; unsigned m_input_sample_rate_divisor;
bool m_little_endian; bool m_little_endian;
std::array<short, MAX_SAMPLES * 2> m_buffer{}; std::array<short, MAX_SAMPLES * 2> m_buffer{};
std::atomic<u32> m_indexW{0}; std::atomic<u32> m_indexW{0};
@ -93,11 +97,13 @@ private:
void RefreshConfig(); void RefreshConfig();
MixerFifo m_dma_mixer{this, 32000, false}; MixerFifo m_dma_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 32000, false};
MixerFifo m_streaming_mixer{this, 48000, false}; MixerFifo m_streaming_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, false};
MixerFifo m_wiimote_speaker_mixer{this, 3000, true}; MixerFifo m_wiimote_speaker_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 3000, true};
std::array<MixerFifo, 4> m_gba_mixers{MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true}, std::array<MixerFifo, 4> m_gba_mixers{MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true},
MixerFifo{this, 48000, true}, MixerFifo{this, 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; unsigned int m_sampleRate;
bool m_is_stretching = false; bool m_is_stretching = false;

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "AudioCommon/WaveFile.h" #include "AudioCommon/WaveFile.h"
#include "AudioCommon/Mixer.h"
#include <string> #include <string>
@ -26,7 +27,7 @@ WaveFileWriter::~WaveFileWriter()
Stop(); 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 // Ask to delete file
if (File::Exists(filename)) if (File::Exists(filename))
@ -65,7 +66,7 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa
if (basename.empty()) if (basename.empty())
SplitPath(filename, nullptr, &basename, nullptr); SplitPath(filename, nullptr, &basename, nullptr);
current_sample_rate = HLESampleRate; current_sample_rate_divisor = sample_rate_divisor;
// ----------------- // -----------------
// Write file header // Write file header
@ -78,7 +79,7 @@ bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRa
Write(16); // size of fmt block Write(16); // size of fmt block
Write(0x00020001); // two channels, uncompressed 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);
Write(sample_rate * 2 * 2); // two channels, 16bit Write(sample_rate * 2 * 2); // two channels, 16bit
@ -114,8 +115,8 @@ void WaveFileWriter::Write4(const char* ptr)
file.WriteBytes(ptr, 4); file.WriteBytes(ptr, 4);
} }
void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count, int sample_rate, void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count,
int l_volume, int r_volume) u32 sample_rate_divisor, int l_volume, int r_volume)
{ {
if (!file) if (!file)
ERROR_LOG_FMT(AUDIO, "WaveFileWriter - file not open."); 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; 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(); Stop();
file_index++; file_index++;
std::ostringstream filename; std::ostringstream filename;
filename << File::GetUserPath(D_DUMPAUDIO_IDX) << basename << file_index << ".wav"; filename << File::GetUserPath(D_DUMPAUDIO_IDX) << basename << file_index << ".wav";
Start(filename.str(), sample_rate); Start(filename.str(), sample_rate_divisor);
current_sample_rate = sample_rate; current_sample_rate_divisor = sample_rate_divisor;
} }
file.WriteBytes(conv_buffer.data(), count * 4); file.WriteBytes(conv_buffer.data(), count * 4);

View File

@ -30,24 +30,28 @@ public:
WaveFileWriter(WaveFileWriter&&) = delete; WaveFileWriter(WaveFileWriter&&) = delete;
WaveFileWriter& operator=(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 Stop();
void SetSkipSilence(bool skip) { skip_silence = skip; } void SetSkipSilence(bool skip) { skip_silence = skip; }
void AddStereoSamplesBE(const short* sample_data, u32 count, int sample_rate, int l_volume, // big endian
int r_volume); // 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; } u32 GetAudioSize() const { return audio_size; }
private: private:
static constexpr size_t BUFFER_SIZE = 32 * 1024; 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 Write(u32 value);
void Write4(const char* ptr); void Write4(const char* ptr);
File::IOFile file;
std::string basename; std::string basename;
int current_sample_rate; u32 file_index = 0;
int file_index = 0; u32 audio_size = 0;
u32 current_sample_rate_divisor;
std::array<short, BUFFER_SIZE> conv_buffer{};
bool skip_silence = false;
}; };

View File

@ -112,8 +112,8 @@ static u32 s_interrupt_timing = 0;
static u64 s_last_cpu_time = 0; static u64 s_last_cpu_time = 0;
static u64 s_cpu_cycles_per_sample = 0; static u64 s_cpu_cycles_per_sample = 0;
static u32 s_ais_sample_rate = 48000; static u32 s_ais_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 48000;
static u32 s_aid_sample_rate = 32000; static u32 s_aid_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 32000;
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
{ {
@ -122,8 +122,8 @@ void DoState(PointerWrap& p)
p.Do(s_sample_counter); p.Do(s_sample_counter);
p.Do(s_interrupt_timing); p.Do(s_interrupt_timing);
p.Do(s_last_cpu_time); p.Do(s_last_cpu_time);
p.Do(s_ais_sample_rate); p.Do(s_ais_sample_rate_divisor);
p.Do(s_aid_sample_rate); p.Do(s_aid_sample_rate_divisor);
p.Do(s_cpu_cycles_per_sample); p.Do(s_cpu_cycles_per_sample);
g_sound_stream->GetMixer()->DoState(p); g_sound_stream->GetMixer()->DoState(p);
@ -148,14 +148,15 @@ void Init()
s_last_cpu_time = 0; s_last_cpu_time = 0;
s_ais_sample_rate = Get48KHzSampleRate(); s_ais_sample_rate_divisor = Get48KHzSampleRateDivisor();
s_aid_sample_rate = Get32KHzSampleRate(); s_aid_sample_rate_divisor = Get32KHzSampleRateDivisor();
s_cpu_cycles_per_sample = SystemTimers::GetTicksPerSecond() / s_ais_sample_rate; s_cpu_cycles_per_sample = static_cast<u64>(SystemTimers::GetTicksPerSecond()) *
s_ais_sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
event_type_ai = CoreTiming::RegisterEvent("AICallback", Update); event_type_ai = CoreTiming::RegisterEvent("AICallback", Update);
g_sound_stream->GetMixer()->SetDMAInputSampleRate(GetAIDSampleRate()); g_sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(GetAIDSampleRateDivisor());
g_sound_stream->GetMixer()->SetStreamInputSampleRate(GetAISSampleRate()); g_sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(GetAISSampleRateDivisor());
} }
void Shutdown() void Shutdown()
@ -188,9 +189,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AISFR to {}", DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AISFR to {}",
tmp_ai_ctrl.AISFR ? "48khz" : "32khz"); tmp_ai_ctrl.AISFR ? "48khz" : "32khz");
s_control.AISFR = tmp_ai_ctrl.AISFR; s_control.AISFR = tmp_ai_ctrl.AISFR;
s_ais_sample_rate = tmp_ai_ctrl.AISFR ? Get48KHzSampleRate() : Get32KHzSampleRate(); s_ais_sample_rate_divisor =
g_sound_stream->GetMixer()->SetStreamInputSampleRate(s_ais_sample_rate); tmp_ai_ctrl.AISFR ? Get48KHzSampleRateDivisor() : Get32KHzSampleRateDivisor();
s_cpu_cycles_per_sample = SystemTimers::GetTicksPerSecond() / s_ais_sample_rate; g_sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(s_ais_sample_rate_divisor);
s_cpu_cycles_per_sample = static_cast<u64>(SystemTimers::GetTicksPerSecond()) *
s_ais_sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
} }
// Set frequency of DMA // Set frequency of DMA
if (tmp_ai_ctrl.AIDFR != s_control.AIDFR) if (tmp_ai_ctrl.AIDFR != s_control.AIDFR)
@ -198,8 +201,9 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIDFR to {}", DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIDFR to {}",
tmp_ai_ctrl.AIDFR ? "32khz" : "48khz"); tmp_ai_ctrl.AIDFR ? "32khz" : "48khz");
s_control.AIDFR = tmp_ai_ctrl.AIDFR; s_control.AIDFR = tmp_ai_ctrl.AIDFR;
s_aid_sample_rate = tmp_ai_ctrl.AIDFR ? Get32KHzSampleRate() : Get48KHzSampleRate(); s_aid_sample_rate_divisor =
g_sound_stream->GetMixer()->SetDMAInputSampleRate(s_aid_sample_rate); tmp_ai_ctrl.AIDFR ? Get32KHzSampleRateDivisor() : Get48KHzSampleRateDivisor();
g_sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(s_aid_sample_rate_divisor);
} }
// Streaming counter // Streaming counter
@ -301,24 +305,24 @@ bool IsPlaying()
return (s_control.PSTAT == 1); return (s_control.PSTAT == 1);
} }
u32 GetAIDSampleRate() u32 GetAIDSampleRateDivisor()
{ {
return s_aid_sample_rate; return s_aid_sample_rate_divisor;
} }
u32 GetAISSampleRate() u32 GetAISSampleRateDivisor()
{ {
return s_ais_sample_rate; return s_ais_sample_rate_divisor;
} }
u32 Get32KHzSampleRate() u32 Get32KHzSampleRateDivisor()
{ {
return SConfig::GetInstance().bWii ? 32000 : 32029; return Get48KHzSampleRateDivisor() * 3 / 2;
} }
u32 Get48KHzSampleRate() u32 Get48KHzSampleRateDivisor()
{ {
return SConfig::GetInstance().bWii ? 48000 : 48043; return (SConfig::GetInstance().bWii ? 1125 : 1124) * 2;
} }
static void Update(u64 userdata, s64 cycles_late) static void Update(u64 userdata, s64 cycles_late)
@ -339,7 +343,8 @@ static void Update(u64 userdata, s64 cycles_late)
int GetAIPeriod() int GetAIPeriod()
{ {
u64 period = s_cpu_cycles_per_sample * (s_interrupt_timing - s_sample_counter); u64 period = s_cpu_cycles_per_sample * (s_interrupt_timing - s_sample_counter);
u64 s_period = s_cpu_cycles_per_sample * s_ais_sample_rate; u64 s_period =
s_cpu_cycles_per_sample * Mixer::FIXED_SAMPLE_RATE_DIVIDEND / s_ais_sample_rate_divisor;
if (period == 0) if (period == 0)
return static_cast<int>(s_period); return static_cast<int>(s_period);
return static_cast<int>(std::min(period, s_period)); return static_cast<int>(std::min(period, s_period));

View File

@ -22,12 +22,13 @@ bool IsPlaying();
void RegisterMMIO(MMIO::Mapping* mmio, u32 base); void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
// Get the audio rates (48000 or 32000 only) // Get the audio rate divisors (divisors for 48KHz or 32KHz only)
u32 GetAIDSampleRate(); // Mixer::FIXED_SAMPLE_RATE_DIVIDEND will be the dividend used for these divisors
u32 GetAISSampleRate(); u32 GetAIDSampleRateDivisor();
u32 GetAISSampleRateDivisor();
u32 Get32KHzSampleRate(); u32 Get32KHzSampleRateDivisor();
u32 Get48KHzSampleRate(); u32 Get48KHzSampleRateDivisor();
void GenerateAISInterrupt(); void GenerateAISInterrupt();

View File

@ -294,12 +294,16 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data, static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data,
s64 cycles_late) s64 cycles_late)
{ {
// TODO: Should we use GetAISSampleRate instead of a fixed 48 KHz? The audio mixer is using // Actual games always set this to 48 KHz
// GetAISSampleRate. (This doesn't affect any actual games, since they all set it to 48 KHz.) // but let's make sure to use GetAISSampleRateDivisor()
const u32 sample_rate = AudioInterface::Get48KHzSampleRate(); // just in case it changes to 32 KHz
const u32 sample_rate_divisor = AudioInterface::GetAISSampleRateDivisor();
// Determine which audio data to read next. // Determine which audio data to read next.
const u32 maximum_samples = sample_rate / 2000 * 7; // 3.5 ms of samples
// 3.5 ms of samples
const u32 maximum_samples =
((Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 2000) * 7) / sample_rate_divisor;
u64 read_offset = 0; u64 read_offset = 0;
u32 read_length = 0; u32 read_length = 0;
@ -328,7 +332,8 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
} }
// Read the next chunk of audio data asynchronously. // Read the next chunk of audio data asynchronously.
s64 ticks_to_dtk = SystemTimers::GetTicksPerSecond() * s64(s_pending_samples) / sample_rate; s64 ticks_to_dtk = SystemTimers::GetTicksPerSecond() * s64(s_pending_samples) *
sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
ticks_to_dtk -= cycles_late; ticks_to_dtk -= cycles_late;
if (read_length > 0) if (read_length > 0)
{ {

View File

@ -405,7 +405,8 @@ void Core::SetSampleRates()
m_core->setAudioBufferSize(m_core, SAMPLES); m_core->setAudioBufferSize(m_core, SAMPLES);
blip_set_rates(m_core->getAudioChannel(m_core, 0), m_core->frequency(m_core), SAMPLE_RATE); blip_set_rates(m_core->getAudioChannel(m_core, 0), m_core->frequency(m_core), SAMPLE_RATE);
blip_set_rates(m_core->getAudioChannel(m_core, 1), m_core->frequency(m_core), SAMPLE_RATE); blip_set_rates(m_core->getAudioChannel(m_core, 1), m_core->frequency(m_core), SAMPLE_RATE);
g_sound_stream->GetMixer()->SetGBAInputSampleRates(m_device_number, SAMPLE_RATE); g_sound_stream->GetMixer()->SetGBAInputSampleRateDivisors(
m_device_number, Mixer::FIXED_SAMPLE_RATE_DIVIDEND / SAMPLE_RATE);
} }
void Core::AddCallbacks() void Core::AddCallbacks()

View File

@ -48,6 +48,7 @@ IPC_HLE_PERIOD: For the Wii Remote this is the call schedule:
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#include "AudioCommon/Mixer.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/Thread.h" #include "Common/Thread.h"
@ -110,7 +111,8 @@ void DSPCallback(u64 userdata, s64 cyclesLate)
int GetAudioDMACallbackPeriod() int GetAudioDMACallbackPeriod()
{ {
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA // System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
return s_cpu_core_clock / (AudioInterface::GetAIDSampleRate() * 4 / 32); return static_cast<u64>(s_cpu_core_clock) * AudioInterface::GetAIDSampleRateDivisor() /
(Mixer::FIXED_SAMPLE_RATE_DIVIDEND * 4 / 32);
} }
void AudioDMACallback(u64 userdata, s64 cyclesLate) void AudioDMACallback(u64 userdata, s64 cyclesLate)

View File

@ -145,8 +145,8 @@ void SpeakerLogic::SpeakerData(const u8* data, int length, float speaker_pan)
// ADPCM sample rate is thought to be x2.(3000 x2 = 6000). // ADPCM sample rate is thought to be x2.(3000 x2 = 6000).
const unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate; const unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate;
g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(samples.get(), sample_length, g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(
sample_rate * 2); samples.get(), sample_length, Mixer::FIXED_SAMPLE_RATE_DIVIDEND / (sample_rate * 2));
#ifdef WIIMOTE_SPEAKER_DUMP #ifdef WIIMOTE_SPEAKER_DUMP
static int num = 0; static int num = 0;

View File

@ -74,7 +74,7 @@ static std::recursive_mutex g_save_thread_mutex;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 143; // Last changed in PR 10784 constexpr u32 STATE_VERSION = 144; // Last changed in PR 10762
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,