mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 17:19:44 -06:00
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:
@ -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)
|
||||
|
Reference in New Issue
Block a user