Sound System Rework: Phase 2 (cont'ed)
. Fixed super fast refresh rate issue . Recovered <TAB> shortcut key for ThrottleSkipping . Removed redundant "soundstream->Update()" in DSPLLE (Thanks to LordMark) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4728 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
eddafd450e
commit
06218e9ebb
|
@ -111,7 +111,7 @@ void DSound::SoundLoop()
|
||||||
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
|
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
|
||||||
if (numBytesToRender >= 256)
|
if (numBytesToRender >= 256)
|
||||||
{
|
{
|
||||||
if (numBytesToRender > sizeof(realtimeBuffer) * sizeof(short))
|
if (numBytesToRender > sizeof(realtimeBuffer))
|
||||||
PanicAlert("soundThread: too big render call");
|
PanicAlert("soundThread: too big render call");
|
||||||
m_mixer->Mix(realtimeBuffer, numBytesToRender / 4);
|
m_mixer->Mix(realtimeBuffer, numBytesToRender / 4);
|
||||||
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
|
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
|
|
||||||
#include "Atomic.h"
|
#include "Atomic.h"
|
||||||
|
|
||||||
#include "Mixer.h"
|
#include "Mixer.h"
|
||||||
#include "AudioCommon.h"
|
#include "AudioCommon.h"
|
||||||
|
|
||||||
|
@ -41,37 +40,13 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||||
numLeft = (numLeft > numSamples) ? numSamples : numLeft;
|
numLeft = (numLeft > numSamples) ? numSamples : numLeft;
|
||||||
|
|
||||||
// Do re-sampling if needed
|
// Do re-sampling if needed
|
||||||
if (m_sampleRate == m_dspSampleRate)
|
if (m_sampleRate == 32000)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < numLeft * 2; i++)
|
for (unsigned int i = 0; i < numLeft * 2; i++)
|
||||||
samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]);
|
samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]);
|
||||||
m_indexR += numLeft * 2;
|
m_indexR += numLeft * 2;
|
||||||
}
|
}
|
||||||
else if (m_sampleRate < m_dspSampleRate) // If down-sampling needed
|
else
|
||||||
{
|
|
||||||
_dbg_assert_msg_(DSPHLE, !(numSamples % 2), "Number of Samples: %i must be even!", numSamples);
|
|
||||||
|
|
||||||
short *pDest = samples;
|
|
||||||
int last_l, last_r, cur_l, cur_r;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < numLeft * 3 / 2; i++)
|
|
||||||
{
|
|
||||||
cur_l = Common::swap16(m_buffer[(m_indexR + i * 2) & INDEX_MASK]);
|
|
||||||
cur_r = Common::swap16(m_buffer[(m_indexR + i * 2 + 1) & INDEX_MASK]);
|
|
||||||
|
|
||||||
if (i % 3)
|
|
||||||
{
|
|
||||||
*pDest++ = (last_l + cur_r) / 2;
|
|
||||||
*pDest++ = (last_r + cur_r) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_l = cur_l;
|
|
||||||
last_r = cur_r;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_indexR += numLeft * 2 * 3 / 2;
|
|
||||||
}
|
|
||||||
else if (m_sampleRate > m_dspSampleRate)
|
|
||||||
{
|
{
|
||||||
// AyuanX: Up-sampling is not implemented yet
|
// AyuanX: Up-sampling is not implemented yet
|
||||||
PanicAlert("Mixer: Up-sampling is not implemented yet!");
|
PanicAlert("Mixer: Up-sampling is not implemented yet!");
|
||||||
|
@ -143,16 +118,8 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||||
if (numSamples > numLeft)
|
if (numSamples > numLeft)
|
||||||
memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4);
|
memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4);
|
||||||
|
|
||||||
// Add the HLE sound
|
// Add the DSPHLE sound, re-sampling is done inside
|
||||||
if (m_sampleRate < m_dspSampleRate)
|
Premix(samples, numSamples);
|
||||||
{
|
|
||||||
PanicAlert("Mixer: DSPHLE down-sampling is not implemented yet!\n"
|
|
||||||
"Usually no game should require this, please report!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Premix(samples, numSamples, m_sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the DTK Music
|
// Add the DTK Music
|
||||||
if (m_EnableDTKMusic)
|
if (m_EnableDTKMusic)
|
||||||
|
@ -161,19 +128,17 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||||
g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate);
|
g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::AtomicAdd(m_numSamples, -(int)numLeft);
|
Common::AtomicAdd(m_numSamples, -(s32)numLeft);
|
||||||
|
|
||||||
return numSamples;
|
return numSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int sample_rate)
|
void CMixer::PushSamples(short *samples, unsigned int num_samples)
|
||||||
{
|
{
|
||||||
// The auto throttle function. This loop will put a ceiling on the CPU MHz.
|
// The auto throttle function. This loop will put a ceiling on the CPU MHz.
|
||||||
if (m_throttle)
|
if (m_throttle)
|
||||||
{
|
{
|
||||||
// AyuanX: Remember to reserve "num_samples * 1.5" free sample space at least!
|
|
||||||
// Becuse we may do re-sampling later
|
|
||||||
while (Common::AtomicLoad(m_numSamples) >= MAX_SAMPLES - RESERVED_SAMPLES)
|
while (Common::AtomicLoad(m_numSamples) >= MAX_SAMPLES - RESERVED_SAMPLES)
|
||||||
{
|
{
|
||||||
if (g_dspInitialize.pEmulatorState)
|
if (g_dspInitialize.pEmulatorState)
|
||||||
|
@ -181,8 +146,12 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
|
||||||
if (*g_dspInitialize.pEmulatorState != 0)
|
if (*g_dspInitialize.pEmulatorState != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
soundStream->Update();
|
// Shortcut key for Throttle Skipping
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (GetAsyncKeyState(VK_TAB)) break;;
|
||||||
|
#endif
|
||||||
SLEEP(1);
|
SLEEP(1);
|
||||||
|
soundStream->Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +160,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// AyuanX: Actual re-sampling work has been moved to sound thread
|
// AyuanX: Actual re-sampling work has been moved to sound thread
|
||||||
// to alleviates the workload on main thread
|
// to alleviate the workload on main thread
|
||||||
// and we simply store raw data here to make fast mem copy
|
// and we simply store raw data here to make fast mem copy
|
||||||
int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (m_indexW & INDEX_MASK)) * sizeof(short);
|
int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (m_indexW & INDEX_MASK)) * sizeof(short);
|
||||||
if (over_bytes > 0)
|
if (over_bytes > 0)
|
||||||
|
@ -206,12 +175,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
|
||||||
|
|
||||||
m_indexW += num_samples * 2;
|
m_indexW += num_samples * 2;
|
||||||
|
|
||||||
if (m_sampleRate < m_dspSampleRate)
|
if (m_sampleRate != 32000)
|
||||||
{
|
|
||||||
// This is kind of tricky :P
|
|
||||||
num_samples = num_samples * 2 / 3;
|
|
||||||
}
|
|
||||||
else if (m_sampleRate > m_dspSampleRate)
|
|
||||||
{
|
{
|
||||||
PanicAlert("Mixer: Up-sampling is not implemented yet!");
|
PanicAlert("Mixer: Up-sampling is not implemented yet!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,16 @@
|
||||||
#define _MIXER_H_
|
#define _MIXER_H_
|
||||||
|
|
||||||
// 16 bit Stereo
|
// 16 bit Stereo
|
||||||
#define MAX_SAMPLES (1024 * 4)
|
#define MAX_SAMPLES (1024 * 8)
|
||||||
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
|
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
|
||||||
#define RESERVED_SAMPLES (MAX_SAMPLES / 8)
|
#define RESERVED_SAMPLES (256)
|
||||||
|
|
||||||
class CMixer {
|
class CMixer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000)
|
CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000)
|
||||||
: m_aiSampleRate(AISampleRate)
|
: m_aiSampleRate(AISampleRate)
|
||||||
, m_dspSampleRate(DSPSampleRate)
|
, m_dacSampleRate(DACSampleRate)
|
||||||
, m_bits(16)
|
, m_bits(16)
|
||||||
, m_channels(2)
|
, m_channels(2)
|
||||||
, m_HLEready(false)
|
, m_HLEready(false)
|
||||||
|
@ -36,19 +36,21 @@ public:
|
||||||
, m_indexW(0)
|
, m_indexW(0)
|
||||||
, m_indexR(0)
|
, m_indexR(0)
|
||||||
{
|
{
|
||||||
// AyuanX: When sample rate differs, we have to do re-sampling
|
// AyuanX: The internal (Core & DSP) sample rate is fixed at 32KHz
|
||||||
|
// So when AI/DAC sample rate differs than 32KHz, we have to do re-sampling
|
||||||
// I perfer speed so let's do down-sampling instead of up-sampling
|
// I perfer speed so let's do down-sampling instead of up-sampling
|
||||||
// If you like better sound than speed, feel free to implement the up-sampling code
|
// If you like better sound than speed, feel free to implement the up-sampling code
|
||||||
m_sampleRate = (m_aiSampleRate < m_dspSampleRate) ? m_aiSampleRate : m_dspSampleRate;
|
m_sampleRate = 32000;
|
||||||
|
NOTICE_LOG(AUDIO_INTERFACE, "Mixer is initialized (AISampleRate:%i, DACSampleRate:%i)", AISampleRate, DACSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from audio threads
|
// Called from audio threads
|
||||||
virtual unsigned int Mix(short* samples, unsigned int numSamples);
|
virtual unsigned int Mix(short* samples, unsigned int numSamples);
|
||||||
virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate) {}
|
virtual void Premix(short *samples, unsigned int numSamples) {}
|
||||||
unsigned int GetNumSamples();
|
unsigned int GetNumSamples();
|
||||||
|
|
||||||
// Called from main thread
|
// Called from main thread
|
||||||
virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate);
|
virtual void PushSamples(short* samples, unsigned int num_samples);
|
||||||
unsigned int GetSampleRate() {return m_sampleRate;}
|
unsigned int GetSampleRate() {return m_sampleRate;}
|
||||||
|
|
||||||
void SetThrottle(bool use) { m_throttle = use;}
|
void SetThrottle(bool use) { m_throttle = use;}
|
||||||
|
@ -62,7 +64,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
unsigned int m_sampleRate;
|
unsigned int m_sampleRate;
|
||||||
unsigned int m_aiSampleRate;
|
unsigned int m_aiSampleRate;
|
||||||
unsigned int m_dspSampleRate;
|
unsigned int m_dacSampleRate;
|
||||||
int m_bits;
|
int m_bits;
|
||||||
int m_channels;
|
int m_channels;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class NullMixer : public CMixer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual unsigned int Mix(short *samples, unsigned int numSamples) { return 0; }
|
virtual unsigned int Mix(short *samples, unsigned int numSamples) { return 0; }
|
||||||
virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate) {}
|
virtual void PushSamples(short* samples, unsigned int num_samples) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class NullSound : public SoundStream
|
class NullSound : public SoundStream
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
#endif // WIN32
|
#endif // WIN32
|
||||||
// 16 bit Stereo
|
// 16 bit Stereo
|
||||||
#define SFX_MAX_SOURCE 1
|
#define SFX_MAX_SOURCE 1
|
||||||
#define OAL_NUM_BUFFERS 8
|
#define OAL_NUM_BUFFERS 16
|
||||||
#define OAL_MAX_SAMPLES 512 // AyuanX: Don't make it too large, as larger buffer means longer delay
|
#define OAL_MAX_SAMPLES 512 // AyuanX: Don't make it too large, as larger buffer means longer delay
|
||||||
#define OAL_THRESHOLD 128
|
#define OAL_THRESHOLD 128 // Some games are quite sensitive to delay
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class OpenALStream: public SoundStream
|
class OpenALStream: public SoundStream
|
||||||
|
|
|
@ -27,7 +27,7 @@ typedef void (__cdecl* TDSP_WriteMailBox)(bool _CPUMailbox, unsigned short);
|
||||||
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(bool _CPUMailbox);
|
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(bool _CPUMailbox);
|
||||||
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
|
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
|
||||||
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
|
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
|
||||||
typedef void (__cdecl *TDSP_SendAIBuffer)(unsigned int address, unsigned int num_samples, unsigned int sample_rate);
|
typedef void (__cdecl *TDSP_SendAIBuffer)(unsigned int address, unsigned int num_samples);
|
||||||
typedef void (__cdecl *TDSP_Update)(int cycles);
|
typedef void (__cdecl *TDSP_Update)(int cycles);
|
||||||
typedef void (__cdecl *TDSP_StopSoundStream)();
|
typedef void (__cdecl *TDSP_StopSoundStream)();
|
||||||
typedef void (__cdecl *TDSP_ClearAudioBuffer)();
|
typedef void (__cdecl *TDSP_ClearAudioBuffer)();
|
||||||
|
|
|
@ -700,7 +700,7 @@ void Callback_VideoCopiedToXFB(bool video_update)
|
||||||
|
|
||||||
while (Timer.GetTimeDifference() < wait_frametime * frames)
|
while (Timer.GetTimeDifference() < wait_frametime * frames)
|
||||||
{
|
{
|
||||||
if (no_framelimit==0)
|
if (no_framelimit == 0)
|
||||||
Common::SleepCurrentThread(1);
|
Common::SleepCurrentThread(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,13 +54,13 @@ union AICR
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned PSTAT : 1; // sample counter/playback enable
|
unsigned PSTAT : 1; // sample counter/playback enable
|
||||||
unsigned AFR : 1; // AI Frequency (0=32khz 1=48khz)
|
unsigned AIFR : 1; // AI Frequency (0=32khz 1=48khz)
|
||||||
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
||||||
unsigned AIINT : 1; // audio interrupt status
|
unsigned AIINT : 1; // audio interrupt status
|
||||||
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
||||||
// matching AISLRCNT. Once set, AIINT will hold
|
// matching AISLRCNT. Once set, AIINT will hold
|
||||||
unsigned SCRESET : 1; // write to reset counter
|
unsigned SCRESET : 1; // write to reset counter
|
||||||
unsigned DSPFR : 1; // DSP Frequency (0=48khz 1=32khz)
|
unsigned DACFR : 1; // DAC Frequency (0=48khz 1=32khz)
|
||||||
unsigned :25;
|
unsigned :25;
|
||||||
};
|
};
|
||||||
u32 hex;
|
u32 hex;
|
||||||
|
@ -90,16 +90,16 @@ struct SAudioRegister
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static SAudioRegister g_AudioRegister;
|
static SAudioRegister g_AudioRegister;
|
||||||
static u64 g_LastCPUTime = 0;
|
static u64 g_LastCPUTime = 0;
|
||||||
static unsigned int g_SampleRate = 32000;
|
static unsigned int g_AISampleRate = 32000;
|
||||||
static unsigned int g_DSPSampleRate = 32000;
|
static unsigned int g_DACSampleRate = 32000;
|
||||||
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(g_AudioRegister);
|
p.Do(g_AudioRegister);
|
||||||
p.Do(g_LastCPUTime);
|
p.Do(g_LastCPUTime);
|
||||||
p.Do(g_SampleRate);
|
p.Do(g_AISampleRate);
|
||||||
p.Do(g_DSPSampleRate);
|
p.Do(g_DACSampleRate);
|
||||||
p.Do(g_CPUCyclesPerSample);
|
p.Do(g_CPUCyclesPerSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ void ReadStreamBlock(short* _pPCM);
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
g_AudioRegister.m_SampleCounter = 0;
|
g_AudioRegister.m_SampleCounter = 0;
|
||||||
g_AudioRegister.m_Control.AFR = 1;
|
g_AudioRegister.m_Control.AIFR = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
|
@ -169,22 +169,22 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||||
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
|
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
|
||||||
|
|
||||||
// Set frequency
|
// Set frequency
|
||||||
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
|
if (tmpAICtrl.AIFR != g_AudioRegister.m_Control.AIFR)
|
||||||
{
|
{
|
||||||
INFO_LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
|
INFO_LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AIFR ? "48khz":"32khz");
|
||||||
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
|
g_AudioRegister.m_Control.AIFR = tmpAICtrl.AIFR;
|
||||||
}
|
}
|
||||||
// Set DSP frequency
|
// Set DSP frequency
|
||||||
if (tmpAICtrl.DSPFR != g_AudioRegister.m_Control.DSPFR)
|
if (tmpAICtrl.DACFR != g_AudioRegister.m_Control.DACFR)
|
||||||
{
|
{
|
||||||
INFO_LOG(AUDIO_INTERFACE, "AI_CONTROL_REGISTER: Change DSPFR Freq to %s", tmpAICtrl.DSPFR ? "48khz":"32khz");
|
INFO_LOG(AUDIO_INTERFACE, "AI_CONTROL_REGISTER: Change DSPFR Freq to %s", tmpAICtrl.DACFR ? "48khz":"32khz");
|
||||||
g_AudioRegister.m_Control.DSPFR = tmpAICtrl.DSPFR;
|
g_AudioRegister.m_Control.DACFR = tmpAICtrl.DACFR;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_SampleRate = tmpAICtrl.AFR ? 48000 : 32000;
|
g_AISampleRate = tmpAICtrl.AIFR ? 48000 : 32000;
|
||||||
g_DSPSampleRate = tmpAICtrl.DSPFR ? 32000 : 48000;
|
g_DACSampleRate = tmpAICtrl.DACFR ? 32000 : 48000;
|
||||||
|
|
||||||
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
|
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_AISampleRate;
|
||||||
|
|
||||||
// Streaming counter
|
// Streaming counter
|
||||||
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
|
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
|
||||||
|
@ -264,10 +264,10 @@ void GenerateAudioInterrupt()
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate)
|
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate)
|
||||||
{
|
{
|
||||||
_AISampleRate = g_SampleRate;
|
_AISampleRate = g_AISampleRate;
|
||||||
_DSPSampleRate = g_DSPSampleRate;
|
_DACSampleRate = g_DACSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback for the disc streaming
|
// Callback for the disc streaming
|
||||||
|
@ -282,12 +282,12 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
|
||||||
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
|
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
|
||||||
|
|
||||||
|
|
||||||
if (g_SampleRate == 48000 && _sampleRate == 32000)
|
if (g_AISampleRate == 48000 && _sampleRate == 32000)
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(AUDIO_INTERFACE, !(_numSamples % 2), "Number of Samples: %i must be even!", _numSamples);
|
_dbg_assert_msg_(AUDIO_INTERFACE, !(_numSamples % 2), "Number of Samples: %i must be even!", _numSamples);
|
||||||
_numSamples = _numSamples * 3 / 2;
|
_numSamples = _numSamples * 3 / 2;
|
||||||
}
|
}
|
||||||
else if (g_SampleRate == 32000 && _sampleRate == 48000)
|
else if (g_AISampleRate == 32000 && _sampleRate == 48000)
|
||||||
{
|
{
|
||||||
// AyuanX: Up-sampling is not implemented yet
|
// AyuanX: Up-sampling is not implemented yet
|
||||||
PanicAlert("AUDIO_INTERFACE: Up-sampling is not implemented yet!");
|
PanicAlert("AUDIO_INTERFACE: Up-sampling is not implemented yet!");
|
||||||
|
@ -299,7 +299,7 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
|
||||||
if (pos == 0)
|
if (pos == 0)
|
||||||
ReadStreamBlock(pcm);
|
ReadStreamBlock(pcm);
|
||||||
|
|
||||||
if (g_SampleRate == 48000 && _sampleRate == 32000)
|
if (g_AISampleRate == 48000 && _sampleRate == 32000)
|
||||||
{
|
{
|
||||||
if (i % 3)
|
if (i % 3)
|
||||||
{
|
{
|
||||||
|
@ -393,16 +393,6 @@ void IncreaseSampleCount(const u32 _iAmount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int GetAISampleRate()
|
|
||||||
{
|
|
||||||
return g_SampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int GetDSPSampleRate()
|
|
||||||
{
|
|
||||||
return g_DSPSampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
// update timer
|
// update timer
|
||||||
|
|
|
@ -34,16 +34,12 @@ void DoState(PointerWrap &p);
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
// Called by DSP plugin
|
// Called by DSP plugin
|
||||||
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate);
|
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate);
|
||||||
unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate = 48000);
|
unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate = 48000);
|
||||||
|
|
||||||
void Read32(u32& _uReturnValue, const u32 _iAddress);
|
void Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||||
void Write32(const u32 _iValue, const u32 _iAddress);
|
void Write32(const u32 _iValue, const u32 _iAddress);
|
||||||
|
|
||||||
// Get the audio rates (48000 or 32000 only)
|
|
||||||
unsigned int GetAISampleRate();
|
|
||||||
unsigned int GetDSPSampleRate();
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -484,17 +484,17 @@ void UpdateAudioDMA()
|
||||||
|
|
||||||
// AyuanX: let's do it in a bundle to speed up
|
// AyuanX: let's do it in a bundle to speed up
|
||||||
if (g_audioDMA.BlocksLeft == g_audioDMA.AudioDMAControl.NumBlocks)
|
if (g_audioDMA.BlocksLeft == g_audioDMA.AudioDMAControl.NumBlocks)
|
||||||
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8, AudioInterface::GetDSPSampleRate());
|
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8);
|
||||||
|
|
||||||
// g_audioDMA.ReadAddress += 32;
|
// g_audioDMA.ReadAddress += 32;
|
||||||
g_audioDMA.BlocksLeft--;
|
g_audioDMA.BlocksLeft--;
|
||||||
|
|
||||||
if (g_audioDMA.BlocksLeft == 0)
|
if (g_audioDMA.BlocksLeft == 0)
|
||||||
{
|
{
|
||||||
|
GenerateDSPInterrupt(DSP::INT_AID);
|
||||||
// g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
|
// g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
|
||||||
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
|
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
|
||||||
// DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
|
// DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
|
||||||
GenerateDSPInterrupt(DSP::INT_AID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -112,7 +112,7 @@ int et_Dec;
|
||||||
int et_VI;
|
int et_VI;
|
||||||
int et_SI;
|
int et_SI;
|
||||||
int et_AI;
|
int et_AI;
|
||||||
int et_AudioFifo;
|
int et_AudioDMA;
|
||||||
int et_DSP;
|
int et_DSP;
|
||||||
int et_IPC_HLE;
|
int et_IPC_HLE;
|
||||||
int et_FakeGPWD; // DC watchdog hack
|
int et_FakeGPWD; // DC watchdog hack
|
||||||
|
@ -127,6 +127,9 @@ int
|
||||||
// These shouldn't be period controlled either, most likely.
|
// These shouldn't be period controlled either, most likely.
|
||||||
DSP_PERIOD,
|
DSP_PERIOD,
|
||||||
|
|
||||||
|
// This is a fixed value, don't change it
|
||||||
|
AUDIO_DMA_PERIOD,
|
||||||
|
|
||||||
// This is completely arbitrary. If we find that we need lower latency, we can just
|
// This is completely arbitrary. If we find that we need lower latency, we can just
|
||||||
// increase this number.
|
// increase this number.
|
||||||
IPC_HLE_PERIOD,
|
IPC_HLE_PERIOD,
|
||||||
|
@ -165,12 +168,10 @@ void DSPCallback(u64 userdata, int cyclesLate)
|
||||||
CoreTiming::ScheduleEvent(DSP_PERIOD - cyclesLate, et_DSP);
|
CoreTiming::ScheduleEvent(DSP_PERIOD - cyclesLate, et_DSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFifoCallback(u64 userdata, int cyclesLate)
|
void AudioDMACallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
int period = CPU_CORE_CLOCK / (AudioInterface::GetDSPSampleRate() * 4 / 32);
|
|
||||||
DSP::UpdateAudioDMA(); // Push audio to speakers.
|
DSP::UpdateAudioDMA(); // Push audio to speakers.
|
||||||
|
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD - cyclesLate, et_AudioDMA);
|
||||||
CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioFifo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
|
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
|
||||||
|
@ -275,6 +276,9 @@ void Init()
|
||||||
// This is the biggest question mark.
|
// This is the biggest question mark.
|
||||||
AI_PERIOD = GetTicksPerSecond() / 80;
|
AI_PERIOD = GetTicksPerSecond() / 80;
|
||||||
|
|
||||||
|
// System internal sample rate is fixed at 32KHz
|
||||||
|
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (32000 * 4 / 32);
|
||||||
|
|
||||||
Common::Timer::IncreaseResolution();
|
Common::Timer::IncreaseResolution();
|
||||||
// store and convert localtime at boot to timebase ticks
|
// store and convert localtime at boot to timebase ticks
|
||||||
startTimeBaseTicks = (u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime();
|
startTimeBaseTicks = (u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime();
|
||||||
|
@ -284,7 +288,7 @@ void Init()
|
||||||
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
|
||||||
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
|
||||||
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
|
||||||
et_AudioFifo = CoreTiming::RegisterEvent("AudioFifoCallback", AudioFifoCallback);
|
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
|
||||||
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
|
||||||
// Always register this. Increases chances of DC/SC save state compatibility.
|
// Always register this. Increases chances of DC/SC save state compatibility.
|
||||||
et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback);
|
et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback);
|
||||||
|
@ -294,7 +298,7 @@ void Init()
|
||||||
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(GetTicksPerSecond() / 60, et_SI);
|
CoreTiming::ScheduleEvent(GetTicksPerSecond() / 60, et_SI);
|
||||||
CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), et_AudioFifo);
|
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
|
||||||
|
|
||||||
// For DC watchdog hack
|
// For DC watchdog hack
|
||||||
if (Core::GetStartupParameter().bCPUThread)
|
if (Core::GetStartupParameter().bCPUThread)
|
||||||
|
|
|
@ -141,6 +141,7 @@
|
||||||
// cr (Not g_dsp.r[CR]) bits
|
// cr (Not g_dsp.r[CR]) bits
|
||||||
// See HW/DSP.cpp.
|
// See HW/DSP.cpp.
|
||||||
#define CR_HALT 0x0004
|
#define CR_HALT 0x0004
|
||||||
|
#define CR_INIT 0x0400
|
||||||
#define CR_EXTERNAL_INT 0x0002
|
#define CR_EXTERNAL_INT 0x0002
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -286,7 +286,7 @@ void CConfigMain::CreateGUIControls()
|
||||||
wxT("\nIt can be convenient in a Wii game that already has a cursor."));
|
wxT("\nIt can be convenient in a Wii game that already has a cursor."));
|
||||||
WiimoteStatusLEDs->SetToolTip(wxT("Show which wiimotes are connected in the statusbar."));
|
WiimoteStatusLEDs->SetToolTip(wxT("Show which wiimotes are connected in the statusbar."));
|
||||||
WiimoteStatusSpeakers->SetToolTip(wxT("Show wiimote speaker status in the statusbar."));
|
WiimoteStatusSpeakers->SetToolTip(wxT("Show wiimote speaker status in the statusbar."));
|
||||||
DSPThread->SetToolTip(wxT("This should be on when using HLE and off when using LLE."));
|
DSPThread->SetToolTip(wxT("Run DSPLLE on a dedicate thread, this has no affect on DSPHLE."));
|
||||||
CPUThread->SetToolTip(wxT("This splits the Video and CPU threads, so they can be run on separate cores.")
|
CPUThread->SetToolTip(wxT("This splits the Video and CPU threads, so they can be run on separate cores.")
|
||||||
wxT("\nCauses major speed improvements on PCs with more than one core,")
|
wxT("\nCauses major speed improvements on PCs with more than one core,")
|
||||||
wxT("\nbut can also cause occasional crashes/glitches."));
|
wxT("\nbut can also cause occasional crashes/glitches."));
|
||||||
|
|
|
@ -17,7 +17,7 @@ typedef const char* (*TName)(void);
|
||||||
typedef void (*TDebuggerBreak)(void);
|
typedef void (*TDebuggerBreak)(void);
|
||||||
typedef void (*TGenerateDSPInt)(void);
|
typedef void (*TGenerateDSPInt)(void);
|
||||||
typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate);
|
typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate);
|
||||||
typedef void (*TGetSampleRate)(unsigned int &AISampleRate, unsigned int &DSPSampleRate);
|
typedef void (*TGetSampleRate)(unsigned int &AISampleRate, unsigned int &DACSampleRate);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -98,9 +98,8 @@ EXPORT void CALL DSP_Update(int cycles);
|
||||||
// Purpose: This function sends the current AI Buffer to the DSP plugin
|
// Purpose: This function sends the current AI Buffer to the DSP plugin
|
||||||
// input: _Address : Memory-Address
|
// input: _Address : Memory-Address
|
||||||
// input: _Number : Number of the Samples
|
// input: _Number : Number of the Samples
|
||||||
// input: _Rate : Sample Rate 32000/48000
|
|
||||||
//
|
//
|
||||||
EXPORT void CALL DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate);
|
EXPORT void CALL DSP_SendAIBuffer(unsigned int address, unsigned int num_samples);
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// Function: DSP_StopSoundStream
|
// Function: DSP_StopSoundStream
|
||||||
|
|
|
@ -58,10 +58,9 @@ DSPConfigDialogHLE::DSPConfigDialogHLE(wxWindow *parent, wxWindowID id, const wx
|
||||||
m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM."));
|
m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM."));
|
||||||
m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n")
|
m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n")
|
||||||
wxT("Disabling this could cause abnormal game speed, such as too fast.\n")
|
wxT("Disabling this could cause abnormal game speed, such as too fast.\n")
|
||||||
wxT("But sometimes enabling this causes constant noise."));
|
wxT("But sometimes enabling this could cause constant noise.\n")
|
||||||
|
wxT("\nKeyboard Shortcut <TAB>: Hold down to instantly disable Throttle."));
|
||||||
m_buttonEnableRE0Fix->SetToolTip(wxT("This fixes audio in Resident Evil Zero and maybe some other games."));
|
m_buttonEnableRE0Fix->SetToolTip(wxT("This fixes audio in Resident Evil Zero and maybe some other games."));
|
||||||
|
|
||||||
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
|
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
|
||||||
|
|
||||||
// Create sizer and add items to dialog
|
// Create sizer and add items to dialog
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "DSPHandler.h"
|
#include "DSPHandler.h"
|
||||||
#include "HLEMixer.h"
|
#include "HLEMixer.h"
|
||||||
|
|
||||||
void HLEMixer::Premix(short *samples, unsigned int numSamples, unsigned int sampleRate)
|
void HLEMixer::Premix(short *samples, unsigned int numSamples)
|
||||||
{
|
{
|
||||||
// if this was called directly from the HLE
|
// if this was called directly from the HLE
|
||||||
if (g_Config.m_EnableHLEAudio && IsHLEReady())
|
if (g_Config.m_EnableHLEAudio && IsHLEReady())
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
class HLEMixer : public CMixer
|
class HLEMixer : public CMixer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HLEMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000)
|
HLEMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000)
|
||||||
: CMixer(AISampleRate, DSPSampleRate) {};
|
: CMixer(AISampleRate, DACSampleRate) {};
|
||||||
|
|
||||||
virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate);
|
virtual void Premix(short *samples, unsigned int numSamples);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HLEMIXER_H
|
#endif // HLEMIXER_H
|
||||||
|
|
|
@ -307,9 +307,9 @@ unsigned short DSP_WriteControlRegister(unsigned short _Value)
|
||||||
{
|
{
|
||||||
if (!Temp.DSPHalt && Temp.DSPInit)
|
if (!Temp.DSPHalt && Temp.DSPInit)
|
||||||
{
|
{
|
||||||
unsigned int AISampleRate, DSPSampleRate;
|
unsigned int AISampleRate, DACSampleRate;
|
||||||
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate);
|
g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate);
|
||||||
soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DSPSampleRate));
|
soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DACSampleRate));
|
||||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||||
// Mixer is initialized
|
// Mixer is initialized
|
||||||
g_InitMixer = true;
|
g_InitMixer = true;
|
||||||
|
@ -334,7 +334,7 @@ void DSP_Update(int cycles)
|
||||||
inside Mixer_PushSamples(), the reason that we don't disable this entire
|
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
|
function when Other Audio is disabled is that then we can't turn it back on
|
||||||
again once the game has started. */
|
again once the game has started. */
|
||||||
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate)
|
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
|
||||||
{
|
{
|
||||||
if (!soundStream)
|
if (!soundStream)
|
||||||
return;
|
return;
|
||||||
|
@ -344,9 +344,8 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned i
|
||||||
if (pMixer && address)
|
if (pMixer && address)
|
||||||
{
|
{
|
||||||
short* samples = (short*)Memory_Get_Pointer(address);
|
short* samples = (short*)Memory_Get_Pointer(address);
|
||||||
// sample_rate could be 32khz/48khz here,
|
// Internal sample rate is always 32khz
|
||||||
// see Core/DSP/DSP.cpp for better information
|
pMixer->PushSamples(samples, num_samples);
|
||||||
pMixer->PushSamples(samples, num_samples, sample_rate);
|
|
||||||
|
|
||||||
// FIXME: Write the audio to a file
|
// FIXME: Write the audio to a file
|
||||||
//if (log_ai)
|
//if (log_ai)
|
||||||
|
|
|
@ -39,7 +39,7 @@ DSPConfigDialogLLE::DSPConfigDialogLLE(wxWindow *parent, wxWindowID id, const wx
|
||||||
|
|
||||||
// Create items
|
// Create items
|
||||||
m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||||
m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Other Audio (Throttle)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Audio Throttle"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||||
wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0);
|
wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxSize(90, 20), wxArrayBackends, wxCB_READONLY, wxDefaultValidator);
|
m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxSize(90, 20), wxArrayBackends, wxCB_READONLY, wxDefaultValidator);
|
||||||
|
|
||||||
|
@ -51,10 +51,11 @@ DSPConfigDialogLLE::DSPConfigDialogLLE(wxWindow *parent, wxWindowID id, const wx
|
||||||
m_buttonEnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
|
m_buttonEnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
|
||||||
|
|
||||||
// Add tooltips
|
// Add tooltips
|
||||||
m_buttonEnableDTKMusic->SetToolTip(wxT("This is sometimes used to play music tracks from the disc"));
|
m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM."));
|
||||||
m_buttonEnableThrottle->SetToolTip(wxT("This is sometimes used together with pre-rendered movies.\n")
|
m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n")
|
||||||
wxT("Disabling this also disables the speed throttle which this causes,\n")
|
wxT("Disabling this could cause abnormal game speed, such as too fast.\n")
|
||||||
wxT("meaning that there will be no upper limit on your FPS."));
|
wxT("But sometimes enabling this could cause constant noise.\n")
|
||||||
|
wxT("\nKeyboard Shortcut <TAB>: Hold down to instantly disable Throttle."));
|
||||||
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
|
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
|
||||||
|
|
||||||
// Create sizer and add items to dialog
|
// Create sizer and add items to dialog
|
||||||
|
|
|
@ -263,9 +263,9 @@ u16 DSP_WriteControlRegister(u16 _uFlag)
|
||||||
{
|
{
|
||||||
if (!Temp.DSPHalt && Temp.DSPInit)
|
if (!Temp.DSPHalt && Temp.DSPInit)
|
||||||
{
|
{
|
||||||
unsigned int AISampleRate, DSPSampleRate;
|
unsigned int AISampleRate, DACSampleRate;
|
||||||
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate);
|
g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate);
|
||||||
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DSPSampleRate));
|
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DACSampleRate));
|
||||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||||
// Mixer is initialized
|
// Mixer is initialized
|
||||||
g_InitMixer = true;
|
g_InitMixer = true;
|
||||||
|
@ -334,6 +334,8 @@ void DSP_WriteMailboxLow(bool _CPUMailbox, u16 _uLowMail)
|
||||||
|
|
||||||
void DSP_Update(int cycles)
|
void DSP_Update(int cycles)
|
||||||
{
|
{
|
||||||
|
// Sound stream update job has been handled by AudioDMA routine, which is more efficient
|
||||||
|
/*
|
||||||
// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
|
// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
|
||||||
int cycles_between_ss_update;
|
int cycles_between_ss_update;
|
||||||
|
|
||||||
|
@ -350,7 +352,7 @@ void DSP_Update(int cycles)
|
||||||
cycle_count -= cycles_between_ss_update;
|
cycle_count -= cycles_between_ss_update;
|
||||||
soundStream->Update();
|
soundStream->Update();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// If we're not on a thread, run cycles here.
|
// If we're not on a thread, run cycles here.
|
||||||
if (!g_dspInitialize.bOnThread)
|
if (!g_dspInitialize.bOnThread)
|
||||||
{
|
{
|
||||||
|
@ -358,7 +360,7 @@ void DSP_Update(int cycles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate)
|
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
|
||||||
{
|
{
|
||||||
if (!soundStream)
|
if (!soundStream)
|
||||||
return;
|
return;
|
||||||
|
@ -369,7 +371,7 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned i
|
||||||
{
|
{
|
||||||
short* samples = (short*)Memory_Get_Pointer(address);
|
short* samples = (short*)Memory_Get_Pointer(address);
|
||||||
|
|
||||||
pMixer->PushSamples(samples, num_samples, sample_rate);
|
pMixer->PushSamples(samples, num_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
soundStream->Update();
|
soundStream->Update();
|
||||||
|
|
Loading…
Reference in New Issue