summaryrefslogtreecommitdiff
path: root/src/pcm/Order.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pcm/Order.cxx')
-rw-r--r--src/pcm/Order.cxx86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/pcm/Order.cxx b/src/pcm/Order.cxx
index e728f0c9f..e75cacb94 100644
--- a/src/pcm/Order.cxx
+++ b/src/pcm/Order.cxx
@@ -21,6 +21,28 @@
#include "PcmBuffer.hxx"
#include "util/ConstBuffer.hxx"
+
+/*
+ * According to:
+ * - https://xiph.org/flac/format.html#frame_header
+ * - https://github.com/nu774/qaac/wiki/Multichannel--handling
+ * the source channel order (after decoding, e.g., flac, alac) is for
+ * - 1ch: mono
+ * - 2ch: left, right
+ * - 3ch: left, right, center
+ * - 4ch: front left, front right, back left, back right
+ * - 5ch: front left, front right, front center, back/surround left, back/surround right
+ * - 6ch (aka 5.1): front left, front right, front center, LFE, back/surround left, back/surround right
+ * - 7ch: front left, front right, front center, LFE, back center, side left, side right
+ * - 8ch: (aka 7.1): front left, front right, front center, LFE, back left, back right, side left, side right
+ *
+ * The ALSA default channel map is (see /usr/share/alsa/pcm/surround71.conf):
+ * - front left, front right, back left, back right, front center, LFE, side left, side right
+ *
+ * Hence, in case of the following source channel orders 3ch, 5ch, 6ch (aka
+ * 5.1), 7ch and 8ch the channel order has to be adapted
+ */
+
template<typename V>
struct TwoPointers {
V *dest;
@@ -44,11 +66,33 @@ struct TwoPointers {
return *this;
}
+ TwoPointers<V> &ToAlsa50() noexcept {
+ *dest++ = src[0]; // front left
+ *dest++ = src[1]; // front right
+ *dest++ = src[3]; // surround left
+ *dest++ = src[4]; // surround right
+ *dest++ = src[2]; // front center
+ src += 5;
+ return *this;
+ }
+
TwoPointers<V> &ToAlsa51() noexcept {
return CopyTwo() // left+right
.SwapTwoPairs(); // center, LFE, surround left+right
}
+ TwoPointers<V> &ToAlsa70() noexcept {
+ *dest++ = src[0]; // front left
+ *dest++ = src[1]; // front right
+ *dest++ = src[5]; // side left
+ *dest++ = src[6]; // side right
+ *dest++ = src[2]; // front center
+ *dest++ = src[3]; // LFE
+ *dest++ = src[4]; // back center
+ src += 7;
+ return *this;
+ }
+
TwoPointers<V> &ToAlsa71() noexcept {
return ToAlsa51()
.CopyTwo(); // side left+right
@@ -57,6 +101,24 @@ struct TwoPointers {
template<typename V>
static void
+ToAlsaChannelOrder50(V *dest, const V *src, size_t n) noexcept
+{
+ TwoPointers<V> p{dest, src};
+ for (size_t i = 0; i != n; ++i)
+ p.ToAlsa50();
+}
+
+template<typename V>
+static inline ConstBuffer<V>
+ToAlsaChannelOrder50(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
+{
+ auto dest = buffer.GetT<V>(src.size);
+ ToAlsaChannelOrder50(dest, src.data, src.size / 5);
+ return { dest, src.size };
+}
+
+template<typename V>
+static void
ToAlsaChannelOrder51(V *dest, const V *src, size_t n) noexcept
{
TwoPointers<V> p{dest, src};
@@ -75,6 +137,24 @@ ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
template<typename V>
static void
+ToAlsaChannelOrder70(V *dest, const V *src, size_t n) noexcept
+{
+ TwoPointers<V> p{dest, src};
+ for (size_t i = 0; i != n; ++i)
+ p.ToAlsa70();
+}
+
+template<typename V>
+static inline ConstBuffer<V>
+ToAlsaChannelOrder70(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
+{
+ auto dest = buffer.GetT<V>(src.size);
+ ToAlsaChannelOrder70(dest, src.data, src.size / 7);
+ return { dest, src.size };
+}
+
+template<typename V>
+static void
ToAlsaChannelOrder71(V *dest, const V *src, size_t n) noexcept
{
TwoPointers<V> p{dest, src};
@@ -97,9 +177,15 @@ ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src,
unsigned channels) noexcept
{
switch (channels) {
+ case 5: // 5.0
+ return ToAlsaChannelOrder50(buffer, src);
+
case 6: // 5.1
return ToAlsaChannelOrder51(buffer, src);
+ case 7: // 7.0
+ return ToAlsaChannelOrder70(buffer, src);
+
case 8: // 7.1
return ToAlsaChannelOrder71(buffer, src);