Commit f6fe001f authored by Florian Heese's avatar Florian Heese Committed by Max Kellermann

Added missing channel order setups for ALSA

parent 32a5bf04
ver 0.21.23 (not yet released) ver 0.21.23 (not yet released)
* output
- alsa: implement channel mapping for 5.0 and 7.0
* player * player
- drain outputs at end of song in "single" mode - drain outputs at end of song in "single" mode
......
...@@ -21,6 +21,28 @@ ...@@ -21,6 +21,28 @@
#include "PcmBuffer.hxx" #include "PcmBuffer.hxx"
#include "util/ConstBuffer.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> template<typename V>
struct TwoPointers { struct TwoPointers {
V *dest; V *dest;
...@@ -44,11 +66,33 @@ struct TwoPointers { ...@@ -44,11 +66,33 @@ struct TwoPointers {
return *this; 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 { TwoPointers<V> &ToAlsa51() noexcept {
return CopyTwo() // left+right return CopyTwo() // left+right
.SwapTwoPairs(); // center, LFE, surround 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 { TwoPointers<V> &ToAlsa71() noexcept {
return ToAlsa51() return ToAlsa51()
.CopyTwo(); // side left+right .CopyTwo(); // side left+right
...@@ -57,6 +101,24 @@ struct TwoPointers { ...@@ -57,6 +101,24 @@ struct TwoPointers {
template<typename V> template<typename V>
static void 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 ToAlsaChannelOrder51(V *dest, const V *src, size_t n) noexcept
{ {
TwoPointers<V> p{dest, src}; TwoPointers<V> p{dest, src};
...@@ -75,6 +137,24 @@ ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) noexcept ...@@ -75,6 +137,24 @@ ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
template<typename V> template<typename V>
static void 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 ToAlsaChannelOrder71(V *dest, const V *src, size_t n) noexcept
{ {
TwoPointers<V> p{dest, src}; TwoPointers<V> p{dest, src};
...@@ -97,9 +177,15 @@ ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src, ...@@ -97,9 +177,15 @@ ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src,
unsigned channels) noexcept unsigned channels) noexcept
{ {
switch (channels) { switch (channels) {
case 5: // 5.0
return ToAlsaChannelOrder50(buffer, src);
case 6: // 5.1 case 6: // 5.1
return ToAlsaChannelOrder51(buffer, src); return ToAlsaChannelOrder51(buffer, src);
case 7: // 7.0
return ToAlsaChannelOrder70(buffer, src);
case 8: // 7.1 case 8: // 7.1
return ToAlsaChannelOrder71(buffer, src); return ToAlsaChannelOrder71(buffer, src);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment