Merge pull request #11041 from AdmiralCurtiss/global-state-audio

HW: Move AudioInterface variables to Core::System.
This commit is contained in:
Mai 2022-09-10 17:10:17 -04:00 committed by GitHub
commit 4edb3a8074
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 156 additions and 88 deletions

View File

@ -109,48 +109,61 @@ union AIVR
u32 hex = 0; u32 hex = 0;
}; };
// STATE_TO_SAVE struct AudioInterfaceState::Data
// Registers {
static AICR s_control; // Registers
static AIVR s_volume; AICR control;
static u32 s_sample_counter = 0; AIVR volume;
static u32 s_interrupt_timing = 0;
static u64 s_last_cpu_time = 0; u32 sample_counter = 0;
static u64 s_cpu_cycles_per_sample = 0; u32 interrupt_timing = 0;
static u32 s_ais_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 48000; u64 last_cpu_time = 0;
static u32 s_aid_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 32000; u64 cpu_cycles_per_sample = 0;
u32 ais_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 48000;
u32 aid_sample_rate_divisor = Mixer::FIXED_SAMPLE_RATE_DIVIDEND / 32000;
CoreTiming::EventType* event_type_ai;
};
AudioInterfaceState::AudioInterfaceState() : m_data(std::make_unique<Data>())
{
}
AudioInterfaceState::~AudioInterfaceState() = default;
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
{ {
p.DoPOD(s_control);
p.DoPOD(s_volume);
p.Do(s_sample_counter);
p.Do(s_interrupt_timing);
p.Do(s_last_cpu_time);
p.Do(s_ais_sample_rate_divisor);
p.Do(s_aid_sample_rate_divisor);
p.Do(s_cpu_cycles_per_sample);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& state = system.GetAudioInterfaceState().GetData();
p.DoPOD(state.control);
p.DoPOD(state.volume);
p.Do(state.sample_counter);
p.Do(state.interrupt_timing);
p.Do(state.last_cpu_time);
p.Do(state.ais_sample_rate_divisor);
p.Do(state.aid_sample_rate_divisor);
p.Do(state.cpu_cycles_per_sample);
SoundStream* sound_stream = system.GetSoundStream(); SoundStream* sound_stream = system.GetSoundStream();
sound_stream->GetMixer()->DoState(p); sound_stream->GetMixer()->DoState(p);
} }
namespace namespace
{ {
CoreTiming::EventType* event_type_ai;
void UpdateInterrupts() void UpdateInterrupts()
{ {
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_AI, ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_AI,
s_control.AIINT & s_control.AIINTMSK); state.control.AIINT & state.control.AIINTMSK);
} }
void GenerateAudioInterrupt() void GenerateAudioInterrupt()
{ {
s_control.AIINT = 1; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
state.control.AIINT = 1;
UpdateInterrupts(); UpdateInterrupts();
} }
@ -159,23 +172,27 @@ void IncreaseSampleCount(const u32 amount)
if (!IsPlaying()) if (!IsPlaying())
return; return;
const u32 old_sample_counter = s_sample_counter + 1; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
s_sample_counter += amount;
if ((s_interrupt_timing - old_sample_counter) <= (s_sample_counter - old_sample_counter)) const u32 old_sample_counter = state.sample_counter + 1;
state.sample_counter += amount;
if ((state.interrupt_timing - old_sample_counter) <= (state.sample_counter - old_sample_counter))
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, DEBUG_LOG_FMT(
"GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} s_control.AIINTVLD={}", AUDIO_INTERFACE, "GenerateAudioInterrupt {:08x}:{:08x} at PC {:08x} control.AIINTVLD={}",
s_sample_counter, s_interrupt_timing, PowerPC::ppcState.pc, s_control.AIINTVLD); state.sample_counter, state.interrupt_timing, PowerPC::ppcState.pc, state.control.AIINTVLD);
GenerateAudioInterrupt(); GenerateAudioInterrupt();
} }
} }
int GetAIPeriod() int GetAIPeriod()
{ {
u64 period = s_cpu_cycles_per_sample * (s_interrupt_timing - s_sample_counter); auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
u64 s_period =
s_cpu_cycles_per_sample * Mixer::FIXED_SAMPLE_RATE_DIVIDEND / s_ais_sample_rate_divisor; u64 period = state.cpu_cycles_per_sample * (state.interrupt_timing - state.sample_counter);
u64 s_period = state.cpu_cycles_per_sample * Mixer::FIXED_SAMPLE_RATE_DIVIDEND /
state.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));
@ -186,65 +203,73 @@ void Update(u64 userdata, s64 cycles_late)
if (!IsPlaying()) if (!IsPlaying())
return; return;
const u64 diff = CoreTiming::GetTicks() - s_last_cpu_time; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
if (diff > s_cpu_cycles_per_sample)
const u64 diff = CoreTiming::GetTicks() - state.last_cpu_time;
if (diff > state.cpu_cycles_per_sample)
{ {
const u32 samples = static_cast<u32>(diff / s_cpu_cycles_per_sample); const u32 samples = static_cast<u32>(diff / state.cpu_cycles_per_sample);
s_last_cpu_time += samples * s_cpu_cycles_per_sample; state.last_cpu_time += samples * state.cpu_cycles_per_sample;
IncreaseSampleCount(samples); IncreaseSampleCount(samples);
} }
CoreTiming::ScheduleEvent(GetAIPeriod() - cycles_late, event_type_ai); CoreTiming::ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai);
} }
void SetAIDSampleRate(SampleRate sample_rate) void SetAIDSampleRate(SampleRate sample_rate)
{ {
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
if (sample_rate == SampleRate::AI32KHz) if (sample_rate == SampleRate::AI32KHz)
{ {
s_control.AIDFR = AID_32KHz; state.control.AIDFR = AID_32KHz;
s_aid_sample_rate_divisor = Get32KHzSampleRateDivisor(); state.aid_sample_rate_divisor = Get32KHzSampleRateDivisor();
} }
else else
{ {
s_control.AIDFR = AID_48KHz; state.control.AIDFR = AID_48KHz;
s_aid_sample_rate_divisor = Get48KHzSampleRateDivisor(); state.aid_sample_rate_divisor = Get48KHzSampleRateDivisor();
} }
SoundStream* sound_stream = Core::System::GetInstance().GetSoundStream(); SoundStream* sound_stream = Core::System::GetInstance().GetSoundStream();
sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(s_aid_sample_rate_divisor); sound_stream->GetMixer()->SetDMAInputSampleRateDivisor(state.aid_sample_rate_divisor);
} }
void SetAISSampleRate(SampleRate sample_rate) void SetAISSampleRate(SampleRate sample_rate)
{ {
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
if (sample_rate == SampleRate::AI32KHz) if (sample_rate == SampleRate::AI32KHz)
{ {
s_control.AISFR = AIS_32KHz; state.control.AISFR = AIS_32KHz;
s_ais_sample_rate_divisor = Get32KHzSampleRateDivisor(); state.ais_sample_rate_divisor = Get32KHzSampleRateDivisor();
} }
else else
{ {
s_control.AISFR = AIS_48KHz; state.control.AISFR = AIS_48KHz;
s_ais_sample_rate_divisor = Get48KHzSampleRateDivisor(); state.ais_sample_rate_divisor = Get48KHzSampleRateDivisor();
} }
s_cpu_cycles_per_sample = static_cast<u64>(SystemTimers::GetTicksPerSecond()) * state.cpu_cycles_per_sample = static_cast<u64>(SystemTimers::GetTicksPerSecond()) *
s_ais_sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND; state.ais_sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND;
SoundStream* sound_stream = Core::System::GetInstance().GetSoundStream(); SoundStream* sound_stream = Core::System::GetInstance().GetSoundStream();
sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(s_ais_sample_rate_divisor); sound_stream->GetMixer()->SetStreamInputSampleRateDivisor(state.ais_sample_rate_divisor);
} }
} // namespace } // namespace
void Init() void Init()
{ {
s_control.hex = 0; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
state.control.hex = 0;
SetAISSampleRate(SampleRate::AI48KHz); SetAISSampleRate(SampleRate::AI48KHz);
SetAIDSampleRate(SampleRate::AI32KHz); SetAIDSampleRate(SampleRate::AI32KHz);
s_volume.hex = 0; state.volume.hex = 0;
s_sample_counter = 0; state.sample_counter = 0;
s_interrupt_timing = 0; state.interrupt_timing = 0;
s_last_cpu_time = 0; state.last_cpu_time = 0;
event_type_ai = CoreTiming::RegisterEvent("AICallback", Update); state.event_type_ai = CoreTiming::RegisterEvent("AICallback", Update);
} }
void Shutdown() void Shutdown()
@ -253,25 +278,28 @@ void Shutdown()
void RegisterMMIO(MMIO::Mapping* mmio, u32 base) void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{ {
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
mmio->Register( mmio->Register(
base | AI_CONTROL_REGISTER, MMIO::DirectRead<u32>(&s_control.hex), base | AI_CONTROL_REGISTER, MMIO::DirectRead<u32>(&state.control.hex),
MMIO::ComplexWrite<u32>([](u32, u32 val) { MMIO::ComplexWrite<u32>([](u32, u32 val) {
const AICR tmp_ai_ctrl(val); const AICR tmp_ai_ctrl(val);
if (s_control.AIINTMSK != tmp_ai_ctrl.AIINTMSK) auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
if (state.control.AIINTMSK != tmp_ai_ctrl.AIINTMSK)
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIINTMSK to {}", tmp_ai_ctrl.AIINTMSK); DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIINTMSK to {}", tmp_ai_ctrl.AIINTMSK);
s_control.AIINTMSK = tmp_ai_ctrl.AIINTMSK; state.control.AIINTMSK = tmp_ai_ctrl.AIINTMSK;
} }
if (s_control.AIINTVLD != tmp_ai_ctrl.AIINTVLD) if (state.control.AIINTVLD != tmp_ai_ctrl.AIINTVLD)
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIINTVLD to {}", tmp_ai_ctrl.AIINTVLD); DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AIINTVLD to {}", tmp_ai_ctrl.AIINTVLD);
s_control.AIINTVLD = tmp_ai_ctrl.AIINTVLD; state.control.AIINTVLD = tmp_ai_ctrl.AIINTVLD;
} }
// Set frequency of streaming audio // Set frequency of streaming audio
if (tmp_ai_ctrl.AISFR != s_control.AISFR) if (tmp_ai_ctrl.AISFR != state.control.AISFR)
{ {
// AISFR rates below are intentionally inverted wrt yagcd // AISFR rates below are intentionally inverted wrt yagcd
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AISFR to {}", DEBUG_LOG_FMT(AUDIO_INTERFACE, "Change AISFR to {}",
@ -280,7 +308,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
} }
// Set frequency of DMA // Set frequency of DMA
if (tmp_ai_ctrl.AIDFR != s_control.AIDFR) if (tmp_ai_ctrl.AIDFR != state.control.AIDFR)
{ {
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");
@ -288,64 +316,70 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
} }
// Streaming counter // Streaming counter
if (tmp_ai_ctrl.PSTAT != s_control.PSTAT) if (tmp_ai_ctrl.PSTAT != state.control.PSTAT)
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, "{} streaming audio", DEBUG_LOG_FMT(AUDIO_INTERFACE, "{} streaming audio",
tmp_ai_ctrl.PSTAT ? "start" : "stop"); tmp_ai_ctrl.PSTAT ? "start" : "stop");
s_control.PSTAT = tmp_ai_ctrl.PSTAT; state.control.PSTAT = tmp_ai_ctrl.PSTAT;
s_last_cpu_time = CoreTiming::GetTicks(); state.last_cpu_time = CoreTiming::GetTicks();
CoreTiming::RemoveEvent(event_type_ai); CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), event_type_ai); CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
} }
// AI Interrupt // AI Interrupt
if (tmp_ai_ctrl.AIINT) if (tmp_ai_ctrl.AIINT)
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Clear AIS Interrupt"); DEBUG_LOG_FMT(AUDIO_INTERFACE, "Clear AIS Interrupt");
s_control.AIINT = 0; state.control.AIINT = 0;
} }
// Sample Count Reset // Sample Count Reset
if (tmp_ai_ctrl.SCRESET) if (tmp_ai_ctrl.SCRESET)
{ {
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Reset AIS sample counter"); DEBUG_LOG_FMT(AUDIO_INTERFACE, "Reset AIS sample counter");
s_sample_counter = 0; state.sample_counter = 0;
s_last_cpu_time = CoreTiming::GetTicks(); state.last_cpu_time = CoreTiming::GetTicks();
} }
UpdateInterrupts(); UpdateInterrupts();
})); }));
mmio->Register(base | AI_VOLUME_REGISTER, MMIO::DirectRead<u32>(&s_volume.hex), mmio->Register(base | AI_VOLUME_REGISTER, MMIO::DirectRead<u32>(&state.volume.hex),
MMIO::ComplexWrite<u32>([](u32, u32 val) { MMIO::ComplexWrite<u32>([](u32, u32 val) {
s_volume.hex = val; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
state.volume.hex = val;
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
SoundStream* sound_stream = system.GetSoundStream(); SoundStream* sound_stream = system.GetSoundStream();
sound_stream->GetMixer()->SetStreamingVolume(s_volume.left, s_volume.right); sound_stream->GetMixer()->SetStreamingVolume(state.volume.left,
state.volume.right);
})); }));
mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead<u32>([](u32) { mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead<u32>([](u32) {
const u64 cycles_streamed = auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
IsPlaying() ? (CoreTiming::GetTicks() - s_last_cpu_time) : s_last_cpu_time; const u64 cycles_streamed = IsPlaying() ?
return s_sample_counter + (CoreTiming::GetTicks() - state.last_cpu_time) :
static_cast<u32>(cycles_streamed / s_cpu_cycles_per_sample); state.last_cpu_time;
return state.sample_counter +
static_cast<u32>(cycles_streamed / state.cpu_cycles_per_sample);
}), }),
MMIO::ComplexWrite<u32>([](u32, u32 val) { MMIO::ComplexWrite<u32>([](u32, u32 val) {
s_sample_counter = val; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
s_last_cpu_time = CoreTiming::GetTicks(); state.sample_counter = val;
CoreTiming::RemoveEvent(event_type_ai); state.last_cpu_time = CoreTiming::GetTicks();
CoreTiming::ScheduleEvent(GetAIPeriod(), event_type_ai); CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
})); }));
mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead<u32>(&s_interrupt_timing), mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead<u32>(&state.interrupt_timing),
MMIO::ComplexWrite<u32>([](u32, u32 val) { MMIO::ComplexWrite<u32>([](u32, u32 val) {
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val, DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
PowerPC::ppcState.pc); PowerPC::ppcState.pc);
s_interrupt_timing = val; state.interrupt_timing = val;
CoreTiming::RemoveEvent(event_type_ai); CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), event_type_ai); CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
})); }));
} }
@ -356,17 +390,20 @@ void GenerateAISInterrupt()
bool IsPlaying() bool IsPlaying()
{ {
return (s_control.PSTAT == 1); auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
return (state.control.PSTAT == 1);
} }
u32 GetAIDSampleRateDivisor() u32 GetAIDSampleRateDivisor()
{ {
return s_aid_sample_rate_divisor; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
return state.aid_sample_rate_divisor;
} }
u32 GetAISSampleRateDivisor() u32 GetAISSampleRateDivisor()
{ {
return s_ais_sample_rate_divisor; auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
return state.ais_sample_rate_divisor;
} }
u32 Get32KHzSampleRateDivisor() u32 Get32KHzSampleRateDivisor()

