@@ -112,8 +112,8 @@ static u32 s_interrupt_timing = 0;
static u64 s_last_cpu_time = 0;
static u64 s_cpu_cycles_per_sample = 0;

static u32 s_ais_sample_rate = 48000;
static u32 s_aid_sample_rate = 32000;
static u32 s_ais_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 48000;
static u32 s_aid_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 32000;

void DoState(PointerWrap& p)
{
@@ -122,8 +122,8 @@ void DoState(PointerWrap& p)
p.Do(s_sample_counter);
p.Do(s_interrupt_timing);
p.Do(s_last_cpu_time);
p.Do(s_ais_sample_rate);
p.Do(s_aid_sample_rate);
p.Do(s_ais_sample_rate_divisor);
p.Do(s_aid_sample_rate_divisor);
p.Do(s_cpu_cycles_per_sample);

g_sound_stream->GetMixer()->DoState(p);
@@ -148,14 +148,15 @@ void Init()

s_last_cpu_time = 0;

s_ais_sample_rate = Get48KHzSampleRate();
s_aid_sample_rate = Get32KHzSampleRate();
s_cpu_cycles_per_sample = SystemTimers::GetTicksPerSecond() / s_ais_sample_rate;
s_ais_sample_rate_divisor = Get48KHzSampleRateDivisor();
s_aid_sample_rate_divisor = Get32KHzSampleRateDivisor();
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);

g_sound_stream->GetMixer()->SetDMAInputSampleRate(GetAIDSampleRate());
g_sound_stream->GetMixer()->SetStreamInputSampleRate(GetAISSampleRate());
g_sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(GetAIDSampleRateDivisor());
g_sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(GetAISSampleRateDivisor());
}

void Shutdown()
@@ -188,18 +189,21 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AISFR to {}",
tmp_ai_ctrl.AISFR ? "48khz" : "32khz");
s_control.AISFR = tmp_ai_ctrl.AISFR;
s_ais_sample_rate = tmp_ai_ctrl.AISFR ? Get48KHzSampleRate() : Get32KHzSampleRate();
g_sound_stream->GetMixer()->SetStreamInputSampleRate(s_ais_sample_rate);
s_cpu_cycles_per_sample = SystemTimers::GetTicksPerSecond() / s_ais_sample_rate;
s_ais_sample_rate_divisor =
tmp_ai_ctrl.AISFR ? Get48KHzSampleRateDivisor() : Get32KHzSampleRateDivisor();
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
if (tmp_ai_ctrl.AIDFR != s_control.AIDFR)
{
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIDFR to {}",
tmp_ai_ctrl.AIDFR ? "32khz" : "48khz");
s_control.AIDFR = tmp_ai_ctrl.AIDFR;
s_aid_sample_rate = tmp_ai_ctrl.AIDFR ? Get32KHzSampleRate() : Get48KHzSampleRate();
g_sound_stream->GetMixer()->SetDMAInputSampleRate(s_aid_sample_rate);
s_aid_sample_rate_divisor =
tmp_ai_ctrl.AIDFR ? Get32KHzSampleRateDivisor() : Get48KHzSampleRateDivisor();
g_sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(s_aid_sample_rate_divisor);
}

// Streaming counter
@@ -301,24 +305,24 @@ bool IsPlaying()
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)
@@ -339,7 +343,8 @@ static void Update(u64 userdata, s64 cycles_late)
int GetAIPeriod()
{
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)
return static_cast<int>(s_period);
return static_cast<int>(std::min(period, s_period));
@@ -22,12 +22,13 @@ bool IsPlaying();

void RegisterMMIO(MMIO::Mapping* mmio, u32 base);

// Get the audio rates (48000 or 32000 only)
u32 GetAIDSampleRate();
u32 GetAISSampleRate();
// Get the audio rate divisors (divisors for 48KHz or 32KHz only)
// Mixer::FIXED_SAMPLE_RATE_DIVIDEND will be the dividend used for these divisors
u32 GetAIDSampleRateDivisor();
u32 GetAISSampleRateDivisor();

u32 Get32KHzSampleRate();
u32 Get48KHzSampleRate();
u32 Get32KHzSampleRateDivisor();
u32 Get48KHzSampleRateDivisor();

void GenerateAISInterrupt();

@@ -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,
s64 cycles_late)
{
// TODO: Should we use GetAISSampleRate instead of a fixed 48 KHz? The audio mixer is using
// GetAISSampleRate. (This doesn't affect any actual games, since they all set it to 48 KHz.)
const u32 sample_rate = AudioInterface::Get48KHzSampleRate();
// Actual games always set this to 48 KHz
// but let's make sure to use GetAISSampleRateDivisor()
// just in case it changes to 32 KHz
const u32 sample_rate_divisor = AudioInterface::GetAISSampleRateDivisor();

// 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;
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.
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;
if (read_length > 0)
{
@@ -405,7 +405,8 @@ void Core::SetSampleRates()
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, 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()
@@ -48,6 +48,7 @@ IPC_HLE_PERIOD: For the Wii Remote this is the call schedule:
#include <cmath>
#include <cstdlib>

#include "AudioCommon/Mixer.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/Thread.h"
@@ -110,7 +111,8 @@ void DSPCallback(u64 userdata, s64 cyclesLate)
int GetAudioDMACallbackPeriod()
{
// 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)
@@ -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).
const unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate;
g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(samples.get(), sample_length,
sample_rate * 2);
g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(
samples.get(), sample_length, Mixer::FIXED_SAMPLE_RATE_DIVIDEND / (sample_rate * 2));

#ifdef WIIMOTE_SPEAKER_DUMP
static int num = 0;
@@ -74,7 +74,7 @@ static std::recursive_mutex g_save_thread_mutex;
static std::thread g_save_thread;

// 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.
// Versions after 42 don't need to be added to this list,