diff options
author | Max Kellermann <max@duempel.org> | 2015-10-27 00:22:22 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2015-10-27 11:44:23 +0100 |
commit | 15e432204e62dd5a1c873af13a679195b9645b0c (patch) | |
tree | a00687f4ac08b273a9416c36681749c42ed9dcbe /src/pcm/Order.cxx | |
parent | 4b1630e1ec1fe5cbecc013a3e1487d9f43fcdd2f (diff) |
pcm/Order: new library to convert from FLAC to ALSA channel order
This new library is integrated in the PcmExport class and (if enabled)
converts MPD's channel order (= FLAC channel order) to ALSA channel
order.
This fixes:
http://bugs.musicpd.org/view.php?id=3147
and
http://bugs.musicpd.org/view.php?id=3255
Diffstat (limited to 'src/pcm/Order.cxx')
-rw-r--r-- | src/pcm/Order.cxx | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/src/pcm/Order.cxx b/src/pcm/Order.cxx new file mode 100644 index 000000000..470f9d119 --- /dev/null +++ b/src/pcm/Order.cxx @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Order.hxx" +#include "PcmBuffer.hxx" +#include "util/ConstBuffer.hxx" + +template<typename V> +struct TwoPointers { + V *dest; + const V *src; + + TwoPointers<V> &CopyOne() { + *dest++ = *src++; + return *this; + } + + TwoPointers<V> &CopyTwo() { + return CopyOne().CopyOne(); + } + + TwoPointers<V> &SwapTwoPairs() { + *dest++ = src[2]; + *dest++ = src[3]; + *dest++ = src[0]; + *dest++ = src[1]; + src += 4; + return *this; + } + + TwoPointers<V> &ToAlsa51() { + return CopyTwo() // left+right + .SwapTwoPairs(); // center, LFE, surround left+right + } + + TwoPointers<V> &ToAlsa71() { + return ToAlsa51() + .CopyTwo(); // side left+right + } +}; + +template<typename V> +static void +ToAlsaChannelOrder51(V *dest, const V *src, size_t n) +{ + TwoPointers<V> p{dest, src}; + for (size_t i = 0; i != n; ++i) + p.ToAlsa51(); +} + +template<typename V> +static inline ConstBuffer<V> +ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) +{ + auto dest = buffer.GetT<V>(src.size); + ToAlsaChannelOrder51(dest, src.data, src.size / 6); + return { dest, src.size }; +} + +template<typename V> +static void +ToAlsaChannelOrder71(V *dest, const V *src, size_t n) +{ + TwoPointers<V> p{dest, src}; + for (size_t i = 0; i != n; ++i) + p.ToAlsa71(); +} + +template<typename V> +static inline ConstBuffer<V> +ToAlsaChannelOrder71(PcmBuffer &buffer, ConstBuffer<V> src) +{ + auto dest = buffer.GetT<V>(src.size); + ToAlsaChannelOrder71(dest, src.data, src.size / 6); + return { dest, src.size }; +} + +template<typename V> +static ConstBuffer<V> +ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src, unsigned channels) +{ + switch (channels) { + case 6: // 5.1 + return ToAlsaChannelOrder51(buffer, src); + + case 8: // 7.1 + return ToAlsaChannelOrder71(buffer, src); + + default: + return src; + } +} + +ConstBuffer<void> +ToAlsaChannelOrder(PcmBuffer &buffer, ConstBuffer<void> src, + SampleFormat sample_format, unsigned channels) +{ + switch (sample_format) { + case SampleFormat::UNDEFINED: + case SampleFormat::S8: + case SampleFormat::DSD: + return src; + + case SampleFormat::S16: + return ToAlsaChannelOrderT(buffer, + ConstBuffer<int16_t>::FromVoid(src), + channels).ToVoid(); + + case SampleFormat::S24_P32: + case SampleFormat::S32: + case SampleFormat::FLOAT: + return ToAlsaChannelOrderT(buffer, + ConstBuffer<int32_t>::FromVoid(src), + channels).ToVoid(); + } + + gcc_unreachable(); +} |