mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
ZeldaHLE: Rip out the whole voice processing code. Still boots games, but no sound at all.
This commit is contained in:
@@ -74,9 +74,6 @@ set(SRCS ActionReplay.cpp
|
||||
HW/DSPHLE/UCodes/ROM.cpp
|
||||
HW/DSPHLE/UCodes/UCodes.cpp
|
||||
HW/DSPHLE/UCodes/Zelda.cpp
|
||||
HW/DSPHLE/UCodes/ZeldaADPCM.cpp
|
||||
HW/DSPHLE/UCodes/ZeldaSynth.cpp
|
||||
HW/DSPHLE/UCodes/ZeldaVoice.cpp
|
||||
HW/DSPHLE/MailHandler.cpp
|
||||
HW/DSPHLE/DSPHLE.cpp
|
||||
HW/DSPLLE/DSPDebugInterface.cpp
|
||||
|
||||
@@ -108,9 +108,6 @@
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\INIT.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ROM.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaADPCM.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaSynth.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaVoice.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPHost.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPLLE.cpp" />
|
||||
|
||||
@@ -336,15 +336,6 @@
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaADPCM.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaSynth.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaVoice.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\UCodes.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -23,21 +23,10 @@ ZeldaUCode::ZeldaUCode(DSPHLE *dsphle, u32 crc)
|
||||
m_current_voice(0),
|
||||
m_current_buffer(0),
|
||||
m_num_buffers(0),
|
||||
m_voice_pbs_addr(0),
|
||||
m_unk_table_addr(0),
|
||||
m_reverb_pbs_addr(0),
|
||||
m_right_buffers_addr(0),
|
||||
m_left_buffers_addr(0),
|
||||
m_pos(0),
|
||||
m_dma_base_addr(0),
|
||||
m_num_steps(0),
|
||||
m_list_in_progress(false),
|
||||
m_step(0),
|
||||
m_read_offset(0),
|
||||
m_mail_state(WaitForMail),
|
||||
m_num_pbs(0),
|
||||
m_pb_address(0),
|
||||
m_pb_address2(0)
|
||||
m_read_offset(0)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "UCode_Zelda - add boot mails for handshake");
|
||||
|
||||
@@ -52,34 +41,11 @@ ZeldaUCode::ZeldaUCode(DSPHLE *dsphle, u32 crc)
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
m_mail_handler.PushMail(0xF3551111); // handshake
|
||||
}
|
||||
|
||||
m_voice_buffer = new s32[256 * 1024];
|
||||
m_resample_buffer = new s16[256 * 1024];
|
||||
m_left_buffer = new s32[256 * 1024];
|
||||
m_right_buffer = new s32[256 * 1024];
|
||||
|
||||
memset(m_buffer, 0, sizeof(m_buffer));
|
||||
memset(m_sync_flags, 0, sizeof(m_sync_flags));
|
||||
memset(m_afc_coef_table, 0, sizeof(m_afc_coef_table));
|
||||
memset(m_pb_mask, 0, sizeof(m_pb_mask));
|
||||
}
|
||||
|
||||
ZeldaUCode::~ZeldaUCode()
|
||||
{
|
||||
m_mail_handler.Clear();
|
||||
|
||||
delete [] m_voice_buffer;
|
||||
delete [] m_resample_buffer;
|
||||
delete [] m_left_buffer;
|
||||
delete [] m_right_buffer;
|
||||
}
|
||||
|
||||
u8 *ZeldaUCode::GetARAMPointer(u32 address)
|
||||
{
|
||||
if (IsDMAVersion())
|
||||
return Memory::GetPointer(m_dma_base_addr) + address;
|
||||
else
|
||||
return DSP::GetARAMPtr() + address;
|
||||
}
|
||||
|
||||
void ZeldaUCode::Update()
|
||||
@@ -116,7 +82,7 @@ void ZeldaUCode::HandleMail_LightVersion(u32 mail)
|
||||
{
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
|
||||
MixAudio();
|
||||
// TODO(delroth): Mix audio.
|
||||
|
||||
m_current_buffer++;
|
||||
|
||||
@@ -176,7 +142,7 @@ void ZeldaUCode::HandleMail_SMSVersion(u32 mail)
|
||||
m_num_sync_mail = 0;
|
||||
m_sync_in_progress = false;
|
||||
|
||||
MixAudio();
|
||||
// TODO(delroth): Mix audio.
|
||||
|
||||
m_current_buffer++;
|
||||
|
||||
@@ -281,7 +247,7 @@ void ZeldaUCode::HandleMail_NormalVersion(u32 mail)
|
||||
|
||||
if (m_current_voice >= m_num_voices)
|
||||
{
|
||||
MixAudio();
|
||||
// TODO(delroth): Mix audio.
|
||||
|
||||
m_current_buffer++;
|
||||
|
||||
@@ -403,63 +369,16 @@ void ZeldaUCode::ExecuteList()
|
||||
|
||||
// DsetupTable ... zelda ww jumps to 0x0095
|
||||
case 0x01:
|
||||
{
|
||||
m_num_voices = extra_data;
|
||||
m_voice_pbs_addr = Read32() & 0x7FFFFFFF;
|
||||
m_unk_table_addr = Read32() & 0x7FFFFFFF;
|
||||
m_afc_coef_table_addr = Read32() & 0x7FFFFFFF;
|
||||
m_reverb_pbs_addr = Read32() & 0x7FFFFFFF; // WARNING: reverb PBs are very different from voice PBs!
|
||||
|
||||
// Read the other table
|
||||
u16 *tmp_ptr = (u16*)Memory::GetPointer(m_unk_table_addr);
|
||||
for (int i = 0; i < 0x280; i++)
|
||||
m_misc_table[i] = (s16)Common::swap16(tmp_ptr[i]);
|
||||
|
||||
// Read AFC coef table
|
||||
tmp_ptr = (u16*)Memory::GetPointer(m_afc_coef_table_addr);
|
||||
for (int i = 0; i < 32; i++)
|
||||
m_afc_coef_table[i] = (s16)Common::swap16(tmp_ptr[i]);
|
||||
|
||||
DEBUG_LOG(DSPHLE, "DsetupTable");
|
||||
DEBUG_LOG(DSPHLE, "Num voice param blocks: %i", m_num_voices);
|
||||
DEBUG_LOG(DSPHLE, "Voice param blocks address: 0x%08x", m_voice_pbs_addr);
|
||||
|
||||
// This points to some strange data table. Don't know yet what it's for. Reverb coefs?
|
||||
DEBUG_LOG(DSPHLE, "DSPRES_FILTER (size: 0x40): 0x%08x", m_unk_table_addr);
|
||||
|
||||
// Zelda WW: This points to a 64-byte array of coefficients, which are EXACTLY the same
|
||||
// as the AFC ADPCM coef array in decode.c of the in_cube winamp plugin,
|
||||
// which can play Zelda audio. So, these should definitely be used when decoding AFC.
|
||||
DEBUG_LOG(DSPHLE, "DSPADPCM_FILTER (size: 0x500): 0x%08x", m_afc_coef_table_addr);
|
||||
DEBUG_LOG(DSPHLE, "Reverb param blocks address: 0x%08x", m_reverb_pbs_addr);
|
||||
}
|
||||
Read32(); Read32(); Read32(); Read32();
|
||||
break;
|
||||
|
||||
// SyncFrame ... zelda ww jumps to 0x0243
|
||||
case 0x02:
|
||||
{
|
||||
m_sync_cmd_pending = true;
|
||||
|
||||
m_current_buffer = 0;
|
||||
m_num_buffers = (cmd_mail >> 16) & 0xFF;
|
||||
|
||||
// Addresses for right & left buffers in main memory
|
||||
// Each buffer is 160 bytes long. The number of (both left & right) buffers
|
||||
// is set by the first mail of the list.
|
||||
m_left_buffers_addr = Read32() & 0x7FFFFFFF;
|
||||
m_right_buffers_addr = Read32() & 0x7FFFFFFF;
|
||||
|
||||
DEBUG_LOG(DSPHLE, "DsyncFrame");
|
||||
// These alternate between three sets of mixing buffers. They are all three fairly near,
|
||||
// but not at, the ADMA read addresses.
|
||||
DEBUG_LOG(DSPHLE, "Right buffer address: 0x%08x", m_right_buffers_addr);
|
||||
DEBUG_LOG(DSPHLE, "Left buffer address: 0x%08x", m_left_buffers_addr);
|
||||
|
||||
Read32(); Read32();
|
||||
if (IsLightVersion())
|
||||
break;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Simply sends the sync messages
|
||||
@@ -485,11 +404,7 @@ void ZeldaUCode::ExecuteList()
|
||||
// This opcode, in the SMG ucode, sets the base address for audio data transfers from main memory (using DMA).
|
||||
// In the Zelda ucode, it is dummy, because this ucode uses accelerator for audio data transfers.
|
||||
case 0x0e:
|
||||
{
|
||||
m_dma_base_addr = Read32() & 0x7FFFFFFF;
|
||||
DEBUG_LOG(DSPHLE, "DsetDMABaseAddr");
|
||||
DEBUG_LOG(DSPHLE, "DMA base address: 0x%08x", m_dma_base_addr);
|
||||
}
|
||||
Read32();
|
||||
break;
|
||||
|
||||
// default ... zelda ww jumps to 0x0043
|
||||
@@ -521,9 +436,6 @@ u32 ZeldaUCode::GetUpdateMs()
|
||||
|
||||
void ZeldaUCode::DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(m_afc_coef_table);
|
||||
p.Do(m_misc_table);
|
||||
|
||||
p.Do(m_sync_in_progress);
|
||||
p.Do(m_max_voice);
|
||||
p.Do(m_sync_flags);
|
||||
@@ -537,17 +449,6 @@ void ZeldaUCode::DoState(PointerWrap &p)
|
||||
p.Do(m_current_buffer);
|
||||
p.Do(m_num_buffers);
|
||||
|
||||
p.Do(m_voice_pbs_addr);
|
||||
p.Do(m_unk_table_addr);
|
||||
p.Do(m_afc_coef_table_addr);
|
||||
p.Do(m_reverb_pbs_addr);
|
||||
|
||||
p.Do(m_right_buffers_addr);
|
||||
p.Do(m_left_buffers_addr);
|
||||
p.Do(m_pos);
|
||||
|
||||
p.Do(m_dma_base_addr);
|
||||
|
||||
p.Do(m_num_steps);
|
||||
p.Do(m_list_in_progress);
|
||||
p.Do(m_step);
|
||||
@@ -555,12 +456,5 @@ void ZeldaUCode::DoState(PointerWrap &p)
|
||||
|
||||
p.Do(m_read_offset);
|
||||
|
||||
p.Do(m_mail_state);
|
||||
p.Do(m_pb_mask);
|
||||
|
||||
p.Do(m_num_pbs);
|
||||
p.Do(m_pb_address);
|
||||
p.Do(m_pb_address2);
|
||||
|
||||
DoStateShared(p);
|
||||
}
|
||||
|
||||
@@ -7,113 +7,6 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
|
||||
|
||||
// Obviously missing things that must be in here, somewhere among the "unknown":
|
||||
// * Volume
|
||||
// * L/R Pan
|
||||
// * (probably) choice of resampling algorithm (point, linear, cubic)
|
||||
|
||||
union ZeldaVoicePB
|
||||
{
|
||||
struct
|
||||
{
|
||||
// Read-Write part
|
||||
u16 Status; // 0x00 | 1 = play, 0 = stop
|
||||
u16 KeyOff; // 0x01 | writing 1 stops voice?
|
||||
u16 RatioInt; // 0x02 | Position delta (playback speed)
|
||||
u16 Unk03; // 0x03 | unknown
|
||||
u16 NeedsReset; // 0x04 | indicates if some values in PB need to be reset
|
||||
u16 ReachedEnd; // 0x05 | set to 1 when end reached
|
||||
u16 IsBlank; // 0x06 | 0 = normal sound, 1 = samples are always the same
|
||||
u16 Unk07; // 0x07 | unknown, in zelda always 0x0010. Something to do with number of saved samples (0x68)?
|
||||
|
||||
u16 SoundType; // 0x08 | "Sound type": so far in zww: 0x0d00 for music (volume mode 0), 0x4861 for sfx (volume mode 1)
|
||||
u16 volumeLeft1; // 0x09 | Left Volume 1 // There's probably two of each because they should be ramped within each frame.
|
||||
u16 volumeLeft2; // 0x0A | Left Volume 2
|
||||
u16 Unk0B; // 0x0B | unknown
|
||||
|
||||
u16 SoundType2; // 0x0C | "Sound type" 2 (not really sound type)
|
||||
u16 volumeRight1; // 0x0D | Right Volume 1
|
||||
u16 volumeRight2; // 0x0E | Right Volume 2
|
||||
u16 Unk0F; // 0x0F | unknown
|
||||
|
||||
u16 SoundType3; // 0x10 | "Sound type" 3 (not really sound type)
|
||||
u16 volumeUnknown1_1; // 0x11 | Unknown Volume 1
|
||||
u16 volumeUnknown1_2; // 0x12 | Unknown Volume 1
|
||||
u16 Unk13; // 0x13 | unknown
|
||||
|
||||
u16 SoundType4; // 0x14 | "Sound type" 4 (not really sound type)
|
||||
u16 volumeUnknown2_1; // 0x15 | Unknown Volume 2
|
||||
u16 volumeUnknown2_2; // 0x16 | Unknown Volume 2
|
||||
u16 Unk17; // 0x17 | unknown
|
||||
|
||||
u16 Unk18[0x10]; // 0x18 | unknown
|
||||
u16 Unk28; // 0x28 | unknown
|
||||
u16 Unk29; // 0x29 | unknown // multiplied by 0x2a @ 0d21/ZWW
|
||||
u16 Unk2a; // 0x2A | unknown // loaded at 0d2e/ZWW
|
||||
u16 Unk2b; // 0x2B | unknown
|
||||
u16 VolumeMode; // 0x2C | unknown // See 0337/ZWW
|
||||
u16 Unk2D; // 0x2D | unknown
|
||||
u16 Unk2E; // 0x2E | unknown
|
||||
u16 Unk2F; // 0x2F | unknown
|
||||
u16 CurSampleFrac; // 0x30 | Fractional part of the current sample position
|
||||
u16 Unk31; // 0x31 | unknown / unused
|
||||
u16 CurBlock; // 0x32 | current block? used by zelda's AFC decoder. we don't need it.
|
||||
u16 FixedSample; // 0x33 | sample value for "blank" voices
|
||||
u32 RestartPos; // 0x34 | restart pos / "loop start offset"
|
||||
u16 Unk36[2]; // 0x36 | unknown // loaded at 0adc/ZWW in 0x21 decoder
|
||||
u32 CurAddr; // 0x38 | current address
|
||||
u32 RemLength; // 0x3A | remaining length
|
||||
u16 ResamplerOldData[4]; // 0x3C | The resampler stores the last 4 decoded samples here from the previous frame, so that the filter kernel has something to read before the start of the buffer.
|
||||
u16 Unk40[0x10]; // 0x40 | Used as some sort of buffer by IIR
|
||||
u16 Unk50[0x8]; // 0x50 | Used as some sort of buffer by 06ff/ZWW
|
||||
u16 Unk58[0x8]; // 0x58 |
|
||||
u16 Unk60[0x6]; // 0x60 |
|
||||
u16 YN2; // 0x66 | YN2
|
||||
u16 YN1; // 0x67 | YN1
|
||||
u16 Unk68[0x10]; // 0x68 | Saved samples from last decode?
|
||||
u16 FilterState1; // 0x78 | unknown // ZWW: 0c84_FilterBufferInPlace loads and stores. Simply, the filter state.
|
||||
u16 FilterState2; // 0x79 | unknown // ZWW: same as above. these two are active if 0x04a8 != 0.
|
||||
u16 Unk7A; // 0x7A | unknown
|
||||
u16 Unk7B; // 0x7B | unknown
|
||||
u16 Unk7C; // 0x7C | unknown
|
||||
u16 Unk7D; // 0x7D | unknown
|
||||
u16 Unk7E; // 0x7E | unknown
|
||||
u16 Unk7F; // 0x7F | unknown
|
||||
|
||||
// Read-only part
|
||||
u16 Format; // 0x80 | audio format
|
||||
u16 RepeatMode; // 0x81 | 0 = one-shot, non zero = loop
|
||||
u16 LoopYN1; // 0x82 | YN1 reload (when AFC loops)
|
||||
u16 LoopYN2; // 0x83 | YN2 reload (when AFC loops)
|
||||
u16 Unk84; // 0x84 | IIR Filter # coefs?
|
||||
u16 StopOnSilence; // 0x85 | Stop on silence? (Flag for something volume related. Decides the weird stuff at 035a/ZWW, alco 0cd3)
|
||||
u16 Unk86; // 0x86 | unknown
|
||||
u16 Unk87; // 0x87 | unknown
|
||||
u32 LoopStartPos; // 0x88 | loopstart pos
|
||||
u32 Length; // 0x8A | sound length
|
||||
u32 StartAddr; // 0x8C | sound start address
|
||||
u32 UnkAddr; // 0x8E | ???
|
||||
u16 Padding[0x10]; // 0x90 | padding
|
||||
u16 Padding2[0x8]; // 0xa0 | FIR filter coefs of some sort (0xa4 controls the appearance of 0xa5-0xa7 and is almost always 0x7FFF)
|
||||
u16 FilterEnable; // 0xa8 | FilterBufferInPlace enable
|
||||
u16 Padding3[0x7]; // 0xa9 | padding
|
||||
u16 Padding4[0x10]; // 0xb0 | padding
|
||||
};
|
||||
u16 raw[0xc0]; // WARNING-do not use on parts of the 32-bit values - they are swapped!
|
||||
};
|
||||
|
||||
union ZeldaUnkPB
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 Control; // 0x00 | control
|
||||
u16 Unk01; // 0x01 | unknown
|
||||
u32 SrcAddr; // 0x02 | some address
|
||||
u16 Unk04[0xC]; // 0x04 | unknown
|
||||
};
|
||||
u16 raw[16];
|
||||
};
|
||||
|
||||
class ZeldaUCode : public UCodeInterface
|
||||
{
|
||||
public:
|
||||
@@ -127,17 +20,8 @@ public:
|
||||
void HandleMail_NormalVersion(u32 mail);
|
||||
void Update() override;
|
||||
|
||||
void CopyPBsFromRAM();
|
||||
void CopyPBsToRAM();
|
||||
|
||||
void DoState(PointerWrap &p) override;
|
||||
|
||||
int *templbuffer;
|
||||
int *temprbuffer;
|
||||
|
||||
// Simple dump ...
|
||||
int DumpAFC(u8* pIn, const int size, const int srate);
|
||||
|
||||
u32 Read32()
|
||||
{
|
||||
u32 res = *(u32*)&m_buffer[m_read_offset];
|
||||
@@ -197,17 +81,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// These are the only dynamically allocated things allowed in the ucode.
|
||||
s32* m_voice_buffer;
|
||||
s16* m_resample_buffer;
|
||||
s32* m_left_buffer;
|
||||
s32* m_right_buffer;
|
||||
|
||||
// If you add variables, remember to keep DoState() and the constructor up to date.
|
||||
|
||||
s16 m_afc_coef_table[32];
|
||||
s16 m_misc_table[0x280];
|
||||
|
||||
bool m_sync_in_progress;
|
||||
u32 m_max_voice;
|
||||
u32 m_sync_flags[16];
|
||||
@@ -222,21 +95,6 @@ private:
|
||||
u32 m_current_buffer;
|
||||
u32 m_num_buffers;
|
||||
|
||||
// Those are set by command 0x1 (DsetupTable)
|
||||
u32 m_voice_pbs_addr;
|
||||
u32 m_unk_table_addr;
|
||||
u32 m_afc_coef_table_addr;
|
||||
u32 m_reverb_pbs_addr;
|
||||
|
||||
u32 m_right_buffers_addr;
|
||||
u32 m_left_buffers_addr;
|
||||
//u32 m_unkAddr;
|
||||
u32 m_pos;
|
||||
|
||||
// Only in SMG ucode
|
||||
// Set by command 0xE (DsetDMABaseAddr)
|
||||
u32 m_dma_base_addr;
|
||||
|
||||
// List, buffer management =====================
|
||||
u32 m_num_steps;
|
||||
bool m_list_in_progress;
|
||||
@@ -245,50 +103,5 @@ private:
|
||||
|
||||
u32 m_read_offset;
|
||||
|
||||
enum EMailState
|
||||
{
|
||||
WaitForMail,
|
||||
ReadingFrameSync,
|
||||
ReadingMessage,
|
||||
ReadingSystemMsg
|
||||
};
|
||||
|
||||
EMailState m_mail_state;
|
||||
u16 m_pb_mask[0x10];
|
||||
|
||||
u32 m_num_pbs;
|
||||
u32 m_pb_address; // The main param block array
|
||||
u32 m_pb_address2; // 4 smaller param blocks
|
||||
|
||||
void ExecuteList();
|
||||
|
||||
u8 *GetARAMPointer(u32 address);
|
||||
|
||||
// AFC decoder
|
||||
static void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type);
|
||||
|
||||
void ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB);
|
||||
void WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB);
|
||||
|
||||
// Voice formats
|
||||
void RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
|
||||
void RenderSynth_RectWave(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
|
||||
void RenderSynth_SawWave(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
|
||||
void RenderSynth_WaveTable(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
|
||||
|
||||
void RenderVoice_PCM8(ZeldaVoicePB& PB, s16* _Buffer, int _Size);
|
||||
void RenderVoice_PCM16(ZeldaVoicePB& PB, s16* _Buffer, int _Size);
|
||||
|
||||
void RenderVoice_AFC(ZeldaVoicePB& PB, s16* _Buffer, int _Size);
|
||||
void RenderVoice_Raw(ZeldaVoicePB& PB, s16* _Buffer, int _Size);
|
||||
|
||||
void Resample(ZeldaVoicePB &PB, int size, s16 *in, s32 *out, bool do_resample = false);
|
||||
|
||||
int ConvertRatio(int pb_ratio);
|
||||
int SizeForResampling(ZeldaVoicePB &PB, int size);
|
||||
|
||||
// Renders a voice and mixes it into LeftBuffer, RightBuffer
|
||||
void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size);
|
||||
|
||||
void MixAudio();
|
||||
};
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Core/HW/DSPHLE/UCodes/Zelda.h"
|
||||
|
||||
void ZeldaUCode::AFCdecodebuffer(const s16 *coef, const char *src, signed short *out, short *histp, short *hist2p, int type)
|
||||
{
|
||||
// First 2 nibbles are ADPCM scale etc.
|
||||
short delta = 1 << (((*src) >> 4) & 0xf);
|
||||
short idx = (*src) & 0xf;
|
||||
src++;
|
||||
|
||||
short nibbles[16];
|
||||
if (type == 9)
|
||||
{
|
||||
for (int i = 0; i < 16; i += 2)
|
||||
{
|
||||
nibbles[i + 0] = *src >> 4;
|
||||
nibbles[i + 1] = *src & 15;
|
||||
src++;
|
||||
}
|
||||
|
||||
for (auto& nibble : nibbles)
|
||||
{
|
||||
if (nibble >= 8)
|
||||
nibble = nibble - 16;
|
||||
nibble <<= 11;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In Pikmin, Dolphin's engine sound is using AFC type 5, even though such a sound is hard
|
||||
// to compare, it seems like to sound exactly like a real GC
|
||||
// In Super Mario Sunshine, you can get such a sound by talking to/jumping on anyone
|
||||
for (int i = 0; i < 16; i += 4)
|
||||
{
|
||||
nibbles[i + 0] = (*src >> 6) & 0x03;
|
||||
nibbles[i + 1] = (*src >> 4) & 0x03;
|
||||
nibbles[i + 2] = (*src >> 2) & 0x03;
|
||||
nibbles[i + 3] = (*src >> 0) & 0x03;
|
||||
src++;
|
||||
}
|
||||
|
||||
for (auto& nibble : nibbles)
|
||||
{
|
||||
if (nibble >= 2)
|
||||
nibble = nibble - 4;
|
||||
nibble <<= 13;
|
||||
}
|
||||
}
|
||||
|
||||
short hist = *histp;
|
||||
short hist2 = *hist2p;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int sample = delta * nibbles[i] + ((int)hist * coef[idx * 2]) + ((int)hist2 * coef[idx * 2 + 1]);
|
||||
sample >>= 11;
|
||||
MathUtil::Clamp(&sample, -32768, 32767);
|
||||
out[i] = sample;
|
||||
hist2 = hist;
|
||||
hist = (short)sample;
|
||||
}
|
||||
*histp = hist;
|
||||
*hist2p = hist2;
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
|
||||
#include "Core/HW/DSPHLE/UCodes/Zelda.h"
|
||||
|
||||
void ZeldaUCode::RenderSynth_RectWave(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||
{
|
||||
s64 ratio = ((s64)PB.RatioInt << 16) * 16;
|
||||
s64 TrueSamplePosition = PB.CurSampleFrac;
|
||||
|
||||
// PB.Format == 0x3 -> Rectangular Wave, 0x0 -> Square Wave
|
||||
unsigned int mask = PB.Format ? 3 : 1;
|
||||
// int shift = PB.Format ? 2 : 1; // Unused?
|
||||
|
||||
u32 pos[2] = {0, 0};
|
||||
int i = 0;
|
||||
|
||||
if (PB.KeyOff != 0)
|
||||
return;
|
||||
|
||||
if (PB.NeedsReset)
|
||||
{
|
||||
PB.RemLength = PB.Length - PB.RestartPos;
|
||||
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
|
||||
PB.ReachedEnd = 0;
|
||||
}
|
||||
|
||||
_lRestart:
|
||||
if (PB.ReachedEnd)
|
||||
{
|
||||
PB.ReachedEnd = 0;
|
||||
|
||||
if (PB.RepeatMode == 0)
|
||||
{
|
||||
PB.KeyOff = 1;
|
||||
PB.RemLength = 0;
|
||||
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PB.RestartPos = PB.LoopStartPos;
|
||||
PB.RemLength = PB.Length - PB.RestartPos;
|
||||
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
|
||||
pos[1] = 0; pos[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (i < _Size)
|
||||
{
|
||||
s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000;
|
||||
|
||||
TrueSamplePosition += (ratio >> 16);
|
||||
|
||||
_Buffer[i++] = (s32)sample;
|
||||
|
||||
(*(u64*)&pos) += ratio;
|
||||
if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
|
||||
{
|
||||
PB.ReachedEnd = 1;
|
||||
goto _lRestart;
|
||||
}
|
||||
}
|
||||
|
||||
if (PB.RemLength < pos[1])
|
||||
{
|
||||
PB.RemLength = 0;
|
||||
PB.ReachedEnd = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PB.RemLength -= pos[1];
|
||||
}
|
||||
|
||||
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
|
||||
}
|
||||
|
||||
void ZeldaUCode::RenderSynth_SawWave(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||
{
|
||||
s32 ratio = (s32)ceil((float)PB.RatioInt / 3);
|
||||
s64 pos = PB.CurSampleFrac;
|
||||
|
||||
for (int i = 0; i < _Size; i++)
|
||||
{
|
||||
pos += ratio;
|
||||
_Buffer[i] = pos & 0xFFFF;
|
||||
}
|
||||
|
||||
PB.CurSampleFrac = pos & 0xFFFF;
|
||||
}
|
||||
|
||||
void ZeldaUCode::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||
{
|
||||
// TODO: Header, footer
|
||||
for (int i = 0; i < _Size; i++)
|
||||
_Buffer[i] = (s32)PB.RatioInt;
|
||||
}
|
||||
|
||||
// A piece of code from LLE so we can see how the wrap register affects the sound
|
||||
|
||||
inline u16 AddValueToReg(u32 ar, s32 ix)
|
||||
{
|
||||
u32 wr = 0x3f;
|
||||
u32 mx = (wr | 1) << 1;
|
||||
u32 nar = ar + ix;
|
||||
u32 dar = (nar ^ ar ^ ix) & mx;
|
||||
|
||||
if (ix >= 0)
|
||||
{
|
||||
if (dar > wr) //overflow
|
||||
nar -= wr + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask
|
||||
nar += wr + 1;
|
||||
}
|
||||
return nar;
|
||||
}
|
||||
|
||||
void ZeldaUCode::RenderSynth_WaveTable(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||
{
|
||||
u16 address;
|
||||
|
||||
switch (PB.Format)
|
||||
{
|
||||
default:
|
||||
case 0x0004:
|
||||
address = 0x140;
|
||||
break;
|
||||
|
||||
case 0x0007:
|
||||
address = 0x100;
|
||||
break;
|
||||
|
||||
case 0x000b:
|
||||
address = 0x180;
|
||||
break;
|
||||
|
||||
case 0x000c:
|
||||
address = 0x1c0;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Resample this!
|
||||
INFO_LOG(DSPHLE, "Synthesizing the incomplete format 0x%04x", PB.Format);
|
||||
|
||||
u64 ACC0 = PB.CurSampleFrac << 6;
|
||||
|
||||
ACC0 &= 0xffff003fffffULL;
|
||||
|
||||
address = AddValueToReg(address, ((ACC0 >> 16) & 0xffff));
|
||||
ACC0 &= 0xffff0000ffffULL;
|
||||
|
||||
for (int i = 0; i < 0x50; i++)
|
||||
{
|
||||
_Buffer[i] = m_misc_table[address];
|
||||
|
||||
ACC0 += PB.RatioInt << 5;
|
||||
address = AddValueToReg(address, ((ACC0 >> 16) & 0xffff));
|
||||
|
||||
ACC0 &= 0xffff0000ffffULL;
|
||||
}
|
||||
|
||||
ACC0 += address << 16;
|
||||
PB.CurSampleFrac = (ACC0 >> 6) & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user