CDROM: Apply volume on output not sector read
Fixes audio starting too late in Mega Man Legends.
This commit is contained in:
parent
37ec1dd7e4
commit
4441bb1a91
|
@ -527,7 +527,18 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
||||||
case 11:
|
case 11:
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Audio volume apply changes <- 0x%02X", value);
|
Log_DebugPrintf("Audio volume apply changes <- 0x%02X", value);
|
||||||
m_adpcm_muted = ConvertToBoolUnchecked(value & u8(0x01));
|
|
||||||
|
const bool adpcm_muted = ConvertToBoolUnchecked(value & u8(0x01));
|
||||||
|
if (adpcm_muted != m_adpcm_muted ||
|
||||||
|
(value & 0x20 && std::memcmp(m_cd_audio_volume_matrix.data(), m_next_cd_audio_volume_matrix.data(),
|
||||||
|
sizeof(m_cd_audio_volume_matrix)) != 0))
|
||||||
|
{
|
||||||
|
if (HasPendingDiscEvent())
|
||||||
|
m_drive_event->InvokeEarly();
|
||||||
|
g_spu.GeneratePendingSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_adpcm_muted = adpcm_muted;
|
||||||
if (value & 0x20)
|
if (value & 0x20)
|
||||||
m_cd_audio_volume_matrix = m_next_cd_audio_volume_matrix;
|
m_cd_audio_volume_matrix = m_next_cd_audio_volume_matrix;
|
||||||
return;
|
return;
|
||||||
|
@ -640,6 +651,11 @@ void CDROM::UpdateInterruptRequest()
|
||||||
g_interrupt_controller.InterruptRequest(InterruptController::IRQ::CDROM);
|
g_interrupt_controller.InterruptRequest(InterruptController::IRQ::CDROM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CDROM::HasPendingDiscEvent() const
|
||||||
|
{
|
||||||
|
return (m_drive_event->IsActive() && m_drive_event->GetTicksUntilNextExecution() <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
TickCount CDROM::GetAckDelayForCommand(Command command)
|
TickCount CDROM::GetAckDelayForCommand(Command command)
|
||||||
{
|
{
|
||||||
if (command == Command::Init)
|
if (command == Command::Init)
|
||||||
|
@ -2072,16 +2088,6 @@ static s16 ZigZagInterpolate(const s16* ringbuf, const s16* table, u8 p)
|
||||||
return static_cast<s16>(std::clamp<s32>(sum, -0x8000, 0x7FFF));
|
return static_cast<s16>(std::clamp<s32>(sum, -0x8000, 0x7FFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr s32 ApplyVolume(s16 sample, u8 volume)
|
|
||||||
{
|
|
||||||
return s32(sample) * static_cast<s32>(ZeroExtend32(volume)) >> 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr s16 SaturateVolume(s32 volume)
|
|
||||||
{
|
|
||||||
return static_cast<s16>(std::clamp<s32>(volume, -0x8000, 0x7FFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool STEREO, bool SAMPLE_RATE>
|
template<bool STEREO, bool SAMPLE_RATE>
|
||||||
void CDROM::ResampleXAADPCM(const s16* frames_in, u32 num_frames_in)
|
void CDROM::ResampleXAADPCM(const s16* frames_in, u32 num_frames_in)
|
||||||
{
|
{
|
||||||
|
@ -2123,12 +2129,7 @@ void CDROM::ResampleXAADPCM(const s16* frames_in, u32 num_frames_in)
|
||||||
{
|
{
|
||||||
const s16 left_interp = ZigZagInterpolate(left_ringbuf, s_zigzag_table[j].data(), p);
|
const s16 left_interp = ZigZagInterpolate(left_ringbuf, s_zigzag_table[j].data(), p);
|
||||||
const s16 right_interp = STEREO ? ZigZagInterpolate(right_ringbuf, s_zigzag_table[j].data(), p) : left_interp;
|
const s16 right_interp = STEREO ? ZigZagInterpolate(right_ringbuf, s_zigzag_table[j].data(), p) : left_interp;
|
||||||
|
AddCDAudioFrame(left_interp, right_interp);
|
||||||
const s16 left_out = SaturateVolume(ApplyVolume(left_interp, m_cd_audio_volume_matrix[0][0]) +
|
|
||||||
ApplyVolume(right_interp, m_cd_audio_volume_matrix[1][0]));
|
|
||||||
const s16 right_out = SaturateVolume(ApplyVolume(left_interp, m_cd_audio_volume_matrix[0][1]) +
|
|
||||||
ApplyVolume(right_interp, m_cd_audio_volume_matrix[1][1]));
|
|
||||||
AddCDAudioFrame(left_out, right_out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2333,12 +2334,7 @@ void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ&
|
||||||
std::memcpy(&samp_left, sector_ptr, sizeof(samp_left));
|
std::memcpy(&samp_left, sector_ptr, sizeof(samp_left));
|
||||||
std::memcpy(&samp_right, sector_ptr + sizeof(s16), sizeof(samp_right));
|
std::memcpy(&samp_right, sector_ptr + sizeof(s16), sizeof(samp_right));
|
||||||
sector_ptr += sizeof(s16) * 2;
|
sector_ptr += sizeof(s16) * 2;
|
||||||
|
AddCDAudioFrame(samp_left, samp_right);
|
||||||
const s16 left = SaturateVolume(ApplyVolume(samp_left, m_cd_audio_volume_matrix[0][0]) +
|
|
||||||
ApplyVolume(samp_right, m_cd_audio_volume_matrix[1][0]));
|
|
||||||
const s16 right = SaturateVolume(ApplyVolume(samp_left, m_cd_audio_volume_matrix[0][1]) +
|
|
||||||
ApplyVolume(samp_right, m_cd_audio_volume_matrix[1][1]));
|
|
||||||
AddCDAudioFrame(left, right);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,13 @@ public:
|
||||||
ALWAYS_INLINE std::tuple<s16, s16> GetAudioFrame()
|
ALWAYS_INLINE std::tuple<s16, s16> GetAudioFrame()
|
||||||
{
|
{
|
||||||
const u32 frame = m_audio_fifo.IsEmpty() ? 0u : m_audio_fifo.Pop();
|
const u32 frame = m_audio_fifo.IsEmpty() ? 0u : m_audio_fifo.Pop();
|
||||||
return std::tuple<s16, s16>(static_cast<s16>(frame), static_cast<s16>(frame >> 16));
|
const s16 left = static_cast<s16>(Truncate16(frame));
|
||||||
|
const s16 right = static_cast<s16>(Truncate16(frame >> 16));
|
||||||
|
const s16 left_out = SaturateVolume(ApplyVolume(left, m_cd_audio_volume_matrix[0][0]) +
|
||||||
|
ApplyVolume(right, m_cd_audio_volume_matrix[1][0]));
|
||||||
|
const s16 right_out = SaturateVolume(ApplyVolume(left, m_cd_audio_volume_matrix[0][1]) +
|
||||||
|
ApplyVolume(right, m_cd_audio_volume_matrix[1][1]));
|
||||||
|
return std::tuple<s16, s16>(left_out, right_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -230,6 +236,15 @@ private:
|
||||||
{
|
{
|
||||||
m_audio_fifo.Push(ZeroExtend32(static_cast<u16>(left)) | (ZeroExtend32(static_cast<u16>(right)) << 16));
|
m_audio_fifo.Push(ZeroExtend32(static_cast<u16>(left)) | (ZeroExtend32(static_cast<u16>(right)) << 16));
|
||||||
}
|
}
|
||||||
|
ALWAYS_INLINE static constexpr s32 ApplyVolume(s16 sample, u8 volume)
|
||||||
|
{
|
||||||
|
return s32(sample) * static_cast<s32>(ZeroExtend32(volume)) >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static constexpr s16 SaturateVolume(s32 volume)
|
||||||
|
{
|
||||||
|
return static_cast<s16>((volume < -0x8000) ? -0x8000 : ((volume > 0x7FFF) ? 0x7FFF : volume));
|
||||||
|
}
|
||||||
|
|
||||||
void SetInterrupt(Interrupt interrupt);
|
void SetInterrupt(Interrupt interrupt);
|
||||||
void SetAsyncInterrupt(Interrupt interrupt);
|
void SetAsyncInterrupt(Interrupt interrupt);
|
||||||
|
@ -240,6 +255,7 @@ private:
|
||||||
void SendAsyncErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80);
|
void SendAsyncErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80);
|
||||||
void UpdateStatusRegister();
|
void UpdateStatusRegister();
|
||||||
void UpdateInterruptRequest();
|
void UpdateInterruptRequest();
|
||||||
|
bool HasPendingDiscEvent() const;
|
||||||
|
|
||||||
TickCount GetAckDelayForCommand(Command command);
|
TickCount GetAckDelayForCommand(Command command);
|
||||||
TickCount GetTicksForRead();
|
TickCount GetTicksForRead();
|
||||||
|
|
Loading…
Reference in New Issue