mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Sound System Rework: Phase 2
. Performance boost (Completely non-blocking between Sound thread and CPU thread, in the meantime keeping them thread safe) . Both 32KHz & 48KHz sound can be handled properly now (But up-sampling is still not implemented, and I don't think any game requires it.) . Strategy adjustment When your PC is *NOT* capable to run the game at 100%: >> DSound Could yield more fluent sound than OpenAL sometimes, but you will lose the sync between video & audio (since audio is played before video to guarantee fluency) >> OpenAL Ensures video & audio are always sync'ed, but sound could be intermittent(to let slow video catch up) . Changed default frame limit to: Auto (Somehow this can dramatically decrease the chance of wiimote desync in game NSMB) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4724 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -19,6 +19,7 @@
|
||||
#define _DSPHANDLER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "AudioCommon.h"
|
||||
#include "MailHandler.h"
|
||||
#include "UCodes/UCodes.h"
|
||||
|
||||
@ -57,34 +58,6 @@ private:
|
||||
CDSPHandler();
|
||||
~CDSPHandler();
|
||||
|
||||
// UDSPControl
|
||||
union UDSPControl
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned DSPReset : 1; // Write 1 to reset and waits for 0
|
||||
unsigned DSPAssertInt : 1;
|
||||
unsigned DSPHalt : 1;
|
||||
|
||||
unsigned AI : 1;
|
||||
unsigned AI_mask : 1;
|
||||
unsigned ARAM : 1;
|
||||
unsigned ARAM_mask : 1;
|
||||
unsigned DSP : 1;
|
||||
unsigned DSP_mask : 1;
|
||||
|
||||
unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag
|
||||
unsigned DSPInitCode : 1;
|
||||
unsigned DSPInit : 1; // DSPInit() writes to this flag
|
||||
unsigned pad : 4;
|
||||
};
|
||||
|
||||
UDSPControl(u16 _Hex = 0)
|
||||
: Hex(_Hex)
|
||||
{}
|
||||
};
|
||||
|
||||
// singleton instance
|
||||
static CDSPHandler* m_pInstance;
|
||||
|
||||
|
@ -20,23 +20,14 @@
|
||||
#include "DSPHandler.h"
|
||||
#include "HLEMixer.h"
|
||||
|
||||
void HLEMixer::MixUCode(short *samples, int numSamples) {
|
||||
// if this was called directly from the HLE, and not by timeout
|
||||
if (g_Config.m_EnableHLEAudio && IsHLEReady()) {
|
||||
void HLEMixer::Premix(short *samples, unsigned int numSamples, unsigned int sampleRate)
|
||||
{
|
||||
// if this was called directly from the HLE
|
||||
if (g_Config.m_EnableHLEAudio && IsHLEReady())
|
||||
{
|
||||
IUCode *pUCode = CDSPHandler::GetInstance().GetUCode();
|
||||
if (pUCode && samples)
|
||||
pUCode->MixAdd(samples, numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
void HLEMixer::Premix(short *samples, int numSamples) {
|
||||
|
||||
// first get the DTK Music
|
||||
// if (g_Config.m_EnableDTKMusic) {
|
||||
// g_dspInitialize.pGetAudioStreaming(samples, numSamples);
|
||||
// }
|
||||
|
||||
MixUCode(samples, numSamples);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
class HLEMixer : public CMixer
|
||||
{
|
||||
public:
|
||||
void MixUCode(short *samples, int numSamples);
|
||||
HLEMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000)
|
||||
: CMixer(AISampleRate, DSPSampleRate) {};
|
||||
|
||||
virtual void Premix(short *samples, int numSamples);
|
||||
virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate);
|
||||
};
|
||||
|
||||
#endif // HLEMIXER_H
|
||||
|
@ -498,7 +498,7 @@ bool CUCode_AX::AXTask(u32& _uMail)
|
||||
SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs);
|
||||
|
||||
SaveLog("Update the SoundThread to be in sync");
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
// soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -156,7 +156,7 @@ struct AXParamBlock
|
||||
/* 63 */ PBADPCMInfo adpcm;
|
||||
/* 83 */ PBSampleRateConverter src;
|
||||
/* 90 */ PBADPCMLoopInfo adpcm_loop_info;
|
||||
/* 93 */ u16 unknown_maybe_padding[3];
|
||||
/* 93 */ //u16 unknown_maybe_padding[3]; // Comment this out to get some speedup
|
||||
};
|
||||
|
||||
struct PBLpf
|
||||
@ -201,7 +201,7 @@ struct AXParamBlockWii
|
||||
/* 95 */ PBADPCMLoopInfo adpcm_loop_info;
|
||||
/* 98 */ PBLpf lpf;
|
||||
/* 102 */ PBHpf hpf;
|
||||
/* 106 */ u16 pad[22];
|
||||
/* 106 */ //u16 pad[22]; // Comment this out to get some speedup
|
||||
};
|
||||
|
||||
struct AXParamBlockWii_ // new CRC version
|
||||
@ -226,7 +226,7 @@ struct AXParamBlockWii_ // new CRC version
|
||||
/* 0x0B4 */ PBADPCMLoopInfo adpcm_loop_info;
|
||||
/* 0x0BA */ PBLpf lpf;
|
||||
/* 0x0C2 */ PBHpf hpf;
|
||||
/* 0x0CA */ u16 pad[27];
|
||||
/* 0x0CA */ //u16 pad[27]; // Comment this out to get some speedup
|
||||
/* 0x100 */
|
||||
};
|
||||
|
||||
|
@ -289,7 +289,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
m_addressPBs = Memory_Read_U32(uAddress);
|
||||
lCUCode_AX->m_addressPBs = m_addressPBs; // for the sake of logging
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
soundStream->Update();
|
||||
// soundStream->Update();
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
|
@ -147,7 +147,7 @@ void CUCode_Zelda::HandleMail_LightVersion(u32 _uMail)
|
||||
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync");
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
// soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
m_bSyncCmdPending = false;
|
||||
}
|
||||
@ -216,7 +216,7 @@ void CUCode_Zelda::HandleMail_SMSVersion(u32 _uMail)
|
||||
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync");
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
// soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
m_bSyncCmdPending = false;
|
||||
}
|
||||
@ -339,7 +339,7 @@ void CUCode_Zelda::HandleMail_NormalVersion(u32 _uMail)
|
||||
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync");
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
// soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
m_bSyncCmdPending = false;
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ DSPDebuggerHLE* m_DebuggerFrame = NULL;
|
||||
#include "Config.h"
|
||||
#include "Setup.h"
|
||||
#include "StringUtil.h"
|
||||
#include "AudioCommon.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
|
||||
@ -42,8 +41,8 @@ PLUGIN_GLOBALS* globals = NULL;
|
||||
DSPInitialize g_dspInitialize;
|
||||
u8* g_pMemory;
|
||||
extern std::vector<std::string> sMailLog, sMailTime;
|
||||
bool g_bMuted = false;
|
||||
|
||||
bool g_InitMixer = false;
|
||||
SoundStream *soundStream = NULL;
|
||||
|
||||
// Mailbox utility
|
||||
@ -203,6 +202,7 @@ void DllConfig(HWND _hParent)
|
||||
|
||||
void Initialize(void *init)
|
||||
{
|
||||
g_InitMixer = false;
|
||||
g_dspInitialize = *(DSPInitialize*)init;
|
||||
|
||||
g_Config.Load();
|
||||
@ -211,10 +211,6 @@ void Initialize(void *init)
|
||||
g_dspState.Reset();
|
||||
|
||||
CDSPHandler::CreateInstance();
|
||||
|
||||
soundStream = AudioCommon::InitSoundStream(new HLEMixer());
|
||||
if(!soundStream)
|
||||
PanicAlert("Error starting up sound stream");
|
||||
}
|
||||
|
||||
void DSP_StopSoundStream()
|
||||
@ -245,6 +241,7 @@ void Shutdown()
|
||||
void DoState(unsigned char **ptr, int mode)
|
||||
{
|
||||
PointerWrap p(ptr, mode);
|
||||
p.Do(g_InitMixer);
|
||||
CDSPHandler::GetInstance().GetUCode()->DoState(p);
|
||||
}
|
||||
|
||||
@ -305,6 +302,19 @@ void DSP_WriteMailboxLow(bool _CPUMailbox, unsigned short _Value)
|
||||
// Other DSP fuctions
|
||||
unsigned short DSP_WriteControlRegister(unsigned short _Value)
|
||||
{
|
||||
UDSPControl Temp(_Value);
|
||||
if (!g_InitMixer)
|
||||
{
|
||||
if (!Temp.DSPHalt && Temp.DSPInit)
|
||||
{
|
||||
unsigned int AISampleRate, DSPSampleRate;
|
||||
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate);
|
||||
soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DSPSampleRate));
|
||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||
// Mixer is initialized
|
||||
g_InitMixer = true;
|
||||
}
|
||||
}
|
||||
return CDSPHandler::GetInstance().WriteControlRegister(_Value);
|
||||
}
|
||||
|
||||
@ -324,44 +334,26 @@ void DSP_Update(int cycles)
|
||||
inside Mixer_PushSamples(), the reason that we don't disable this entire
|
||||
function when Other Audio is disabled is that then we can't turn it back on
|
||||
again once the game has started. */
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
|
||||
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate)
|
||||
{
|
||||
// TODO: This is not yet fully threadsafe.
|
||||
if (!soundStream) {
|
||||
if (!soundStream)
|
||||
return;
|
||||
}
|
||||
|
||||
CMixer* pMixer = soundStream->GetMixer();
|
||||
|
||||
if (pMixer && address)
|
||||
{
|
||||
short* samples = (short*)Memory_Get_Pointer(address);
|
||||
/*
|
||||
short samples[16] = {0}; // interleaved stereo
|
||||
if (address)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
samples[i] = Memory_Read_U16(address + i * 2);
|
||||
}
|
||||
|
||||
// FIXME: Write the audio to a file
|
||||
//if (log_ai)
|
||||
// g_wave_writer.AddStereoSamples(samples, 8);
|
||||
}
|
||||
*/
|
||||
// sample_rate is usually 32k here,
|
||||
// sample_rate could be 32khz/48khz here,
|
||||
// see Core/DSP/DSP.cpp for better information
|
||||
pMixer->PushSamples(samples, 32 / 4, sample_rate);
|
||||
pMixer->PushSamples(samples, num_samples, sample_rate);
|
||||
|
||||
// FIXME: Write the audio to a file
|
||||
//if (log_ai)
|
||||
// g_wave_writer.AddStereoSamples(samples, 8);
|
||||
}
|
||||
|
||||
// SoundStream is updated only when necessary (there is no 70 ms limit
|
||||
// so each sample now triggers the sound stream)
|
||||
|
||||
// TODO: think about this.
|
||||
static int counter = 0;
|
||||
counter++;
|
||||
if ((counter & 31) == 0 && soundStream)
|
||||
soundStream->Update();
|
||||
soundStream->Update();
|
||||
}
|
||||
|
||||
void DSP_ClearAudioBuffer()
|
||||
|
@ -40,6 +40,11 @@ u32 Memory_Read_U32(u32 _uAddress)
|
||||
return Common::swap32(*(u32*)&g_dsp.cpu_ram[_uAddress & RAM_MASK]);
|
||||
}
|
||||
|
||||
void* Memory_Get_Pointer(u32 _uAddress)
|
||||
{
|
||||
return &g_dsp.cpu_ram[_uAddress & RAM_MASK];
|
||||
}
|
||||
|
||||
#if PROFILE
|
||||
|
||||
#define PROFILE_MAP_SIZE 0x10000
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
u16 Memory_Read_U16(u32 _uAddress); // For PB address detection
|
||||
u32 Memory_Read_U32(u32 _uAddress);
|
||||
void* Memory_Get_Pointer(u32 _uAddress);
|
||||
|
||||
#if PROFILE
|
||||
void ProfilerDump(u64 _count);
|
||||
|
@ -47,6 +47,7 @@ PLUGIN_GLOBALS* globals = NULL;
|
||||
DSPInitialize g_dspInitialize;
|
||||
Common::Thread *g_hDSPThread = NULL;
|
||||
SoundStream *soundStream = NULL;
|
||||
bool g_InitMixer = false;
|
||||
|
||||
bool bIsRunning = false;
|
||||
|
||||
@ -166,6 +167,7 @@ void DllConfig(HWND _hParent)
|
||||
void DoState(unsigned char **ptr, int mode)
|
||||
{
|
||||
PointerWrap p(ptr, mode);
|
||||
p.Do(g_InitMixer);
|
||||
}
|
||||
|
||||
void DllDebugger(HWND _hParent, bool Show)
|
||||
@ -202,6 +204,7 @@ void DSP_DebugBreak()
|
||||
|
||||
void Initialize(void *init)
|
||||
{
|
||||
g_InitMixer = false;
|
||||
bool bCanWork = true;
|
||||
g_dspInitialize = *(DSPInitialize*)init;
|
||||
|
||||
@ -229,7 +232,6 @@ void Initialize(void *init)
|
||||
{
|
||||
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
|
||||
}
|
||||
soundStream = AudioCommon::InitSoundStream();
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
if (m_DebuggerFrame)
|
||||
@ -256,6 +258,19 @@ void Shutdown()
|
||||
|
||||
u16 DSP_WriteControlRegister(u16 _uFlag)
|
||||
{
|
||||
UDSPControl Temp(_uFlag);
|
||||
if (!g_InitMixer)
|
||||
{
|
||||
if (!Temp.DSPHalt && Temp.DSPInit)
|
||||
{
|
||||
unsigned int AISampleRate, DSPSampleRate;
|
||||
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate);
|
||||
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DSPSampleRate));
|
||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||
// Mixer is initialized
|
||||
g_InitMixer = true;
|
||||
}
|
||||
}
|
||||
DSPInterpreter::WriteCR(_uFlag);
|
||||
return DSPInterpreter::ReadCR();
|
||||
}
|
||||
@ -343,29 +358,21 @@ void DSP_Update(int cycles)
|
||||
}
|
||||
}
|
||||
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
|
||||
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate)
|
||||
{
|
||||
if (soundStream->GetMixer())
|
||||
if (!soundStream)
|
||||
return;
|
||||
|
||||
CMixer* pMixer = soundStream->GetMixer();
|
||||
|
||||
if (pMixer && address)
|
||||
{
|
||||
short samples[16] = {0}; // interleaved stereo
|
||||
if (address)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
samples[i] = Memory_Read_U16(address + i * 2);
|
||||
}
|
||||
}
|
||||
soundStream->GetMixer()->PushSamples(samples, 32 / 4, sample_rate);
|
||||
short* samples = (short*)Memory_Get_Pointer(address);
|
||||
|
||||
pMixer->PushSamples(samples, num_samples, sample_rate);
|
||||
}
|
||||
|
||||
// SoundStream is updated only when necessary (there is no 70 ms limit
|
||||
// so each sample now triggers the sound stream)
|
||||
|
||||
// TODO: think about this.
|
||||
// static int counter = 0;
|
||||
// counter++;
|
||||
if (/*(counter & 31) == 0 &&*/ soundStream)
|
||||
soundStream->Update();
|
||||
soundStream->Update();
|
||||
}
|
||||
|
||||
void DSP_ClearAudioBuffer()
|
||||
|
Reference in New Issue
Block a user