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:
skidau 2013-03-01 11:51:11 +11:00
parent 0399959c39
commit 7a04ec6f92
4 changed files with 28 additions and 27 deletions

View File

@ -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

View File

@ -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);

View File

@ -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());
}
}

View File

@ -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);