Skip to content

Commit

Permalink
Added FreeSurround support to the PulseAudio backend
Browse files Browse the repository at this point in the history
  • Loading branch information
LAGonauta committed Jun 5, 2017
1 parent 10c470f commit a2bec0e
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 34 deletions.
8 changes: 3 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -611,11 +611,9 @@ else()
set(PNG png)
endif()

find_package(OpenAL)
if(OPENAL_FOUND)
message(STATUS "Using static FreeSurround from Externals")
add_subdirectory(Externals/FreeSurround)
endif()
# There is no system FreeSurround library available
message(STATUS "Using static FreeSurround from Externals")
add_subdirectory(Externals/FreeSurround)

# Using static soundtouch from Externals
# Unable to use system soundtouch library: We require shorts, not floats.
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/AudioCommon/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ if(ENABLE_PULSEAUDIO)
if(PULSEAUDIO_FOUND)
message(STATUS "PulseAudio found, enabling PulseAudio sound backend")
target_sources(audiocommon PRIVATE PulseAudioStream.cpp)
target_link_libraries(audiocommon PRIVATE PulseAudio::PulseAudio)
target_link_libraries(audiocommon PRIVATE PulseAudio::PulseAudio FreeSurround)
target_compile_definitions(audiocommon PRIVATE HAVE_PULSEAUDIO=1)
else()
message(STATUS "PulseAudio NOT found, disabling PulseAudio sound backend")
Expand Down
87 changes: 59 additions & 28 deletions Source/Core/AudioCommon/PulseAudioStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@

#include <cstring>

#include "AudioCommon/DPL2Decoder.h"
#include "AudioCommon/PulseAudioStream.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "FreeSurround/FreeSurroundDecoder.h"

namespace
{
const size_t BUFFER_SAMPLES = 512; // ~10 ms - needs to be at least 240 for surround
static DPL2FSDecoder fsdecoder;
}

PulseAudio::PulseAudio() : m_thread(), m_run_thread()
Expand All @@ -23,15 +24,17 @@ PulseAudio::PulseAudio() : m_thread(), m_run_thread()
bool PulseAudio::Start()
{
m_stereo = !SConfig::GetInstance().bDPL2Decoder;
m_channels = m_stereo ? 2 : 5; // will tell PA we use a Stereo or 5.0 channel setup
m_channels = m_stereo ? 2 : 6; // will tell PA we use a Stereo or 5.0 channel setup

NOTICE_LOG(AUDIO, "PulseAudio backend using %d channels", m_channels);

m_run_thread.Set();
m_thread = std::thread(&PulseAudio::SoundLoop, this);

// Initialize DPL2 parameters
DPL2Reset();
// Initialize FS decoder
fsdecoder.Init();
fsdecoder.set_block_size(BUFFER_SAMPLES);
fsdecoder.set_sample_rate(m_mixer->GetSampleRate());

return true;
}
Expand Down Expand Up @@ -105,12 +108,15 @@ bool PulseAudio::PulseInit()
m_bytespersample = sizeof(float);

channel_map_p = &channel_map; // explicit channel map:
channel_map.channels = 5;
channel_map.channels = 6;
// FreeSurround:
// FL | FC | FR | BL | BR | LFE
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_CENTER;
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_RIGHT;
channel_map.map[3] = PA_CHANNEL_POSITION_REAR_LEFT;
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_RIGHT;
channel_map.map[5] = PA_CHANNEL_POSITION_LFE;
}
ss.channels = m_channels;
ss.rate = m_mixer->GetSampleRate();
Expand Down Expand Up @@ -194,32 +200,57 @@ void PulseAudio::WriteCallback(pa_stream* s, size_t length)
}
else
{
// get a floating point mix
s16 s16buffer_stereo[frames * 2];
m_mixer->Mix(s16buffer_stereo, frames); // implicitly mixes to 16-bit stereo

float floatbuffer_stereo[frames * 2];
// s16 to float
for (int i = 0; i < frames * 2; ++i)
if (m_channels == 6) // Extract dpl2/5.1 Surround
{
floatbuffer_stereo[i] = s16buffer_stereo[i] / float(1 << 15);
}
// Calculate how many times we need to request the FS decoder
int num_fs_dec_requests = 0;
if (m_floatsurround_buffer_queue.size() < static_cast<u32>(frames * m_channels))
{
long num_frames_remaining =
frames - static_cast<long>(m_floatsurround_buffer_queue.size() / m_channels);
while (num_frames_remaining > 0)
{
++num_fs_dec_requests;
num_frames_remaining = num_frames_remaining - BUFFER_SAMPLES;
}
}

if (m_channels == 5) // Extract dpl2/5.0 Surround
{
float floatbuffer_6chan[frames * 6];
// DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR
DPL2Decode(floatbuffer_stereo, frames, floatbuffer_6chan);

// Discard the subwoofer channel - DPL2Decode generates a pretty
// good 5.0 but not a good 5.1 output.
const int dpl2_to_5chan[] = {0, 1, 2, 4, 5};
for (int i = 0; i < frames; ++i)
while (num_fs_dec_requests > 0)
{
for (int j = 0; j < m_channels; ++j)
// get a floating point mix
s16 s16buffer_stereo[frames * 2];
m_mixer->Mix(s16buffer_stereo, BUFFER_SAMPLES); // implicitly mixes to 16-bit stereo

float floatbuffer_stereo[frames * 2];
// s16 to float
for (int i = 0; i < frames * 2; ++i)
{
((float*)buffer)[m_channels * i + j] = floatbuffer_6chan[6 * i + dpl2_to_5chan[j]];
floatbuffer_stereo[i] = s16buffer_stereo[i] / static_cast<float>(INT16_MAX);
}

// FSDPL2Decode
float* dpl2_fs = fsdecoder.decode(floatbuffer_stereo);

// Add to queue. PA was already initialized with the correct
// channel mapping.
for (u32 i = 0; i < BUFFER_SAMPLES; ++i)
{
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 0 /*LEFTFRONT*/]);
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 1 /*CENTREFRONT*/]);
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 2 /*RIGHTFRONT*/]);
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 3 /*LEFTREAR*/]);
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 4 /*RIGHTREAR*/]);
m_floatsurround_buffer_queue.push(dpl2_fs[i * m_channels + 5 /*sub/lfe*/]);
}

--num_fs_dec_requests;
}

// Copy to output array with desired number of frames
for (long i = 0, num_samples = frames * m_channels; i < num_samples; ++i)
{
static_cast<float*>(buffer)[i] = m_floatsurround_buffer_queue.front();
m_floatsurround_buffer_queue.pop();
}
}
else
Expand Down
3 changes: 3 additions & 0 deletions Source/Core/AudioCommon/PulseAudioStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#pragma once

#include <queue>

#if defined(HAVE_PULSEAUDIO) && HAVE_PULSEAUDIO
#include <pulse/pulseaudio.h>
#endif
Expand Down Expand Up @@ -45,6 +47,7 @@ class PulseAudio final : public SoundStream
bool m_stereo; // stereo, else surround
int m_bytespersample;
int m_channels;
std::queue<float> m_floatsurround_buffer_queue;

int m_pa_error;
int m_pa_connected;
Expand Down

0 comments on commit a2bec0e

Please sign in to comment.