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