View File

@ -5,6 +5,8 @@
#pragma once #pragma once
#include <memory>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
class PointerWrap; class PointerWrap;
@ -15,6 +17,23 @@ class Mapping;
namespace AudioInterface namespace AudioInterface
{ {
class AudioInterfaceState
{
public:
AudioInterfaceState();
AudioInterfaceState(const AudioInterfaceState&) = delete;
AudioInterfaceState(AudioInterfaceState&&) = delete;
AudioInterfaceState& operator=(const AudioInterfaceState&) = delete;
AudioInterfaceState& operator=(AudioInterfaceState&&) = delete;
~AudioInterfaceState();
struct Data;
Data& GetData() { return *m_data; }
private:
std::unique_ptr<Data> m_data;
};
void Init(); void Init();
void Shutdown(); void Shutdown();
void DoState(PointerWrap& p); void DoState(PointerWrap& p);

View File

@ -7,6 +7,7 @@
#include "AudioCommon/SoundStream.h" #include "AudioCommon/SoundStream.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/DVD/DVDThread.h" #include "Core/HW/DVD/DVDThread.h"
@ -18,6 +19,7 @@ struct System::Impl
bool m_sound_stream_running = false; bool m_sound_stream_running = false;
bool m_audio_dump_started = false; bool m_audio_dump_started = false;
AudioInterface::AudioInterfaceState m_audio_interface_state;
DVDInterface::DVDInterfaceState m_dvd_interface_state; DVDInterface::DVDInterfaceState m_dvd_interface_state;
DVDThread::DVDThreadState m_dvd_thread_state; DVDThread::DVDThreadState m_dvd_thread_state;
}; };
@ -64,6 +66,11 @@ void System::SetAudioDumpStarted(bool started)
m_impl->m_audio_dump_started = started; m_impl->m_audio_dump_started = started;
} }
AudioInterface::AudioInterfaceState& System::GetAudioInterfaceState() const
{
return m_impl->m_audio_interface_state;
}
DVDInterface::DVDInterfaceState& System::GetDVDInterfaceState() const DVDInterface::DVDInterfaceState& System::GetDVDInterfaceState() const
{ {
return m_impl->m_dvd_interface_state; return m_impl->m_dvd_interface_state;

View File

@ -7,6 +7,10 @@
class SoundStream; class SoundStream;
namespace AudioInterface
{
class AudioInterfaceState;
};
namespace DVDInterface namespace DVDInterface
{ {
class DVDInterfaceState; class DVDInterfaceState;
@ -49,6 +53,7 @@ public:
bool IsAudioDumpStarted() const; bool IsAudioDumpStarted() const;
void SetAudioDumpStarted(bool started); void SetAudioDumpStarted(bool started);
AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const;
DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const;
DVDThread::DVDThreadState& GetDVDThreadState() const; DVDThread::DVDThreadState& GetDVDThreadState() const;