summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2014-12-22 02:22:26 +0100
committerPierre Bourdon <delroth@gmail.com>2015-08-14 16:01:31 +0200
commitc033395e28a3fc14a9d481b415bed30b657cdff3 (patch)
tree5261114754bd8d3f526205995f8cb5267e810041 /Source/Core
parent8b9b9f033abdc36d62c4933fe8cde7c64d1d2fb2 (diff)
Zelda HLE: Introduce behavior flags to handle UCode version differences.
MAKE_DOLBY_LOUDER solves some of the volume issues that were happening in Zelda Twilight Princess and SMG1.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp85
-rw-r--r--Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h13
2 files changed, 66 insertions, 32 deletions
diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp
index 66b0dc7e31..8d28775350 100644
--- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp
+++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp
@@ -2,32 +2,59 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-// Games that use this UCode (exhaustive list):
-// * Animal Crossing (type ????, CRC ????)
-// * Donkey Kong Jungle Beat (type ????, CRC ????)
-// * IPL (type ????, CRC ????)
-// * Luigi's Mansion (type ????, CRC ????)
-// * Mario Kart: Double Dash!! (type ????, CRC ????)
-// * Pikmin (type ????, CRC ????)
-// * Pikmin 2 (type ????, CRC ????)
-// * Super Mario Galaxy (type Wii-DAC, CRC D643001F)
-// * Super Mario Galaxy 2 (type ????, CRC ????)
-// * Super Mario Sunshine (type ????, CRC ????)
-// * The Legend of Zelda: Four Swords Adventures (type ????, CRC ????)
-// * The Legend of Zelda: The Wind Waker (type DAC, CRC 86840740)
-// * The Legend of Zelda: Twilight Princess / GC (type DAC, CRC 6CA33A6D)
-// * The Legend of Zelda: Twilight Princess / Wii (type ????, CRC ????)
-
#include "Core/ConfigManager.h"
#include "Core/HW/DSPHLE/MailHandler.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
#include "Core/HW/DSPHLE/UCodes/Zelda.h"
+// These flags modify the behavior of the HLE implementation based on the UCode
+// version. When introducing a new flag, please recheck the behavior of each
+// UCode version.
+enum ZeldaUCodeFlag
+{
+ // UCode for Wii where no ARAM is present. Instead of using ARAM, DMAs from
+ // MRAM are used to transfer sound data.
+ NO_ARAM = 0x00000001,
+
+ // Multiply by two the computed Dolby positional volumes. Some UCodes do
+ // not do that (Zelda TWW for example), others do (Zelda TP, SMG).
+ MAKE_DOLBY_LOUDER = 0x00000002,
+};
+
+static const std::map<u32, u32> UCODE_FLAGS = {
+ // The Legend of Zelda: The Wind Waker.
+ { 0x86840740, 0 },
+ // The Legend of Zelda: Twilight Princess / GC.
+ { 0x6CA33A6D, MAKE_DOLBY_LOUDER },
+ // Super Mario Galaxy.
+ { 0xD643001F, NO_ARAM | MAKE_DOLBY_LOUDER },
+
+ // TODO: Other games that use this UCode (exhaustive list):
+ // * Animal Crossing (type ????, CRC ????)
+ // * Donkey Kong Jungle Beat (type ????, CRC ????)
+ // * IPL (type ????, CRC ????)
+ // * Luigi's Mansion (type ????, CRC ????)
+ // * Mario Kart: Double Dash!! (type ????, CRC ????)
+ // * Pikmin (type ????, CRC ????)
+ // * Pikmin 2 (type ????, CRC ????)
+ // * Super Mario Galaxy 2 (type ????, CRC ????)
+ // * Super Mario Sunshine (type ????, CRC ????)
+ // * The Legend of Zelda: Four Swords Adventures (type ????, CRC ????)
+ // * The Legend of Zelda: Twilight Princess / Wii (type ????, CRC ????)
+};
+
ZeldaUCode::ZeldaUCode(DSPHLE *dsphle, u32 crc)
: UCodeInterface(dsphle, crc)
{
m_mail_handler.PushMail(DSP_INIT, true);
m_mail_handler.PushMail(0xF3551111); // handshake
+
+ auto it = UCODE_FLAGS.find(crc);
+ if (it == UCODE_FLAGS.end())
+ PanicAlert("No flags definition found for Zelda CRC %08x", crc);
+
+ m_flags = it->second;
+ m_renderer.SetFlags(m_flags);
}
ZeldaUCode::~ZeldaUCode()
@@ -50,6 +77,7 @@ u32 ZeldaUCode::GetUpdateMs()
void ZeldaUCode::DoState(PointerWrap &p)
{
+ p.Do(m_flags);
p.Do(m_mail_current_state);
p.Do(m_mail_expected_cmd_mails);
@@ -271,7 +299,7 @@ void ZeldaUCode::RunPendingCommands()
// because the Wii does not have an ARAM, so it simulates it with MRAM
// and DMAs.
case 0x0E:
- if (!IsWiiDAC())
+ if (!(m_flags & NO_ARAM))
PanicAlert("Setting base ARAM addr on non Wii DAC.");
m_renderer.SetARAMBaseAddr(Read32());
SendCommandAck(CommandAck::STANDARD, sync);
@@ -779,11 +807,12 @@ void ZeldaAudioRenderer::AddVoice(u16 voice_id)
s16 front_volume = m_sine_table[vpb.GetDolbyVoiceY() ^ 0x7F];
// Compute volume for each quadrant.
+ u16 shift_factor = (m_flags & MAKE_DOLBY_LOUDER) ? 15 : 16;
s16 quadrant_volumes[4] = {
- (s16)((left_volume * front_volume) >> 16),
- (s16)((left_volume * back_volume) >> 16),
- (s16)((right_volume * front_volume) >> 16),
- (s16)((right_volume * back_volume) >> 16),
+ (s16)((left_volume * front_volume) >> shift_factor),
+ (s16)((left_volume * back_volume) >> shift_factor),
+ (s16)((right_volume * front_volume) >> shift_factor),
+ (s16)((right_volume * back_volume) >> shift_factor),
};
// Compute the volume delta for each sample to match the difference
@@ -791,19 +820,19 @@ void ZeldaAudioRenderer::AddVoice(u16 voice_id)
s16 delta = vpb.dolby_volume_target - vpb.dolby_volume_current;
s16 volume_deltas[4];
for (size_t i = 0; i < 4; ++i)
- volume_deltas[i] = ((u16)quadrant_volumes[i] * delta) >> 16;
+ volume_deltas[i] = ((u16)quadrant_volumes[i] * delta) >> shift_factor;
// Apply master volume to each quadrant.
for (size_t i = 0; i < 4; ++i)
- quadrant_volumes[i] = (quadrant_volumes[i] * vpb.dolby_volume_current) >> 16;
+ quadrant_volumes[i] = (quadrant_volumes[i] * vpb.dolby_volume_current) >> shift_factor;
// Compute reverb volume and ramp deltas.
s16 reverb_volumes[4], reverb_volume_deltas[4];
- s16 reverb_volume_factor = (vpb.dolby_volume_current * vpb.dolby_reverb_factor) >> 15;
+ s16 reverb_volume_factor = (vpb.dolby_volume_current * vpb.dolby_reverb_factor) >> (shift_factor - 1);
for (size_t i = 0; i < 4; ++i)
{
- reverb_volumes[i] = (quadrant_volumes[i] * reverb_volume_factor) >> 15;
- reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> 16;
+ reverb_volumes[i] = (quadrant_volumes[i] * reverb_volume_factor) >> shift_factor;
+ reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> shift_factor;
}
struct {
@@ -1351,6 +1380,7 @@ void ZeldaAudioRenderer::DownloadRawSamplesFromMRAM(
void ZeldaAudioRenderer::DoState(PointerWrap& p)
{
+ p.Do(m_flags);
p.Do(m_prepared);
p.Do(m_output_lbuf_addr);
@@ -1373,9 +1403,10 @@ void ZeldaAudioRenderer::DoState(PointerWrap& p)
p.Do(m_sine_table);
p.Do(m_afc_coeffs);
+ p.Do(m_aram_base_addr);
p.Do(m_vpb_base_addr);
-
p.Do(m_reverb_pb_base_addr);
+
p.Do(m_reverb_pb_frames_count);
p.Do(m_buf_unk0_reverb_last8);
p.Do(m_buf_unk1_reverb_last8);
diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h
index dd647e9712..e9126ef8a8 100644
--- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h
+++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h
@@ -15,6 +15,7 @@ public:
void AddVoice(u16 voice_id);
void FinalizeFrame();
+ void SetFlags(u32 flags) { m_flags = flags; }
void SetSineTable(std::array<s16, 0x80>&& sine_table) { m_sine_table = sine_table; }
void SetConstPatterns(std::array<s16, 0x100>&& patterns) { m_const_patterns = patterns; }
void SetResamplingCoeffs(std::array<s16, 0x100>&& coeffs) { m_resampling_coeffs = coeffs; }
@@ -31,6 +32,9 @@ public:
private:
struct VPB;
+ // See Zelda.cpp for the list of possible flags.
+ u32 m_flags;
+
// Utility functions for audio operations.
// Apply volume to a buffer. The volume is a fixed point integer, usually
@@ -189,12 +193,11 @@ public:
void DoState(PointerWrap &p) override;
- bool IsWiiDAC() const
- {
- return m_crc == 0xd643001f;
- }
-
private:
+ // Flags that alter the behavior of the UCode. See Zelda.cpp for complete
+ // list and explanation.
+ u32 m_flags;
+
// UCode state machine. The control flow in the Zelda UCode family is quite
// complex, using interrupt handlers heavily to handle incoming messages
// which, depending on the type, get handled immediately or are queued in a