summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon/SurroundDecoder.cpp
blob: acab16816ce86f42002c93b47d280711862ddb37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "AudioCommon/SurroundDecoder.h"

#include <FreeSurround/FreeSurroundDecoder.h>
#include <limits>

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 const 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