Implemented proper timing for the sample counter in the AudioInterface, removing the previous hack.
Cleaned up some of the audio streaming code.
This commit is contained in:
parent
0399959c39
commit
7a04ec6f92
|
@ -145,6 +145,8 @@ static void GenerateAudioInterrupt();
|
|||
static void UpdateInterrupts();
|
||||
static void IncreaseSampleCount(const u32 _uAmount);
|
||||
void ReadStreamBlock(s16* _pPCM);
|
||||
u64 GetAIPeriod();
|
||||
int et_AI;
|
||||
|
||||
void Init()
|
||||
{
|
||||
|
@ -159,6 +161,8 @@ void Init()
|
|||
|
||||
g_AISSampleRate = 48000;
|
||||
g_AIDSampleRate = 32000;
|
||||
|
||||
et_AI = CoreTiming::RegisterEvent("AICallback", Update);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
@ -178,11 +182,8 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
|||
break;
|
||||
|
||||
case AI_SAMPLE_COUNTER:
|
||||
Update(0, 0);
|
||||
_rReturnValue = m_SampleCounter;
|
||||
// HACK - AI SRC init will do while (oldval == sample_counter) {}
|
||||
// in order to pass this, we need to increment the counter whenever read
|
||||
if (m_Control.PSTAT)
|
||||
m_SampleCounter++;
|
||||
break;
|
||||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
|
@ -236,6 +237,9 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
|
||||
// Tell Drive Interface to start/stop streaming
|
||||
DVDInterface::g_bStream = tmpAICtrl.PSTAT;
|
||||
|
||||
CoreTiming::RemoveEvent(et_AI);
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
|
@ -271,6 +275,8 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
m_InterruptTiming = _Value;
|
||||
CoreTiming::RemoveEvent(et_AI);
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
|
||||
DEBUG_LOG(AUDIO_INTERFACE, "Set interrupt: %08x samples", m_InterruptTiming);
|
||||
break;
|
||||
|
||||
|
@ -448,7 +454,7 @@ unsigned int GetAIDSampleRate()
|
|||
return g_AIDSampleRate;
|
||||
}
|
||||
|
||||
void Update()
|
||||
void Update(u64 userdata, int cyclesLate)
|
||||
{
|
||||
if (m_Control.PSTAT)
|
||||
{
|
||||
|
@ -458,8 +464,17 @@ void Update()
|
|||
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
||||
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
||||
IncreaseSampleCount(Samples);
|
||||
}
|
||||
}
|
||||
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2) - cyclesLate, et_AI);
|
||||
}
|
||||
}
|
||||
|
||||
u64 GetAIPeriod()
|
||||
{
|
||||
u64 period = g_CPUCyclesPerSample * m_InterruptTiming;
|
||||
if (period == 0)
|
||||
period = 32000 * g_CPUCyclesPerSample;
|
||||
return period;
|
||||
}
|
||||
|
||||
} // end of namespace AudioInterface
|
||||
|
|
|
@ -31,7 +31,7 @@ void Init();
|
|||
void Shutdown();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void Update();
|
||||
void Update(u64 userdata, int cyclesLate);
|
||||
|
||||
// Called by DSP emulator
|
||||
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../ConfigManager.h"
|
||||
#include "../DSPEmulator.h"
|
||||
#include "SystemTimers.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
|
@ -152,7 +153,7 @@ struct AudioDMA
|
|||
SourceAddress = 0;
|
||||
ReadAddress = 0;
|
||||
AudioDMAControl.Hex = 0;
|
||||
BlocksLeft = 0;
|
||||
BlocksLeft = 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -355,7 +356,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
|||
|
||||
// AI
|
||||
case AUDIO_DMA_BLOCKS_LEFT:
|
||||
_uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based
|
||||
_uReturnValue = g_audioDMA.BlocksLeft;
|
||||
break;
|
||||
|
||||
case AUDIO_DMA_START_LO:
|
||||
|
@ -665,7 +666,7 @@ void UpdateDSPSlice(int cycles) {
|
|||
// This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
|
||||
void UpdateAudioDMA()
|
||||
{
|
||||
if (g_audioDMA.AudioDMAControl.Enable && g_audioDMA.BlocksLeft)
|
||||
if (g_audioDMA.AudioDMAControl.Enable && g_audioDMA.BlocksLeft > -1)
|
||||
{
|
||||
// Read audio at g_audioDMA.ReadAddress in RAM and push onto an
|
||||
// external audio fifo in the emulator, to be mixed with the disc
|
||||
|
@ -675,7 +676,7 @@ void UpdateAudioDMA()
|
|||
g_audioDMA.BlocksLeft--;
|
||||
g_audioDMA.ReadAddress += 32;
|
||||
|
||||
if (g_audioDMA.BlocksLeft == 0)
|
||||
if (g_audioDMA.BlocksLeft == -1)
|
||||
{
|
||||
dsp_emulator->DSP_SendAIBuffer(g_audioDMA.SourceAddress, 8*g_audioDMA.AudioDMAControl.NumBlocks);
|
||||
GenerateDSPInterrupt(DSP::INT_AID);
|
||||
|
@ -687,7 +688,7 @@ void UpdateAudioDMA()
|
|||
{
|
||||
// Send silence. Yeah, it's a bit of a waste to sample rate convert
|
||||
// silence. or hm. Maybe we shouldn't do this :)
|
||||
//dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
|
||||
dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ enum
|
|||
int et_Dec;
|
||||
int et_VI;
|
||||
int et_SI;
|
||||
int et_AI;
|
||||
int et_CP;
|
||||
int et_AudioDMA;
|
||||
int et_DSP;
|
||||
|
@ -120,9 +119,6 @@ int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default
|
|||
// These are badly educated guesses
|
||||
// Feel free to experiment. Set these in Init below.
|
||||
int
|
||||
// This one should simply be determined by the increasing counter in AI.
|
||||
AI_PERIOD,
|
||||
|
||||
// These shouldn't be period controlled either, most likely.
|
||||
DSP_PERIOD,
|
||||
|
||||
|
@ -148,12 +144,6 @@ u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
|
|||
return GetTicksPerSecond() / 1000 * _Milliseconds;
|
||||
}
|
||||
|
||||
void AICallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
AudioInterface::Update();
|
||||
CoreTiming::ScheduleEvent(AI_PERIOD - cyclesLate, et_AI);
|
||||
}
|
||||
|
||||
// DSP/CPU timeslicing.
|
||||
void DSPCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
|
@ -277,9 +267,6 @@ void Init()
|
|||
if (DSP::GetDSPEmulator()->IsLLE())
|
||||
DSP_PERIOD = 12000; // TO BE TWEAKED
|
||||
|
||||
// This is the biggest question mark.
|
||||
AI_PERIOD = GetTicksPerSecond() / 80;
|
||||
|
||||
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
|
||||
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
|
||||
|
||||
|
@ -295,7 +282,6 @@ void Init()
|
|||
CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks());
|
||||
|
||||
et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
|
||||
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
|
||||
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
||||
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
|
||||
|
@ -305,7 +291,6 @@ void Init()
|
|||
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
||||
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
|
||||
|
||||
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
|
||||
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
|
||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
|
||||
|
|
Loading…
Reference in New Issue