Swapped FFDShow's DPL2 decoder by FreeSurround
Added class in AudioCommon for the surround decoder
This commit is contained in:
parent
7b9375875c
commit
df631f0d75
|
@ -45,6 +45,7 @@
|
||||||
<ClCompile Include="NullSoundStream.cpp" />
|
<ClCompile Include="NullSoundStream.cpp" />
|
||||||
<ClCompile Include="OpenALStream.cpp" />
|
<ClCompile Include="OpenALStream.cpp" />
|
||||||
<ClCompile Include="WASAPIStream.cpp" />
|
<ClCompile Include="WASAPIStream.cpp" />
|
||||||
|
<ClCompile Include="SurroundDecoder.cpp" />
|
||||||
<ClCompile Include="WaveFile.cpp" />
|
<ClCompile Include="WaveFile.cpp" />
|
||||||
<ClCompile Include="XAudio2Stream.cpp" />
|
<ClCompile Include="XAudio2Stream.cpp" />
|
||||||
<ClCompile Include="XAudio2_7Stream.cpp">
|
<ClCompile Include="XAudio2_7Stream.cpp">
|
||||||
|
@ -65,6 +66,7 @@
|
||||||
<ClInclude Include="PulseAudioStream.h" />
|
<ClInclude Include="PulseAudioStream.h" />
|
||||||
<ClInclude Include="SoundStream.h" />
|
<ClInclude Include="SoundStream.h" />
|
||||||
<ClInclude Include="WASAPIStream.h" />
|
<ClInclude Include="WASAPIStream.h" />
|
||||||
|
<ClInclude Include="SurroundDecoder.h" />
|
||||||
<ClInclude Include="WaveFile.h" />
|
<ClInclude Include="WaveFile.h" />
|
||||||
<ClInclude Include="XAudio2Stream.h" />
|
<ClInclude Include="XAudio2Stream.h" />
|
||||||
<ClInclude Include="XAudio2_7Stream.h" />
|
<ClInclude Include="XAudio2_7Stream.h" />
|
||||||
|
@ -79,6 +81,9 @@
|
||||||
<ProjectReference Include="$(CoreDir)Common\Common.vcxproj">
|
<ProjectReference Include="$(CoreDir)Common\Common.vcxproj">
|
||||||
<Project>{2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4}</Project>
|
<Project>{2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="$(ExternalsDir)FreeSurround\FreeSurround.vcxproj">
|
||||||
|
<Project>{8498f2fa-5ca6-4169-9971-de5b1fe6132c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
<ClCompile Include="WASAPIStream.cpp">
|
<ClCompile Include="WASAPIStream.cpp">
|
||||||
<Filter>SoundStreams</Filter>
|
<Filter>SoundStreams</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SurroundDecoder.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AudioCommon.h" />
|
<ClInclude Include="AudioCommon.h" />
|
||||||
|
@ -68,6 +69,7 @@
|
||||||
<ClInclude Include="WASAPIStream.h">
|
<ClInclude Include="WASAPIStream.h">
|
||||||
<Filter>SoundStreams</Filter>
|
<Filter>SoundStreams</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="SurroundDecoder.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
|
|
@ -5,6 +5,7 @@ add_library(audiocommon
|
||||||
CubebUtils.cpp
|
CubebUtils.cpp
|
||||||
DPL2Decoder.cpp
|
DPL2Decoder.cpp
|
||||||
Mixer.cpp
|
Mixer.cpp
|
||||||
|
SurroundDecoder.cpp
|
||||||
NullSoundStream.cpp
|
NullSoundStream.cpp
|
||||||
WaveFile.cpp
|
WaveFile.cpp
|
||||||
)
|
)
|
||||||
|
@ -69,4 +70,4 @@ if(WIN32)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(audiocommon PRIVATE cubeb SoundTouch)
|
target_link_libraries(audiocommon PRIVATE cubeb SoundTouch FreeSurround)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "AudioCommon/DPL2Decoder.h"
|
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
@ -16,10 +15,10 @@
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
Mixer::Mixer(unsigned int BackendSampleRate)
|
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");
|
INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized");
|
||||||
DPL2Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mixer::~Mixer()
|
Mixer::~Mixer()
|
||||||
|
@ -167,20 +166,23 @@ unsigned int Mixer::MixSurround(float* samples, unsigned int num_samples)
|
||||||
if (!num_samples)
|
if (!num_samples)
|
||||||
return 0;
|
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
|
size_t needed_frames = m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples);
|
||||||
// writes.
|
|
||||||
unsigned int available_samples = Mix(m_scratch_buffer.data(), num_samples);
|
// Mix() may also use m_scratch_buffer internally, but is safe because it alternates reads
|
||||||
for (size_t i = 0; i < static_cast<size_t>(available_samples) * 2; ++i)
|
// and writes.
|
||||||
|
size_t available_frames = Mix(m_scratch_buffer.data(), static_cast<u32>(needed_frames));
|
||||||
|
if (available_frames != needed_frames)
|
||||||
{
|
{
|
||||||
m_float_conversion_buffer[i] =
|
ERROR_LOG(AUDIO, "Error decoding surround frames.");
|
||||||
m_scratch_buffer[i] / static_cast<float>(std::numeric_limits<short>::max());
|
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)
|
void Mixer::MixerFifo::PushSamples(const short* samples, unsigned int num_samples)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include "AudioCommon/AudioStretcher.h"
|
#include "AudioCommon/AudioStretcher.h"
|
||||||
|
#include "AudioCommon/SurroundDecoder.h"
|
||||||
#include "AudioCommon/WaveFile.h"
|
#include "AudioCommon/WaveFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
@ -52,6 +53,9 @@ private:
|
||||||
static constexpr float CONTROL_FACTOR = 0.2f;
|
static constexpr float CONTROL_FACTOR = 0.2f;
|
||||||
static constexpr u32 CONTROL_AVG = 32; // In freq_shift per FIFO size offset
|
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
|
class MixerFifo final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -86,8 +90,8 @@ private:
|
||||||
|
|
||||||
bool m_is_stretching = false;
|
bool m_is_stretching = false;
|
||||||
AudioCommon::AudioStretcher m_stretcher;
|
AudioCommon::AudioStretcher m_stretcher;
|
||||||
|
AudioCommon::SurroundDecoder m_surround_decoder;
|
||||||
std::array<short, MAX_SAMPLES * 2> m_scratch_buffer;
|
std::array<short, MAX_SAMPLES * 2> m_scratch_buffer;
|
||||||
std::array<float, MAX_SAMPLES * 2> m_float_conversion_buffer;
|
|
||||||
|
|
||||||
WaveFileWriter m_wave_writer_dtk;
|
WaveFileWriter m_wave_writer_dtk;
|
||||||
WaveFileWriter m_wave_writer_dsp;
|
WaveFileWriter m_wave_writer_dsp;
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <FreeSurround/FreeSurroundDecoder.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#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<DPL2FSDecoder>();
|
||||||
|
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<s64>(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<float>(std::numeric_limits<short>::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<int>(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
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#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<DPL2FSDecoder> m_fsdecoder;
|
||||||
|
std::array<float, 32768> m_float_conversion_buffer;
|
||||||
|
FixedSizeQueue<float, 32768> m_decoded_fifo;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // AudioCommon
|
Loading…
Reference in New Issue