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 UpdateInterrupts();
static void IncreaseSampleCount(const u32 _uAmount); static void IncreaseSampleCount(const u32 _uAmount);
void ReadStreamBlock(s16* _pPCM); void ReadStreamBlock(s16* _pPCM);
u64 GetAIPeriod();
int et_AI;
void Init() void Init()
{ {
@ -159,6 +161,8 @@ void Init()
g_AISSampleRate = 48000; g_AISSampleRate = 48000;
g_AIDSampleRate = 32000; g_AIDSampleRate = 32000;
et_AI = CoreTiming::RegisterEvent("AICallback", Update);
} }
void Shutdown() void Shutdown()
@ -178,11 +182,8 @@ void Read32(u32& _rReturnValue, const u32 _Address)
break; break;
case AI_SAMPLE_COUNTER: case AI_SAMPLE_COUNTER:
Update(0, 0);
_rReturnValue = m_SampleCounter; _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; break;
case AI_INTERRUPT_TIMING: case AI_INTERRUPT_TIMING:
@ -236,6 +237,9 @@ void Write32(const u32 _Value, const u32 _Address)
// Tell Drive Interface to start/stop streaming // Tell Drive Interface to start/stop streaming
DVDInterface::g_bStream = tmpAICtrl.PSTAT; DVDInterface::g_bStream = tmpAICtrl.PSTAT;
CoreTiming::RemoveEvent(et_AI);
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
} }
// AI Interrupt // AI Interrupt
@ -271,6 +275,8 @@ void Write32(const u32 _Value, const u32 _Address)
case AI_INTERRUPT_TIMING: case AI_INTERRUPT_TIMING:
m_InterruptTiming = _Value; m_InterruptTiming = _Value;
CoreTiming::RemoveEvent(et_AI);
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
DEBUG_LOG(AUDIO_INTERFACE, "Set interrupt: %08x samples", m_InterruptTiming); DEBUG_LOG(AUDIO_INTERFACE, "Set interrupt: %08x samples", m_InterruptTiming);
break; break;
@ -448,7 +454,7 @@ unsigned int GetAIDSampleRate()
return g_AIDSampleRate; return g_AIDSampleRate;
} }
void Update() void Update(u64 userdata, int cyclesLate)
{ {
if (m_Control.PSTAT) if (m_Control.PSTAT)
{ {
@ -458,8 +464,17 @@ void Update()
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample); const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
g_LastCPUTime += Samples * g_CPUCyclesPerSample; g_LastCPUTime += Samples * g_CPUCyclesPerSample;
IncreaseSampleCount(Samples); 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 } // end of namespace AudioInterface

View File

@ -31,7 +31,7 @@ void Init();
void Shutdown(); void Shutdown();
void DoState(PointerWrap &p); void DoState(PointerWrap &p);
void Update(); void Update(u64 userdata, int cyclesLate);
// Called by DSP emulator // Called by DSP emulator
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate); void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate);

View File

@ -47,6 +47,7 @@
#include "../PowerPC/PowerPC.h" #include "../PowerPC/PowerPC.h"
#include "../ConfigManager.h" #include "../ConfigManager.h"
#include "../DSPEmulator.h" #include "../DSPEmulator.h"
#include "SystemTimers.h"
namespace DSP namespace DSP
{ {
@ -152,7 +153,7 @@ struct AudioDMA
SourceAddress = 0; SourceAddress = 0;
ReadAddress = 0; ReadAddress = 0;
AudioDMAControl.Hex = 0; AudioDMAControl.Hex = 0;
BlocksLeft = 0; BlocksLeft = 1;
} }
}; };
@ -355,7 +356,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// AI // AI
case AUDIO_DMA_BLOCKS_LEFT: 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; break;
case AUDIO_DMA_START_LO: 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) // This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
void UpdateAudioDMA() 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 // Read audio at g_audioDMA.ReadAddress in RAM and push onto an
// external audio fifo in the emulator, to be mixed with the disc // external audio fifo in the emulator, to be mixed with the disc
@ -675,7 +676,7 @@ void UpdateAudioDMA()
g_audioDMA.BlocksLeft--; g_audioDMA.BlocksLeft--;
g_audioDMA.ReadAddress += 32; 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); dsp_emulator->DSP_SendAIBuffer(g_audioDMA.SourceAddress, 8*g_audioDMA.AudioDMAControl.NumBlocks);
GenerateDSPInterrupt(DSP::INT_AID); GenerateDSPInterrupt(DSP::INT_AID);
@ -687,7 +688,7 @@ void UpdateAudioDMA()
{ {
// Send silence. Yeah, it's a bit of a waste to sample rate convert // Send silence. Yeah, it's a bit of a waste to sample rate convert
// silence. or hm. Maybe we shouldn't do this :) // 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_Dec;
int et_VI; int et_VI;
int et_SI; int et_SI;
int et_AI;
int et_CP; int et_CP;
int et_AudioDMA; int et_AudioDMA;
int et_DSP; 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 // These are badly educated guesses
// Feel free to experiment. Set these in Init below. // Feel free to experiment. Set these in Init below.
int int
// This one should simply be determined by the increasing counter in AI.
AI_PERIOD,
// These shouldn't be period controlled either, most likely. // These shouldn't be period controlled either, most likely.
DSP_PERIOD, DSP_PERIOD,
@ -148,12 +144,6 @@ u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
return GetTicksPerSecond() / 1000 * _Milliseconds; return GetTicksPerSecond() / 1000 * _Milliseconds;
} }
void AICallback(u64 userdata, int cyclesLate)
{
AudioInterface::Update();
CoreTiming::ScheduleEvent(AI_PERIOD - cyclesLate, et_AI);
}
// DSP/CPU timeslicing. // DSP/CPU timeslicing.
void DSPCallback(u64 userdata, int cyclesLate) void DSPCallback(u64 userdata, int cyclesLate)
{ {
@ -277,9 +267,6 @@ void Init()
if (DSP::GetDSPEmulator()->IsLLE()) if (DSP::GetDSPEmulator()->IsLLE())
DSP_PERIOD = 12000; // TO BE TWEAKED 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 // System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32); AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
@ -295,7 +282,6 @@ void Init()
CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks());
et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback); et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU)
@ -305,7 +291,6 @@ void Init()
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback); et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP); CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);