Rewrite handling of DTK (streaming) audio.

The primary motivation here is to make sure we submit samples from the
CPU thread. This makes sure the timing of related interrupts accurate,
and generally keeps the different kinds of audio synchronized.  This will also
allow improvements to audio dumping functionality.

The new code is also more concise because it gets rid of some duplicated
audio mixing code.
This commit is contained in:
magumagu
2014-04-10 18:28:19 -07:00
parent d7736ac714
commit d43ecd0bd1
6 changed files with 146 additions and 249 deletions

View File

@ -56,10 +56,8 @@ This file mainly deals with the [Drive I/F], however [AIDFR] controls
#include "Core/CoreTiming.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/CPU.h"
#include "Core/HW/DVDInterface.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/StreamADPCM.h"
#include "Core/HW/SystemTimers.h"
#include "Core/PowerPC/PowerPC.h"
@ -205,9 +203,6 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
m_Control.PSTAT = tmpAICtrl.PSTAT;
g_LastCPUTime = CoreTiming::GetTicks();
// Tell Drive Interface to start/stop streaming
DVDInterface::g_bStream = tmpAICtrl.PSTAT;
CoreTiming::RemoveEvent(et_AI);
CoreTiming::ScheduleEvent(((int)GetAIPeriod() / 2), et_AI);
}
@ -272,133 +267,6 @@ void GenerateAISInterrupt()
GenerateAudioInterrupt();
}
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate)
{
_AISampleRate = g_AISSampleRate;
_DACSampleRate = g_AIDSampleRate;
}
// Callback for the disc streaming
// WARNING - called from audio thread
unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate)
{
if (m_Control.PSTAT && !CCPU::IsStepping())
{
static int pos = 0;
static short pcm[NGCADPCM::SAMPLES_PER_BLOCK*2];
const int lvolume = m_Volume.left;
const int rvolume = m_Volume.right;
if (g_AISSampleRate == 48000 && _sampleRate == 32000)
{
_dbg_assert_msg_(AUDIO_INTERFACE, !(_numSamples & 1), "Number of Samples: %i must be even!", _numSamples);
_numSamples = _numSamples * 3 / 2;
}
int pcm_l = 0, pcm_r = 0;
for (unsigned int i = 0; i < _numSamples; i++)
{
if (pos == 0)
ReadStreamBlock(pcm);
if (g_AISSampleRate == 48000 && _sampleRate == 32000) //downsample 48>32
{
if (i % 3)
{
pcm_l = (((pcm_l + (int)pcm[pos*2]) / 2 * lvolume) >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_l, -32767, 32767);
*_pDestBuffer++ = pcm_l;
pcm_r = (((pcm_r + (int)pcm[pos*2+1]) / 2 * rvolume) >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_r, -32767, 32767);
*_pDestBuffer++ = pcm_r;
}
pcm_l = pcm[pos*2];
pcm_r = pcm[pos*2+1];
pos++;
}
else if (g_AISSampleRate == 32000 && _sampleRate == 48000) //upsample 32>48
{
//starts with one sample of 0
const u32 ratio = (u32)( 65536.0f * 32000.0f / (float)_sampleRate );
static u32 frac = 0;
static s16 l1 = 0;
static s16 l2 = 0;
if (frac >= 0x10000 || frac == 0)
{
frac &= 0xffff;
l1 = l2; //current
l2 = pcm[pos * 2]; //next
}
pcm_l = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
pcm_r = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
pcm_l = (pcm_l * lvolume >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_l, -32767, 32767);
*_pDestBuffer++ = pcm_l;
pcm_r = (pcm_r * lvolume >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_r, -32767, 32767);
*_pDestBuffer++ = pcm_r;
frac += ratio;
pos += frac >> 16;
}
else //1:1 no resampling
{
pcm_l = (((int)pcm[pos*2] * lvolume) >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_l, -32767, 32767);
*_pDestBuffer++ = pcm_l;
pcm_r = (((int)pcm[pos*2+1] * rvolume) >> 8) + (int)(*_pDestBuffer);
MathUtil::Clamp(&pcm_r, -32767, 32767);
*_pDestBuffer++ = pcm_r;
pos++;
}
if (pos == NGCADPCM::SAMPLES_PER_BLOCK)
pos = 0;
}
}
else
{
// Don't overwrite existed sample data
/*
for (unsigned int i = 0; i < _numSamples * 2; i++)
{
_pDestBuffer[i] = 0; //silence!
}
*/
}
return _numSamples;
}
// WARNING - called from audio thread
void ReadStreamBlock(s16 *_pPCM)
{
u8 tempADPCM[NGCADPCM::ONE_BLOCK_SIZE];
if (DVDInterface::DVDReadADPCM(tempADPCM, NGCADPCM::ONE_BLOCK_SIZE))
{
NGCADPCM::DecodeBlock(_pPCM, tempADPCM);
}
else
{
memset(_pPCM, 0, NGCADPCM::SAMPLES_PER_BLOCK*2);
}
// our whole streaming code is "faked" ... so it shouldn't increase the sample counter
// streaming will never work correctly this way, but at least the program will think all is alright.
}
static void IncreaseSampleCount(const u32 _iAmount)
{
if (m_Control.PSTAT)