From df631f0d75bd6422aca4b69854671ba1c561b077 Mon Sep 17 00:00:00 2001 From: LAGonauta Date: Wed, 9 Aug 2017 16:57:26 -0300 Subject: [PATCH] Swapped FFDShow's DPL2 decoder by FreeSurround Added class in AudioCommon for the surround decoder --- Source/Core/AudioCommon/AudioCommon.vcxproj | 5 + .../AudioCommon/AudioCommon.vcxproj.filters | 2 + Source/Core/AudioCommon/CMakeLists.txt | 3 +- Source/Core/AudioCommon/Mixer.cpp | 26 +++--- Source/Core/AudioCommon/Mixer.h | 6 +- Source/Core/AudioCommon/SurroundDecoder.cpp | 93 +++++++++++++++++++ Source/Core/AudioCommon/SurroundDecoder.h | 36 +++++++ 7 files changed, 157 insertions(+), 14 deletions(-) create mode 100644 Source/Core/AudioCommon/SurroundDecoder.cpp create mode 100644 Source/Core/AudioCommon/SurroundDecoder.h diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj b/Source/Core/AudioCommon/AudioCommon.vcxproj index bd6b469ac6..5413cc1eb6 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj @@ -45,6 +45,7 @@ + @@ -65,6 +66,7 @@ + @@ -79,6 +81,9 @@ {2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4} + + {8498f2fa-5ca6-4169-9971-de5b1fe6132c} + diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters index c710630f4a..fdc0e186d2 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters @@ -30,6 +30,7 @@ SoundStreams + @@ -68,6 +69,7 @@ SoundStreams + diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt index 8664d4bf70..e00de45877 100644 --- a/Source/Core/AudioCommon/CMakeLists.txt +++ b/Source/Core/AudioCommon/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(audiocommon CubebUtils.cpp DPL2Decoder.cpp Mixer.cpp + SurroundDecoder.cpp NullSoundStream.cpp WaveFile.cpp ) @@ -69,4 +70,4 @@ if(WIN32) endif() endif() -target_link_libraries(audiocommon PRIVATE cubeb SoundTouch) +target_link_libraries(audiocommon PRIVATE cubeb SoundTouch FreeSurround) diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index da0f81c87e..7620ba5cec 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -7,7 +7,6 @@ #include #include -#include "AudioCommon/DPL2Decoder.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" @@ -16,10 +15,10 @@ #include "Core/ConfigManager.h" Mixer::Mixer(unsigned int BackendSampleRate) - : m_sampleRate(BackendSampleRate), m_stretcher(BackendSampleRate) + : m_sampleRate(BackendSampleRate), m_stretcher(BackendSampleRate), + m_surround_decoder(BackendSampleRate, SURROUND_BLOCK_SIZE) { INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized"); - DPL2Reset(); } Mixer::~Mixer() @@ -167,20 +166,23 @@ unsigned int Mixer::MixSurround(float* samples, unsigned int num_samples) if (!num_samples) return 0; - memset(samples, 0, num_samples * 6 * sizeof(float)); + memset(samples, 0, num_samples * SURROUND_CHANNELS * sizeof(float)); - // Mix() may also use m_scratch_buffer internally, but is safe because it alternates reads and - // writes. - unsigned int available_samples = Mix(m_scratch_buffer.data(), num_samples); - for (size_t i = 0; i < static_cast(available_samples) * 2; ++i) + size_t needed_frames = m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples); + + // Mix() may also use m_scratch_buffer internally, but is safe because it alternates reads + // and writes. + size_t available_frames = Mix(m_scratch_buffer.data(), static_cast(needed_frames)); + if (available_frames != needed_frames) { - m_float_conversion_buffer[i] = - m_scratch_buffer[i] / static_cast(std::numeric_limits::max()); + ERROR_LOG(AUDIO, "Error decoding surround frames."); + return 0; } - DPL2Decode(m_float_conversion_buffer.data(), available_samples, samples); + m_surround_decoder.PutFrames(m_scratch_buffer.data(), needed_frames); + m_surround_decoder.ReceiveFrames(samples, num_samples); - return available_samples; + return num_samples; } void Mixer::MixerFifo::PushSamples(const short* samples, unsigned int num_samples) diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index e2545d6be1..83a13cf5d6 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -8,6 +8,7 @@ #include #include "AudioCommon/AudioStretcher.h" +#include "AudioCommon/SurroundDecoder.h" #include "AudioCommon/WaveFile.h" #include "Common/CommonTypes.h" @@ -52,6 +53,9 @@ private: static constexpr float CONTROL_FACTOR = 0.2f; static constexpr u32 CONTROL_AVG = 32; // In freq_shift per FIFO size offset + const unsigned int SURROUND_CHANNELS = 6; + const unsigned int SURROUND_BLOCK_SIZE = 512; + class MixerFifo final { public: @@ -86,8 +90,8 @@ private: bool m_is_stretching = false; AudioCommon::AudioStretcher m_stretcher; + AudioCommon::SurroundDecoder m_surround_decoder; std::array m_scratch_buffer; - std::array m_float_conversion_buffer; WaveFileWriter m_wave_writer_dtk; WaveFileWriter m_wave_writer_dsp; diff --git a/Source/Core/AudioCommon/SurroundDecoder.cpp b/Source/Core/AudioCommon/SurroundDecoder.cpp new file mode 100644 index 0000000000..8ded0ca5e8 --- /dev/null +++ b/Source/Core/AudioCommon/SurroundDecoder.cpp @@ -0,0 +1,93 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "AudioCommon/SurroundDecoder.h" + +namespace AudioCommon +{ +constexpr size_t STEREO_CHANNELS = 2; +constexpr size_t SURROUND_CHANNELS = 6; + +SurroundDecoder::SurroundDecoder(u32 sample_rate, u32 frame_block_size) + : m_sample_rate(sample_rate), m_frame_block_size(frame_block_size) +{ + m_fsdecoder = std::make_unique(); + m_fsdecoder->Init(cs_5point1, m_frame_block_size, m_sample_rate); +} + +SurroundDecoder::~SurroundDecoder() = default; + +void SurroundDecoder::Clear() +{ + m_fsdecoder->flush(); + m_decoded_fifo.clear(); +} + +// Currently only 6 channels are supported. +size_t SurroundDecoder::QueryFramesNeededForSurroundOutput(const size_t output_frames) const +{ + if (m_decoded_fifo.size() < output_frames * SURROUND_CHANNELS) + { + // Output stereo frames needed to have at least the desired number of surround frames + size_t frames_needed = output_frames - m_decoded_fifo.size() / SURROUND_CHANNELS; + return frames_needed + m_frame_block_size - frames_needed % m_frame_block_size; + } + + return 0; +} + +// Receive and decode samples +void SurroundDecoder::PutFrames(const short* in, const size_t num_frames_in) +{ + // Maybe check if it is really power-of-2? + s64 remaining_frames = static_cast(num_frames_in); + size_t frame_index = 0; + + while (remaining_frames > 0) + { + // Convert to float + for (size_t i = 0, end = m_frame_block_size * STEREO_CHANNELS; i < end; ++i) + { + m_float_conversion_buffer[i] = in[i + frame_index * STEREO_CHANNELS] / + static_cast(std::numeric_limits::max()); + } + + // Decode + const float* dpl2_fs = m_fsdecoder->decode(m_float_conversion_buffer.data()); + + // Add to ring buffer and fix channel mapping + // Maybe modify FreeSurround to output the correct mapping? + // FreeSurround: + // FL | FC | FR | BL | BR | LFE + // Most backends: + // FL | FR | FC | LFE | BL | BR + for (size_t i = 0; i < m_frame_block_size; ++i) + { + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 0]); // LEFTFRONT + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 2]); // RIGHTFRONT + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 1]); // CENTREFRONT + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 5]); // sub/lfe + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 3]); // LEFTREAR + m_decoded_fifo.push(dpl2_fs[i * SURROUND_CHANNELS + 4]); // RIGHTREAR + } + + remaining_frames = remaining_frames - static_cast(m_frame_block_size); + frame_index = frame_index + m_frame_block_size; + } +} + +void SurroundDecoder::ReceiveFrames(float* out, const size_t num_frames_out) +{ + // Copy to output array with desired num_frames_out + for (size_t i = 0, num_samples_output = num_frames_out * SURROUND_CHANNELS; + i < num_samples_output; ++i) + { + out[i] = m_decoded_fifo.pop_front(); + } +} + +} // namespace AudioCommon diff --git a/Source/Core/AudioCommon/SurroundDecoder.h b/Source/Core/AudioCommon/SurroundDecoder.h new file mode 100644 index 0000000000..699be74278 --- /dev/null +++ b/Source/Core/AudioCommon/SurroundDecoder.h @@ -0,0 +1,36 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/FixedSizeQueue.h" + +class DPL2FSDecoder; + +namespace AudioCommon +{ +class SurroundDecoder +{ +public: + explicit SurroundDecoder(u32 sample_rate, u32 frame_block_size); + ~SurroundDecoder(); + size_t QueryFramesNeededForSurroundOutput(const size_t output_frames) const; + void PutFrames(const short* in, const size_t num_frames_in); + void ReceiveFrames(float* out, const size_t num_frames_out); + void Clear(); + +private: + u32 m_sample_rate; + u32 m_frame_block_size; + + std::unique_ptr m_fsdecoder; + std::array m_float_conversion_buffer; + FixedSizeQueue m_decoded_fifo; +}; + +} // AudioCommon