diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 636d8fa928..207743bbd0 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -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 diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index eaba8a5f96..335d505c62 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -108,9 +108,6 @@ - - - diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index b35c0caa9c..92d88bc479 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -336,15 +336,6 @@ HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes - - HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes - - - HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes - - - HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes - HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index c18b8a6ce9..72a8b0d42e 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -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); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h index 6785f52b70..5f65008c35 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h @@ -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(); }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaADPCM.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaADPCM.cpp deleted file mode 100644 index 52e7ae44bb..0000000000 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaADPCM.cpp +++ /dev/null @@ -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; -} diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaSynth.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaSynth.cpp deleted file mode 100644 index 054efeaddd..0000000000 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaSynth.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include - -#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; -} - - diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaVoice.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaVoice.cpp deleted file mode 100644 index e6db1b0d85..0000000000 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ZeldaVoice.cpp +++ /dev/null @@ -1,790 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include - -#include "Common/CommonFuncs.h" -#include "Common/MathUtil.h" - -#include "Core/HW/DSP.h" -#include "Core/HW/Memmap.h" -#include "Core/HW/DSPHLE/UCodes/UCodes.h" -#include "Core/HW/DSPHLE/UCodes/Zelda.h" - -void ZeldaUCode::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB) -{ - u16 *memory = (u16*)Memory::GetPointer(_Addr); - - // Perform byteswap - for (int i = 0; i < (0x180 / 2); i++) - ((u16*)&PB)[i] = Common::swap16(memory[i]); - - // Word swap all 32-bit variables. - PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); - PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); - PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); - // Read only part - PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16); - PB.Length = (PB.Length << 16) | (PB.Length >> 16); - PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16); - PB.UnkAddr = (PB.UnkAddr << 16) | (PB.UnkAddr >> 16); -} - -void ZeldaUCode::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB) -{ - u16 *memory = (u16*)Memory::GetPointer(_Addr); - - // Word swap all 32-bit variables. - PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); - PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); - PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); - - // Perform byteswap - // Only the first 0x100 bytes are written back - for (int i = 0; i < (0x100 / 2); i++) - memory[i] = Common::swap16(((u16*)&PB)[i]); -} - -int ZeldaUCode::ConvertRatio(int pb_ratio) -{ - return pb_ratio * 16; -} - -int ZeldaUCode::SizeForResampling(ZeldaVoicePB &PB, int size) -{ - // This is the little calculation at the start of every sample decoder - // in the ucode. - return (PB.CurSampleFrac + size * ConvertRatio(PB.RatioInt)) >> 16; -} - -// Simple resampler, linear interpolation. -// Any future state should be stored in PB.raw[0x3c to 0x3f]. -// In must point 4 samples into a buffer. -void ZeldaUCode::Resample(ZeldaVoicePB &PB, int size, s16 *in, s32 *out, bool do_resample) -{ - if (!do_resample) - { - memcpy(out, in, size * sizeof(int)); - return; - } - - for (int i = 0; i < 4; i++) - { - in[i - 4] = (s16)PB.ResamplerOldData[i]; - } - - int ratio = ConvertRatio(PB.RatioInt); - int in_size = SizeForResampling(PB, size); - - int position = PB.CurSampleFrac; - for (int i = 0; i < size; i++) - { - int int_pos = (position >> 16); - int frac = ((position & 0xFFFF) >> 1); - out[i] = (in[int_pos - 3] * (frac ^ 0x7FFF) + in[int_pos - 2] * frac) >> 15; - position += ratio; - } - - for (int i = 0; i < 4; i++) - { - PB.ResamplerOldData[i] = (u16)(s16)in[in_size - 4 + i]; - } - PB.CurSampleFrac = position & 0xFFFF; -} - -static void UpdateSampleCounters10(ZeldaVoicePB &PB) -{ - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); - PB.ReachedEnd = 0; -} - -void ZeldaUCode::RenderVoice_PCM16(ZeldaVoicePB &PB, s16 *_Buffer, int _Size) -{ - int _RealSize = SizeForResampling(PB, _Size); - u32 rem_samples = _RealSize; - if (PB.KeyOff) - goto clear_buffer; - if (PB.NeedsReset) - { - UpdateSampleCounters10(PB); - for (int i = 0; i < 4; i++) - PB.ResamplerOldData[i] = 0; // Doesn't belong here, but dunno where to do it. - } - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; -reached_end: - if (!PB.RepeatMode) - { - // One shot - play zeros the rest of the buffer. -clear_buffer: - for (u32 i = 0; i < rem_samples; i++) - *_Buffer++ = 0; - PB.KeyOff = 1; - return; - } - else - { - PB.RestartPos = PB.LoopStartPos; - UpdateSampleCounters10(PB); - } - } - // SetupAccelerator - const s16 *read_ptr = (s16*)GetARAMPointer(PB.CurAddr); - if (PB.RemLength < (u32)rem_samples) - { - // finish-up loop - for (u32 i = 0; i < PB.RemLength; i++) - *_Buffer++ = Common::swap16(*read_ptr++); - rem_samples -= PB.RemLength; - goto reached_end; - } - // main render loop - for (u32 i = 0; i < rem_samples; i++) - *_Buffer++ = Common::swap16(*read_ptr++); - - PB.RemLength -= rem_samples; - if (PB.RemLength == 0) - PB.ReachedEnd = 1; - PB.CurAddr += rem_samples << 1; -} - -static void UpdateSampleCounters8(ZeldaVoicePB &PB) -{ - PB.RemLength = PB.Length - PB.RestartPos; - PB.CurAddr = PB.StartAddr + PB.RestartPos; - PB.ReachedEnd = 0; -} - -void ZeldaUCode::RenderVoice_PCM8(ZeldaVoicePB &PB, s16 *_Buffer, int _Size) -{ - int _RealSize = SizeForResampling(PB, _Size); - u32 rem_samples = _RealSize; - if (PB.KeyOff) - goto clear_buffer; - if (PB.NeedsReset) - { - UpdateSampleCounters8(PB); - for (int i = 0; i < 4; i++) - PB.ResamplerOldData[i] = 0; // Doesn't belong here, but dunno where to do it. - } - if (PB.ReachedEnd) - { -reached_end: - PB.ReachedEnd = 0; - if (!PB.RepeatMode) - { - // One shot - play zeros the rest of the buffer. -clear_buffer: - for (u32 i = 0; i < rem_samples; i++) - *_Buffer++ = 0; - PB.KeyOff = 1; - return; - } - else - { - PB.RestartPos = PB.LoopStartPos; - UpdateSampleCounters8(PB); - } - } - - // SetupAccelerator - const s8 *read_ptr = (s8*)GetARAMPointer(PB.CurAddr); - if (PB.RemLength < (u32)rem_samples) - { - // finish-up loop - for (u32 i = 0; i < PB.RemLength; i++) - *_Buffer++ = (s8)(*read_ptr++) << 8; - rem_samples -= PB.RemLength; - goto reached_end; - } - // main render loop - for (u32 i = 0; i < rem_samples; i++) - *_Buffer++ = (s8)(*read_ptr++) << 8; - - PB.RemLength -= rem_samples; - if (PB.RemLength == 0) - PB.ReachedEnd = 1; - PB.CurAddr += rem_samples; -} - -template -void PrintObject(const T &Obj) -{ - std::stringstream ss; - u8 *o = (u8 *)&Obj; - - // If this miscompiles, adjust the size of - // ZeldaVoicePB to 0x180 bytes (0xc0 shorts). - static_assert(sizeof(ZeldaVoicePB) == 0x180, "ZeldaVoicePB incorrectly defined."); - - ss << std::hex; - for (size_t i = 0; i < sizeof(T); i++) - { - if ((i & 1) == 0) - ss << ' '; - ss.width(2); - ss.fill('0'); - ss << Common::swap16(o[i]); - } - - DEBUG_LOG(DSPHLE, "AFC PB:%s", ss.str().c_str()); -} - -void ZeldaUCode::RenderVoice_AFC(ZeldaVoicePB &PB, s16 *_Buffer, int _Size) -{ - // TODO: Compare mono, stereo and surround samples -#if defined DEBUG || defined DEBUGFAST - PrintObject(PB); -#endif - - int _RealSize = SizeForResampling(PB, _Size); - - // initialize "decoder" if the sample is played the first time - if (PB.NeedsReset != 0) - { - // This is 0717_ReadOutPBStuff - // increment 4fb - // zelda: - // perhaps init or "has played before" - PB.CurBlock = 0x00; - PB.YN2 = 0x00; // history1 - PB.YN1 = 0x00; // history2 - - // Length in samples. - PB.RemLength = PB.Length; - // Copy ARAM addr from r to rw area. - PB.CurAddr = PB.StartAddr; - PB.ReachedEnd = 0; - PB.CurSampleFrac = 0; - - for (int i = 0; i < 4; i++) - PB.ResamplerOldData[i] = 0; - } - - if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above - { - for (int i = 0; i < _RealSize; i++) - *_Buffer++ = 0; - return; - } - - // Round upwards how many samples we need to copy, 0759 - // u32 frac = NumberOfSamples & 0xF; - // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction - - const u8 *source; - u32 ram_mask = 1024 * 1024 * 16 - 1; - if (IsDMAVersion()) - { - source = Memory::GetPointer(m_dma_base_addr); - ram_mask = 1024 * 1024 * 64 - 1; - } - else - { - source = DSP::GetARAMPtr(); - } - - int sampleCount = 0; // must be above restart. - -restart: - if (PB.ReachedEnd) - { - PB.ReachedEnd = 0; - - if ((PB.RepeatMode == 0) || (PB.StopOnSilence != 0)) - { - PB.KeyOff = 1; - PB.RemLength = 0; - PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; - - while (sampleCount < _RealSize) - _Buffer[sampleCount++] = 0; - return; - } - else - { - //AFC looping - // The loop start pos is incorrect? (Fixed?), so samples will loop a bit wrong. - // this fixes the intro music in ZTP. - PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; - // see DSP_UC_Zelda.txt line 2817 - PB.CurAddr = ((((((PB.LoopStartPos >> 4) & 0xffff0000)*PB.Format)<<16)+ - (((PB.LoopStartPos >> 4) & 0xffff)*PB.Format))+PB.StartAddr) & 0xffffffff; - - // Hmm, this shouldn't be reversed .. or should it? Is it different between versions of the ucode? - // -> it has to be reversed in ZTP, otherwise intro music is broken... - PB.YN1 = PB.LoopYN2; - PB.YN2 = PB.LoopYN1; - } - } - - short outbuf[16] = {0}; - u16 prev_yn1 = PB.YN1; - u16 prev_yn2 = PB.YN2; - u32 prev_addr = PB.CurAddr; - - // Prefill the decode buffer. - AFCdecodebuffer(m_afc_coef_table, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); - PB.CurAddr += PB.Format; // 9 or 5 - - u32 SamplePosition = PB.Length - PB.RemLength; - while (sampleCount < _RealSize) - { - _Buffer[sampleCount] = outbuf[SamplePosition & 15]; - sampleCount++; - - SamplePosition++; - PB.RemLength--; - if (PB.RemLength == 0) - { - PB.ReachedEnd = 1; - goto restart; - } - - // Need new samples! - if ((SamplePosition & 15) == 0) - { - prev_yn1 = PB.YN1; - prev_yn2 = PB.YN2; - prev_addr = PB.CurAddr; - - AFCdecodebuffer(m_afc_coef_table, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); - PB.CurAddr += PB.Format; // 9 or 5 - } - } - - // Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block. - // We'll re-decode it the next time around. - PB.YN2 = prev_yn2; - PB.YN1 = prev_yn1; - PB.CurAddr = prev_addr; - - PB.NeedsReset = 0; - // PB.CurBlock = 0x10 - (PB.LoopStartPos & 0xf); - // write back - // NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction - - // i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples... - // just decrement them with the number of samples you have played - // and increase the ARAM Offset in pTest[0x38], pTest[0x39] - - // end of block (Zelda 03b2) -} - -void Decoder21_ReadAudio(ZeldaVoicePB &PB, int size, s16 *_Buffer); - -// Researching what's actually inside the mysterious 0x21 case -// 0x21 seems to really just be reading raw 16-bit audio from RAM (not ARAM). -// The rules seem to be quite different, though. -// It's used for streaming, not for one-shot or looped sample playback. -void ZeldaUCode::RenderVoice_Raw(ZeldaVoicePB &PB, s16 *_Buffer, int _Size) -{ - // Decoder0x21 starts here. - u32 _RealSize = SizeForResampling(PB, _Size); - - // Decoder0x21Core starts here. - u32 AX0 = _RealSize; - - // ERROR_LOG(DSPHLE, "0x21 volume mode: %i , stop: %i ", PB.VolumeMode, PB.StopOnSilence); - - // The PB.StopOnSilence check is a hack, we should check the buffers and enter this - // only when the buffer is completely 0 (i.e. when the music has finished fading out) - if (PB.StopOnSilence || PB.RemLength < (u32)_RealSize) - { - WARN_LOG(DSPHLE, "Raw: END"); - // Let's ignore this entire case since it doesn't seem to happen - // in Zelda, since Length is set to 0xF0000000 - // blah - // blah - // readaudio - // blah - PB.RemLength = 0; - PB.KeyOff = 1; - } - - PB.RemLength -= _RealSize; - - u64 ACC0 = (u32)(PB.raw[0x8a ^ 1] << 16); // 0x8a 0ad5, yes it loads a, not b - u64 ACC1 = (u32)(PB.raw[0x34 ^ 1] << 16); // 0x34 - - // ERROR_LOG(DSPHLE, "%08x %08x", (u32)ACC0, (u32)ACC1); - - ACC0 -= ACC1; - - PB.Unk36[0] = (u16)(ACC0 >> 16); - - ACC0 -= AX0 << 16; - - if ((s64)ACC0 < 0) - { - // ERROR_LOG(DSPHLE, "Raw loop: ReadAudio size = %04x 34:%04x %08x", PB.Unk36[0], PB.raw[0x34 ^ 1], (int)ACC0); - Decoder21_ReadAudio(PB, PB.Unk36[0], _Buffer); - - ACC0 = -(s64)ACC0; - _Buffer += PB.Unk36[0]; - - PB.raw[0x34 ^ 1] = 0; - - PB.StartAddr = PB.LoopStartPos; - - Decoder21_ReadAudio(PB, (int)(ACC0 >> 16), _Buffer); - return; - } - - Decoder21_ReadAudio(PB, _RealSize, _Buffer); -} - -void Decoder21_ReadAudio(ZeldaVoicePB &PB, int size, s16* _Buffer) -{ - // 0af6 - if (!size) - return; - -#if 0 - // 0afa - u32 AX1 = (PB.RestartPos >> 16) & 1; // PB.raw[0x34], except that it's part of a dword - // 0b00 - Eh, WTF. - u32 ACC0 = PB.StartAddr + ((PB.RestartPos >> 16) << 1) - 2*AX1; - u32 ACC1 = (size << 16) + 0x20000; - // All this trickery, and more, seems to be to align the DMA, which - // we really don't care about. So let's skip it. See the #else. - -#else - // ERROR_LOG(DSPHLE, "ReadAudio: %08x %08x", PB.StartAddr, PB.raw[0x34 ^ 1]); - u32 ACC0 = PB.StartAddr + (PB.raw[0x34 ^ 1] << 1); - u32 ACC1 = (size << 16); -#endif - // ACC0 is the address - // ACC1 is the read size - - const u16* src = (u16*)Memory::GetPointer(ACC0 & Memory::RAM_MASK); - - for (u32 i = 0; i < (ACC1 >> 16); i++) - { - _Buffer[i] = Common::swap16(src[i]); - } - - PB.raw[0x34 ^ 1] += size; -} - - -void ZeldaUCode::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) -{ - if (PB.IsBlank) - { - s32 sample = (s32)(s16)PB.FixedSample; - for (int i = 0; i < _Size; i++) - m_voice_buffer[i] = sample; - - goto ContinueWithBlock; // Yes, a goto. Yes, it's evil, but it makes the flow look much more like the DSP code. - } - - // XK: Use this to disable MIDI music (GREAT for testing). Also kills some sound FX. - //if (PB.SoundType == 0x0d00) - //{ - // PB.NeedsReset = 0; - // return; - //} - - // The Resample calls actually don't resample yet. - - // ResampleBuffer corresponds to 0x0580 in ZWW ucode. - // VoiceBuffer corresponds to 0x0520. - - // First jump table at ZWW: 2a6 - switch (PB.Format) - { - case 0x0005: // AFC with extra low bitrate (32:5 compression). - case 0x0009: // AFC with normal bitrate (32:9 compression). - RenderVoice_AFC(PB, m_resample_buffer + 4, _Size); - Resample(PB, _Size, m_resample_buffer + 4, m_voice_buffer, true); - break; - - case 0x0008: // PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD + very little in Zelda WW. - RenderVoice_PCM8(PB, m_resample_buffer + 4, _Size); - Resample(PB, _Size, m_resample_buffer + 4, m_voice_buffer, true); - break; - - case 0x0010: // PCM16 - normal PCM 16-bit audio. - RenderVoice_PCM16(PB, m_resample_buffer + 4, _Size); - Resample(PB, _Size, m_resample_buffer + 4, m_voice_buffer, true); - break; - - case 0x0020: - // Normally, this shouldn't resample, it should just decode directly - // to the output buffer. However, (if we ever see this sound type), we'll - // have to resample anyway since we're running at a different sample rate. - - RenderVoice_Raw(PB, m_resample_buffer + 4, _Size); - Resample(PB, _Size, m_resample_buffer + 4, m_voice_buffer, true); - break; - - case 0x0021: - // Raw sound from RAM. Important for Zelda WW. Cutscenes use the music - // to let the game know they ended - RenderVoice_Raw(PB, m_resample_buffer + 4, _Size); - Resample(PB, _Size, m_resample_buffer + 4, m_voice_buffer, true); - break; - - default: - // Second jump table - // TODO: Cases to find examples of: - // -0x0002 - // -0x0003 - // -0x0006 - // -0x000a - switch (PB.Format) - { - // Synthesized sounds - case 0x0003: WARN_LOG(DSPHLE, "PB Format 0x03 used!"); - case 0x0000: // Example: Magic meter filling up in ZWW - RenderSynth_RectWave(PB, m_voice_buffer, _Size); - break; - - case 0x0001: // Example: "Denied" sound when trying to pull out a sword indoors in ZWW - RenderSynth_SawWave(PB, m_voice_buffer, _Size); - break; - - case 0x0006: - WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); - RenderSynth_Constant(PB, m_voice_buffer, _Size); - break; - - // These are more "synth" formats - square wave, saw wave etc. - case 0x0002: - WARN_LOG(DSPHLE, "PB Format 0x02 used!"); - break; - - case 0x0004: // Example: Big Pikmin onion mothership landing/building a bridge in Pikmin - case 0x0007: // Example: "success" SFX in Pikmin 1, Pikmin 2 in a cave, not sure what sound it is. - case 0x000b: // Example: SFX in area selection menu in Pikmin - case 0x000c: // Example: beam of death/yellow force-field in Temple of the Gods, ZWW - RenderSynth_WaveTable(PB, m_voice_buffer, _Size); - break; - - default: - // TODO: Implement general decoder here - memset(m_voice_buffer, 0, _Size * sizeof(s32)); - ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format); - break; - } - } - -ContinueWithBlock: - - if (PB.FilterEnable) - { // 0x04a8 - for (int i = 0; i < _Size; i++) - { - // TODO: Apply filter from ZWW: 0c84_FilterBufferInPlace - } - } - - for (int i = 0; i < _Size; i++) - { - // TODO? - } - - // Apply volume. There are two different modes. - if (PB.VolumeMode != 0) - { - // Complex volume mode. Let's see what we can do. - if (PB.StopOnSilence) - { - PB.raw[0x2b] = PB.raw[0x2a] >> 1; - if (PB.raw[0x2b] == 0) - { - PB.KeyOff = 1; - } - } - - short AX0L = PB.raw[0x28] >> 8; - short AX0H = PB.raw[0x28] & 0x7F; - short AX1L = AX0L ^ 0x7F; - short AX1H = AX0H ^ 0x7F; - AX0L = m_misc_table[0x200 + AX0L]; - AX0H = m_misc_table[0x200 + AX0H]; - AX1L = m_misc_table[0x200 + AX1L]; - AX1H = m_misc_table[0x200 + AX1H]; - - short b00[20]; - b00[0] = AX1L * AX1H >> 16; - b00[1] = AX0L * AX1H >> 16; - b00[2] = AX0H * AX1L >> 16; - b00[3] = AX0L * AX0H >> 16; - - for (int i = 0; i < 4; i++) - { - b00[i + 4] = (s16)b00[i] * (s16)PB.raw[0x2a] >> 16; - } - - int prod = ((s16)PB.raw[0x2a] * (s16)PB.raw[0x29] * 2) >> 16; - for (int i = 0; i < 4; i++) - { - b00[i + 8] = (s16)b00[i + 4] * prod; - } - - // ZWW 0d34 - - int diff = (s16)PB.raw[0x2b] - (s16)PB.raw[0x2a]; - PB.raw[0x2a] = PB.raw[0x2b]; - - for (int i = 0; i < 4; i++) - { - b00[i + 0xc] = (unsigned short)b00[i] * diff >> 16; - } - - for (int i = 0; i < 4; i++) - { - b00[i + 0x10] = (s16)b00[i + 0xc] * PB.raw[0x29]; - } - - for (int count = 0; count < 8; count++) - { - // The 8 buffers to mix to: 0d00, 0d60, 0f40 0ca0 0e80 0ee0 0c00 0c50 - // We just mix to the first two and call it stereo :p - int value = b00[0x4 + count]; - //int delta = b00[0xC + count] << 11; // Unused? - - int ramp = value << 16; - for (int i = 0; i < _Size; i++) - { - int unmixed_audio = m_voice_buffer[i]; - switch (count) - { - case 0: _LeftBuffer[i] += (u64)unmixed_audio * ramp >> 29; break; - case 1: _RightBuffer[i] += (u64)unmixed_audio * ramp >> 29; break; - } - } - } - } - else - { - // ZWW 0355 - if (PB.StopOnSilence) - { - int sum = 0; - int addr = 0x0a; - for (int i = 0; i < 6; i++) - { - u16 value = PB.raw[addr]; - addr--; - value >>= 1; - PB.raw[addr] = value; - sum += value; - addr += 5; - } - - if (sum == 0) - { - PB.KeyOff = 1; - } - } - - // Seems there are 6 temporary output buffers. - for (int count = 0; count < 6; count++) - { - int addr = 0x08; - - // we'll have to keep a map of buffers I guess... - u16 dest_buffer_address = PB.raw[addr++]; - - bool mix = dest_buffer_address ? true : false; - - u16 vol2 = PB.raw[addr++]; - u16 vol1 = PB.raw[addr++]; - - int delta = (vol2 - vol1) << 11; - - addr--; - - u32 ramp = vol1 << 16; - if (mix) - { - // 0ca9_RampedMultiplyAddBuffer - for (int i = 0; i < _Size; i++) - { - int value = m_voice_buffer[i]; - - // TODO - add to buffer specified by dest_buffer_address - switch (count) - { - // These really should be 32. - case 0: _LeftBuffer[i] += (u64)value * ramp >> 29; break; - case 1: _RightBuffer[i] += (u64)value * ramp >> 29; break; - } - - if (((i & 1) == 0) && i < 64) - { - ramp += delta; - } - } - if (_Size < 32) - { - ramp += delta * (_Size - 32); - } - } - // Update the PB with the volume actually reached. - PB.raw[addr++] = ramp >> 16; - - addr++; - } - } - // 03b2, this is the reason of using PB.NeedsReset. Seems to be necessary for SMG, and maybe other games. - if (PB.IsBlank == 0) - { - PB.NeedsReset = 0; - } -} - -void ZeldaUCode::MixAudio() -{ - const int BufferSamples = 5 * 16; - - // Final mix buffers - memset(m_left_buffer, 0, BufferSamples * sizeof(s32)); - memset(m_right_buffer, 0, BufferSamples * sizeof(s32)); - - // For each PB... - for (u32 i = 0; i < m_num_voices; i++) - { - if (!IsLightVersion()) - { - u32 flags = m_sync_flags[(i >> 4) & 0xF]; - if (!(flags & 1 << (15 - (i & 0xF)))) - continue; - } - - ZeldaVoicePB pb; - ReadVoicePB(m_voice_pbs_addr + (i * 0x180), pb); - - if (pb.Status == 0) - continue; - if (pb.KeyOff != 0) - continue; - - RenderAddVoice(pb, m_left_buffer, m_right_buffer, BufferSamples); - WritebackVoicePB(m_voice_pbs_addr + (i * 0x180), pb); - } - - // Post processing, final conversion. - s16* left_buffer = (s16*)HLEMemory_Get_Pointer(m_left_buffers_addr); - s16* right_buffer = (s16*)HLEMemory_Get_Pointer(m_right_buffers_addr); - left_buffer += m_current_buffer * BufferSamples; - right_buffer += m_current_buffer * BufferSamples; - for (int i = 0; i < BufferSamples; i++) - { - s32 left = m_left_buffer[i]; - s32 right = m_right_buffer[i]; - - MathUtil::Clamp(&left, -32768, 32767); - left_buffer[i] = Common::swap16((short)left); - - MathUtil::Clamp(&right, -32768, 32767); - right_buffer[i] = Common::swap16((short)right); - } -}