mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 22:00:39 -06:00
Audio system update - HLE plugin submitted, homebrew has sound, and also Mario movies!! (this was very unexpected). This also acts as a frame limiter. Might provide an option to turn it off in the future.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@227 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -53,14 +53,14 @@ union AICR
|
||||
AICR(u32 _hex) { hex = _hex;}
|
||||
struct
|
||||
{
|
||||
unsigned PSTAT : 1; // sample counter/playback enable
|
||||
unsigned AFR : 1; // 0=32khz 1=48khz
|
||||
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
||||
unsigned AIINT : 1; // audio interrupt status
|
||||
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
||||
// matching AISLRCNT. Once set, AIINT will hold
|
||||
unsigned SCRESET : 1; // write to reset counter
|
||||
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
|
||||
unsigned PSTAT : 1; // sample counter/playback enable
|
||||
unsigned AFR : 1; // 0=32khz 1=48khz
|
||||
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
||||
unsigned AIINT : 1; // audio interrupt status
|
||||
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
||||
// matching AISLRCNT. Once set, AIINT will hold
|
||||
unsigned SCRESET : 1; // write to reset counter
|
||||
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
|
||||
unsigned :25;
|
||||
};
|
||||
u32 hex;
|
||||
@ -96,6 +96,7 @@ void ReadStreamBlock(short* _pPCM);
|
||||
|
||||
static u64 g_LastCPUTime = 0;
|
||||
static int g_SampleRate = 32000;
|
||||
static int g_DSPSampleRate = 32000;
|
||||
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
||||
|
||||
void Init()
|
||||
@ -116,6 +117,7 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
case AI_CONTROL_REGISTER: //0x6C00
|
||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||
_rReturnValue = g_AudioRegister.m_Control.hex;
|
||||
|
||||
return;
|
||||
|
||||
// Sample Rate (AIGetDSPSampleRate)
|
||||
@ -164,7 +166,10 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
|
||||
}
|
||||
|
||||
g_SampleRate = g_AudioRegister.m_Control.AFR ? 48000 : 32000;
|
||||
g_SampleRate = tmpAICtrl.AFR ? 32000 : 48000;
|
||||
g_DSPSampleRate = tmpAICtrl.DSPFR ? 32000 : 48000;
|
||||
// PanicAlert("Sample rate %i %i", g_Aui, g_SampleRate);
|
||||
|
||||
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
|
||||
|
||||
// Streaming counter
|
||||
@ -195,6 +200,8 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||
g_LastCPUTime = CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
g_AudioRegister.m_Control = tmpAICtrl;
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
@ -316,11 +323,16 @@ void IncreaseSampleCount(const u32 _iAmount)
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetRate()
|
||||
u32 GetAISampleRate()
|
||||
{
|
||||
return g_SampleRate;
|
||||
}
|
||||
|
||||
u32 GetDSPSampleRate()
|
||||
{
|
||||
return g_DSPSampleRate;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// update timer
|
||||
|
@ -42,7 +42,8 @@ void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
||||
// Get the Audio Rate (48000 or 32000)
|
||||
u32 GetRate();
|
||||
u32 GetAISampleRate();
|
||||
u32 GetDSPSampleRate();
|
||||
|
||||
} // end of namespace AudioInterface
|
||||
|
||||
|
@ -179,11 +179,6 @@ void WriteARAM(u8 _iValue, u32 _iAddress);
|
||||
bool Update_DSP_ReadRegister();
|
||||
void Update_DSP_WriteRegister();
|
||||
|
||||
int GetDSPSampleRate()
|
||||
{
|
||||
return 32000; // TODO - can also be 48000
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE);
|
||||
@ -414,7 +409,7 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
|
||||
g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
|
||||
GenerateDSPInterrupt(DSP::INT_AID);
|
||||
LOG(DSP, "AID DMA started - source address %08x, length %i blocks", g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks);
|
||||
LOG(DSPINTERFACE, "AID DMA started - source address %08x, length %i blocks", g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -432,8 +427,12 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
void UpdateAudioDMA()
|
||||
{
|
||||
if (g_audioDMA.AudioDMAControl.Enabled && g_audioDMA.BlocksLeft) {
|
||||
// TODO : Read audio at g_audioDMA.ReadAddress in RAM and push onto an external audio fifo in the emulator,
|
||||
// to be mixed with the disc streaming output. If that audio queue fills up, we have to delay the emulator.
|
||||
// Read audio at g_audioDMA.ReadAddress in RAM and push onto an external audio fifo in the emulator,
|
||||
// to be mixed with the disc streaming output. If that audio queue fills up, we delay the emulator.
|
||||
|
||||
// TO RESTORE OLD BEHAVIOUR, COMMENT OUT THIS LINE
|
||||
PluginDSP::DSP_SendAIBuffer(g_audioDMA.ReadAddress, AudioInterface::GetDSPSampleRate());
|
||||
|
||||
g_audioDMA.ReadAddress += 32;
|
||||
g_audioDMA.BlocksLeft--;
|
||||
if (!g_audioDMA.BlocksLeft) {
|
||||
@ -444,6 +443,10 @@ void UpdateAudioDMA()
|
||||
g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
|
||||
GenerateDSPInterrupt(DSP::INT_AID);
|
||||
}
|
||||
} else {
|
||||
// Send silence. Yeah, it's a bit of a waste to sample rate convert silence.
|
||||
// or hm. Maybe we shouldn't do this :)
|
||||
// PluginDSP::DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@ u8 ReadARAM(const u32 _uAddress);
|
||||
u8* GetARAMPtr();
|
||||
|
||||
void UpdateAudioDMA();
|
||||
int GetDSPSampleRate();
|
||||
|
||||
}// end of namespace DSP
|
||||
|
||||
|
@ -92,15 +92,14 @@ void AICallback(u64 userdata, int cyclesLate)
|
||||
|
||||
void DSPCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// Poke the DSP, make it do stuff. This should eventually be replaced with dsp->RunCycles(1000) or whatever,
|
||||
// ~1/6th as many cycles as the period PPC-side.
|
||||
PluginDSP::DSP_Update();
|
||||
PluginDSP::DSP_Update(DSP_PERIOD / 6);
|
||||
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, &DSPCallback, "DSPCallback");
|
||||
}
|
||||
|
||||
void AudioFifoCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
int period = CPU_CORE_CLOCK / (DSP::GetDSPSampleRate() * 4 / 32);
|
||||
int period = CPU_CORE_CLOCK / (AudioInterface::GetDSPSampleRate() * 4 / 32);
|
||||
DSP::UpdateAudioDMA(); // Push audio to speakers.
|
||||
|
||||
CoreTiming::ScheduleEvent(period - cyclesLate, &AudioFifoCallback, "AudioFifoCallback");
|
||||
@ -140,7 +139,7 @@ void DecrementerSet()
|
||||
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
|
||||
fakeDec = decValue*TIMER_RATIO;
|
||||
CoreTiming::RemoveEvent(DecrementerCallback);
|
||||
CoreTiming::ScheduleEvent(decValue*TIMER_RATIO, DecrementerCallback, "DecCallback");
|
||||
CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, DecrementerCallback, "DecCallback");
|
||||
}
|
||||
|
||||
void AdvanceCallback(int cyclesExecuted)
|
||||
|
@ -31,8 +31,8 @@ typedef void (__cdecl* TDSP_WriteMailBox)(BOOL _CPUMailbox, unsigned short);
|
||||
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(BOOL _CPUMailbox);
|
||||
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
|
||||
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
|
||||
typedef void (__cdecl* TDSP_Update)();
|
||||
typedef void (__cdecl* TDSP_SendAIBuffer)(unsigned int _Address, unsigned int _Size);
|
||||
typedef void (__cdecl* TDSP_Update)(int cycles);
|
||||
typedef void (__cdecl* TDSP_SendAIBuffer)(unsigned int address, int sample_rate);
|
||||
|
||||
//! Function Pointer
|
||||
TGetDllInfo g_GetDllInfo = 0;
|
||||
@ -217,16 +217,16 @@ unsigned short DSP_ReadControlRegister()
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
//
|
||||
void DSP_Update()
|
||||
void DSP_Update(int cycles)
|
||||
{
|
||||
g_DSP_Update();
|
||||
g_DSP_Update(cycles);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
//
|
||||
void DSP_SendAIBuffer(unsigned int _Address, unsigned int _Size)
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
|
||||
{
|
||||
g_DSP_SendAIBuffer(_Address, _Size);
|
||||
g_DSP_SendAIBuffer(address, sample_rate);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ void DSP_WriteMailboxHigh(bool _CPUMailbox, unsigned short _Value);
|
||||
void DSP_WriteMailboxLow(bool _CPUMailbox, unsigned short _Value);
|
||||
unsigned short DSP_WriteControlRegister(unsigned short _Flags);
|
||||
unsigned short DSP_ReadControlRegister();
|
||||
void DSP_Update();
|
||||
void DSP_SendAIBuffer(unsigned int _Address, unsigned int _Size);
|
||||
void DSP_Update(int cycles);
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate);
|
||||
|
||||
} // end of namespace PluginDSP
|
||||
|
||||
|
@ -353,7 +353,8 @@ namespace Jit64
|
||||
|
||||
const u8* DoJit(u32 emaddress, JitBlock &b)
|
||||
{
|
||||
_assert_msg_(DYNA_REC, emaddress != 0, "ERROR - Trying to compile at 0. LR=%08x",LR);
|
||||
if (emaddress == 0)
|
||||
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
||||
|
||||
u32 size;
|
||||
js.isLastInstruction = false;
|
||||
|
@ -87,12 +87,14 @@ namespace Jit64
|
||||
if (inst.LK)
|
||||
AND(32, M(&CR), Imm32(~(0xFF000000)));
|
||||
#endif
|
||||
//if (destination == js.compilerPC)
|
||||
//{
|
||||
if (destination == js.compilerPC)
|
||||
{
|
||||
//PanicAlert("Idle loop detected at %08x", destination);
|
||||
// CALL(ProtectFunction(&CoreTiming::Idle, 0));
|
||||
// JMP(Asm::testExceptions, true);
|
||||
//}
|
||||
// make idle loops go faster
|
||||
js.downcountAmount += 8;
|
||||
}
|
||||
WriteExit(destination, 0);
|
||||
}
|
||||
else {
|
||||
|
@ -99,9 +99,6 @@ u32 PPCAnalyst::EvaluateBranchTarget(UGeckoInstruction instr, u32 pc)
|
||||
|
||||
u32 PPCAnalyst::AnalyzeFunction(u32 startAddr, SFunction &func)
|
||||
{
|
||||
//if (startAddr <0x80000008 || startAddr>0x80000000+Memory::RAM_MASK)
|
||||
// return 0;
|
||||
|
||||
func.name = StringFromFormat("zzz_%08x ??", startAddr);
|
||||
func.calls.clear();
|
||||
func.callers.clear();
|
||||
|
@ -262,9 +262,8 @@ inline void decodebytesARGB8pass1(u32 *dst, u16 *src, int numpixels)
|
||||
for (int x = 0; x < numpixels; x++)
|
||||
{
|
||||
int val = Common::swap16(src[x]);
|
||||
int a=val&0xFF;
|
||||
val>>=8;
|
||||
|
||||
int a = val & 0xFF;
|
||||
val >>= 8;
|
||||
*dst++ = (a<<16) | (val<<24);
|
||||
}
|
||||
}
|
||||
@ -274,9 +273,8 @@ inline void decodebytesARGB8pass2(u32 *dst, u16 *src, int numpixels)
|
||||
for (int x = 0; x < numpixels; x++)
|
||||
{
|
||||
int val = Common::swap16(src[x]);
|
||||
int a=val&0xFF;
|
||||
val>>=8;
|
||||
|
||||
int a = val & 0xFF;
|
||||
val >>= 8;
|
||||
*dst++ |= (val<<8) | (a<<0);
|
||||
}
|
||||
}
|
||||
@ -419,9 +417,9 @@ PC_TexFormat TexDecoder_Decode(u8 *dst, u8 *src, int width, int height, int texf
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++, src += 8)
|
||||
decodebytesARGB8pass1((u32*)dst+(y+iy)*width+x, (u16*)src, 4);
|
||||
decodebytesARGB8pass1((u32*)dst + (y+iy)*width + x, (u16*)src, 4);
|
||||
for (int iy = 0; iy < 4; iy++, src += 8)
|
||||
decodebytesARGB8pass2((u32*)dst+(y+iy)*width+x, (u16*)src, 4);
|
||||
decodebytesARGB8pass2((u32*)dst + (y+iy)*width + x, (u16*)src, 4);
|
||||
}
|
||||
}
|
||||
return PC_TEX_FMT_BGRA32;
|
||||
|
Reference in New Issue
Block a user