From fd5e74dbd058f11ef8ca015e6d2442316b6f9b5f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 16 Jun 2019 12:11:44 +0200 Subject: pcm/Pcm{Dop,Export}: drop "Pcm" prefix --- src/pcm/Dop.cxx | 94 +++++++++++++++++++++ src/pcm/Dop.hxx | 37 +++++++++ src/pcm/Export.cxx | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pcm/Export.hxx | 189 +++++++++++++++++++++++++++++++++++++++++ src/pcm/PcmDop.cxx | 94 --------------------- src/pcm/PcmDop.hxx | 37 --------- src/pcm/PcmExport.cxx | 226 -------------------------------------------------- src/pcm/PcmExport.hxx | 189 ----------------------------------------- src/pcm/meson.build | 4 +- 9 files changed, 548 insertions(+), 548 deletions(-) create mode 100644 src/pcm/Dop.cxx create mode 100644 src/pcm/Dop.hxx create mode 100644 src/pcm/Export.cxx create mode 100644 src/pcm/Export.hxx delete mode 100644 src/pcm/PcmDop.cxx delete mode 100644 src/pcm/PcmDop.hxx delete mode 100644 src/pcm/PcmExport.cxx delete mode 100644 src/pcm/PcmExport.hxx (limited to 'src/pcm') diff --git a/src/pcm/Dop.cxx b/src/pcm/Dop.cxx new file mode 100644 index 000000000..671abd2e6 --- /dev/null +++ b/src/pcm/Dop.cxx @@ -0,0 +1,94 @@ +/* + * Copyright 2003-2018 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 "Dop.hxx" +#include "PcmBuffer.hxx" +#include "AudioFormat.hxx" +#include "util/ConstBuffer.hxx" + +#include + +constexpr +static inline uint32_t +pcm_two_dsd_to_dop_marker1(uint8_t a, uint8_t b) noexcept +{ + return 0xff050000 | (a << 8) | b; +} + +constexpr +static inline uint32_t +pcm_two_dsd_to_dop_marker2(uint8_t a, uint8_t b) noexcept +{ + return 0xfffa0000 | (a << 8) | b; +} + +ConstBuffer +pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels, + ConstBuffer _src) noexcept +{ + assert(audio_valid_channel_count(channels)); + assert(_src.size % channels == 0); + + const size_t num_src_samples = _src.size; + const size_t num_src_frames = num_src_samples / channels; + + /* this rounds down and discards up to 3 odd frames; not + elegant, but good enough for now */ + const size_t num_dop_quads = num_src_frames / 4; + const size_t num_frames = num_dop_quads * 2; + const size_t num_samples = num_frames * channels; + + uint32_t *const dest0 = (uint32_t *)buffer.GetT(num_samples), + *dest = dest0; + + auto src = _src.data; + for (size_t i = num_dop_quads; i > 0; --i) { + for (unsigned c = channels; c > 0; --c) { + /* each 24 bit sample has 16 DSD sample bits + plus the magic 0x05 marker */ + + *dest++ = pcm_two_dsd_to_dop_marker1(src[0], src[channels]); + + /* seek the source pointer to the next + channel */ + ++src; + } + + /* skip the second byte of each channel, because we + have already copied it */ + src += channels; + + for (unsigned c = channels; c > 0; --c) { + /* each 24 bit sample has 16 DSD sample bits + plus the magic 0xfa marker */ + + *dest++ = pcm_two_dsd_to_dop_marker2(src[0], src[channels]); + + /* seek the source pointer to the next + channel */ + ++src; + } + + /* skip the second byte of each channel, because we + have already copied it */ + src += channels; + } + + return { dest0, num_samples }; +} diff --git a/src/pcm/Dop.hxx b/src/pcm/Dop.hxx new file mode 100644 index 000000000..0a2c9b205 --- /dev/null +++ b/src/pcm/Dop.hxx @@ -0,0 +1,37 @@ +/* + * Copyright 2003-2018 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. + */ + +#ifndef MPD_PCM_DOP_HXX +#define MPD_PCM_DOP_HXX + +#include + +class PcmBuffer; +template struct ConstBuffer; + +/** + * Pack DSD 1 bit samples into (padded) 24 bit PCM samples for + * playback over USB, according to the DoP standard: + * http://dsd-guide.com/dop-open-standard + */ +ConstBuffer +pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels, + ConstBuffer src) noexcept; + +#endif diff --git a/src/pcm/Export.cxx b/src/pcm/Export.cxx new file mode 100644 index 000000000..32f72318c --- /dev/null +++ b/src/pcm/Export.cxx @@ -0,0 +1,226 @@ +/* + * Copyright 2003-2018 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 "Export.hxx" +#include "AudioFormat.hxx" +#include "Order.hxx" +#include "PcmPack.hxx" +#include "util/ByteReverse.hxx" +#include "util/ConstBuffer.hxx" + +#ifdef ENABLE_DSD +#include "Dsd16.hxx" +#include "Dsd32.hxx" +#include "PcmDsd.hxx" +#include "Dop.hxx" +#endif + +#include + +void +PcmExport::Open(SampleFormat sample_format, unsigned _channels, + Params params) noexcept +{ + assert(audio_valid_sample_format(sample_format)); + + channels = _channels; + alsa_channel_order = params.alsa_channel_order + ? sample_format + : SampleFormat::UNDEFINED; + +#ifdef ENABLE_DSD + assert((params.dsd_u16 + params.dsd_u32 + params.dop) <= 1); + assert(!params.dop || audio_valid_channel_count(_channels)); + + dsd_u16 = params.dsd_u16 && sample_format == SampleFormat::DSD; + if (dsd_u16) + /* after the conversion to DSD_U16, the DSD samples + are stuffed inside fake 16 bit samples */ + sample_format = SampleFormat::S16; + + dsd_u32 = params.dsd_u32 && sample_format == SampleFormat::DSD; + if (dsd_u32) + /* after the conversion to DSD_U32, the DSD samples + are stuffed inside fake 32 bit samples */ + sample_format = SampleFormat::S32; + + dop = params.dop && sample_format == SampleFormat::DSD; + if (dop) + /* after the conversion to DoP, the DSD + samples are stuffed inside fake 24 bit samples */ + sample_format = SampleFormat::S24_P32; +#endif + + shift8 = params.shift8 && sample_format == SampleFormat::S24_P32; + pack24 = params.pack24 && sample_format == SampleFormat::S24_P32; + + assert(!shift8 || !pack24); + + reverse_endian = 0; + if (params.reverse_endian) { + size_t sample_size = pack24 + ? 3 + : sample_format_size(sample_format); + assert(sample_size <= 0xff); + + if (sample_size > 1) + reverse_endian = sample_size; + } +} + +size_t +PcmExport::GetFrameSize(const AudioFormat &audio_format) const noexcept +{ + if (pack24) + /* packed 24 bit samples (3 bytes per sample) */ + return audio_format.channels * 3; + +#ifdef ENABLE_DSD + if (dsd_u16) + return channels * 2; + + if (dsd_u32) + return channels * 4; + + if (dop) + /* the DSD-over-USB draft says that DSD 1-bit samples + are enclosed within 24 bit samples, and MPD's + representation of 24 bit is padded to 32 bit (4 + bytes per sample) */ + return channels * 4; +#endif + + return audio_format.GetFrameSize(); +} + +unsigned +PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept +{ +#ifdef ENABLE_DSD + if (dsd_u16) + /* DSD_U16 combines two 8-bit "samples" in one 16-bit + "sample" */ + sample_rate /= 2; + + if (dsd_u32) + /* DSD_U32 combines four 8-bit "samples" in one 32-bit + "sample" */ + sample_rate /= 4; + + if (dop) + /* DoP packs two 8-bit "samples" in one 24-bit + "sample" */ + sample_rate /= 2; +#endif + + return sample_rate; +} + +unsigned +PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept +{ +#ifdef ENABLE_DSD + if (dsd_u16) + sample_rate *= 2; + + if (dsd_u32) + sample_rate *= 4; + + if (dop) + sample_rate *= 2; +#endif + + return sample_rate; +} + +ConstBuffer +PcmExport::Export(ConstBuffer data) noexcept +{ + if (alsa_channel_order != SampleFormat::UNDEFINED) + data = ToAlsaChannelOrder(order_buffer, data, + alsa_channel_order, channels); + +#ifdef ENABLE_DSD + if (dsd_u16) + data = Dsd8To16(dop_buffer, channels, + ConstBuffer::FromVoid(data)) + .ToVoid(); + + if (dsd_u32) + data = Dsd8To32(dop_buffer, channels, + ConstBuffer::FromVoid(data)) + .ToVoid(); + + if (dop) + data = pcm_dsd_to_dop(dop_buffer, channels, + ConstBuffer::FromVoid(data)) + .ToVoid(); +#endif + + if (pack24) { + const auto src = ConstBuffer::FromVoid(data); + const size_t num_samples = src.size; + const size_t dest_size = num_samples * 3; + uint8_t *dest = (uint8_t *)pack_buffer.Get(dest_size); + assert(dest != nullptr); + + pcm_pack_24(dest, src.begin(), src.end()); + + data.data = dest; + data.size = dest_size; + } else if (shift8) { + const auto src = ConstBuffer::FromVoid(data); + + uint32_t *dest = (uint32_t *)pack_buffer.Get(data.size); + data.data = dest; + + for (auto i : src) + *dest++ = i << 8; + } + + if (reverse_endian > 0) { + assert(reverse_endian >= 2); + + const auto src = ConstBuffer::FromVoid(data); + + uint8_t *dest = (uint8_t *)reverse_buffer.Get(data.size); + assert(dest != nullptr); + data.data = dest; + + reverse_bytes(dest, src.begin(), src.end(), reverse_endian); + } + + return data; +} + +size_t +PcmExport::CalcSourceSize(size_t size) const noexcept +{ + if (pack24) + /* 32 bit to 24 bit conversion (4 to 3 bytes) */ + size = (size / 3) * 4; + +#ifdef ENABLE_DSD + if (dop) + /* DoP doubles the transport size */ + size /= 2; +#endif + + return size; +} diff --git a/src/pcm/Export.hxx b/src/pcm/Export.hxx new file mode 100644 index 000000000..48da4c272 --- /dev/null +++ b/src/pcm/Export.hxx @@ -0,0 +1,189 @@ +/* + * Copyright 2003-2018 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. + */ + +#ifndef PCM_EXPORT_HXX +#define PCM_EXPORT_HXX + +#include "SampleFormat.hxx" +#include "PcmBuffer.hxx" +#include "config.h" + +template struct ConstBuffer; +struct AudioFormat; + +/** + * An object that handles export of PCM samples to some instance + * outside of MPD. It has a few more options to tweak the binary + * representation which are not supported by the #PcmConvert library. + */ +class PcmExport { + /** + * This buffer is used to reorder channels. + * + * @see #alsa_channel_order + */ + PcmBuffer order_buffer; + +#ifdef ENABLE_DSD + /** + * The buffer is used to convert DSD samples to the + * DoP format. + * + * @see #dop + */ + PcmBuffer dop_buffer; +#endif + + /** + * The buffer is used to pack samples, removing padding. + * + * @see #pack24 + */ + PcmBuffer pack_buffer; + + /** + * The buffer is used to reverse the byte order. + * + * @see #reverse_endian + */ + PcmBuffer reverse_buffer; + + /** + * The number of channels. + */ + uint8_t channels; + + /** + * Convert the given buffer from FLAC channel order to ALSA + * channel order using ToAlsaChannelOrder()? + * + * If this value is SampleFormat::UNDEFINED, then no channel + * reordering is applied, otherwise this is the input sample + * format. + */ + SampleFormat alsa_channel_order; + +#ifdef ENABLE_DSD + /** + * Convert DSD (U8) to DSD_U16? + */ + bool dsd_u16; + + /** + * Convert DSD (U8) to DSD_U32? + */ + bool dsd_u32; + + /** + * Convert DSD to DSD-over-PCM (DoP)? Input format must be + * SampleFormat::DSD and output format must be + * SampleFormat::S24_P32. + */ + bool dop; +#endif + + /** + * Convert (padded) 24 bit samples to 32 bit by shifting 8 + * bits to the left? + */ + bool shift8; + + /** + * Pack 24 bit samples? + */ + bool pack24; + + /** + * Export the samples in reverse byte order? A non-zero value + * means the option is enabled and represents the size of each + * sample (2 or bigger). + */ + uint8_t reverse_endian; + +public: + struct Params { + bool alsa_channel_order = false; +#ifdef ENABLE_DSD + bool dsd_u16 = false; + bool dsd_u32 = false; + bool dop = false; +#endif + bool shift8 = false; + bool pack24 = false; + bool reverse_endian = false; + + /** + * Calculate the output sample rate, given a specific input + * sample rate. Usually, both are the same; however, with + * DSD_U32, four input bytes (= 4 * 8 bits) are combined to + * one output word (32 bits), dividing the sample rate by 4. + */ + gcc_pure + unsigned CalcOutputSampleRate(unsigned input_sample_rate) const noexcept; + + /** + * The inverse of CalcOutputSampleRate(). + */ + gcc_pure + unsigned CalcInputSampleRate(unsigned output_sample_rate) const noexcept; + }; + + /** + * Open the object. + * + * There is no "close" method. This function may be called multiple + * times to reuse the object. + * + * This function cannot fail. + * + * @param channels the number of channels; ignored unless dop is set + */ + void Open(SampleFormat sample_format, unsigned channels, + Params params) noexcept; + + /** + * Reset the filter's state, e.g. drop/flush buffers. + */ + void Reset() noexcept { + } + + /** + * Calculate the size of one output frame. + */ + gcc_pure + size_t GetFrameSize(const AudioFormat &audio_format) const noexcept; + + /** + * Export a PCM buffer. + * + * @param src the source PCM buffer + * @return the destination buffer (may be a pointer to the source buffer) + */ + ConstBuffer Export(ConstBuffer src) noexcept; + + /** + * Converts the number of consumed bytes from the pcm_export() + * destination buffer to the according number of bytes from the + * pcm_export() source buffer. + */ + gcc_pure + size_t CalcSourceSize(size_t dest_size) const noexcept; +}; + +#endif diff --git a/src/pcm/PcmDop.cxx b/src/pcm/PcmDop.cxx deleted file mode 100644 index a0a6bdae6..000000000 --- a/src/pcm/PcmDop.cxx +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2003-2018 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 "PcmDop.hxx" -#include "PcmBuffer.hxx" -#include "AudioFormat.hxx" -#include "util/ConstBuffer.hxx" - -#include - -constexpr -static inline uint32_t -pcm_two_dsd_to_dop_marker1(uint8_t a, uint8_t b) noexcept -{ - return 0xff050000 | (a << 8) | b; -} - -constexpr -static inline uint32_t -pcm_two_dsd_to_dop_marker2(uint8_t a, uint8_t b) noexcept -{ - return 0xfffa0000 | (a << 8) | b; -} - -ConstBuffer -pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels, - ConstBuffer _src) noexcept -{ - assert(audio_valid_channel_count(channels)); - assert(_src.size % channels == 0); - - const size_t num_src_samples = _src.size; - const size_t num_src_frames = num_src_samples / channels; - - /* this rounds down and discards up to 3 odd frames; not - elegant, but good enough for now */ - const size_t num_dop_quads = num_src_frames / 4; - const size_t num_frames = num_dop_quads * 2; - const size_t num_samples = num_frames * channels; - - uint32_t *const dest0 = (uint32_t *)buffer.GetT(num_samples), - *dest = dest0; - - auto src = _src.data; - for (size_t i = num_dop_quads; i > 0; --i) { - for (unsigned c = channels; c > 0; --c) { - /* each 24 bit sample has 16 DSD sample bits - plus the magic 0x05 marker */ - - *dest++ = pcm_two_dsd_to_dop_marker1(src[0], src[channels]); - - /* seek the source pointer to the next - channel */ - ++src; - } - - /* skip the second byte of each channel, because we - have already copied it */ - src += channels; - - for (unsigned c = channels; c > 0; --c) { - /* each 24 bit sample has 16 DSD sample bits - plus the magic 0xfa marker */ - - *dest++ = pcm_two_dsd_to_dop_marker2(src[0], src[channels]); - - /* seek the source pointer to the next - channel */ - ++src; - } - - /* skip the second byte of each channel, because we - have already copied it */ - src += channels; - } - - return { dest0, num_samples }; -} diff --git a/src/pcm/PcmDop.hxx b/src/pcm/PcmDop.hxx deleted file mode 100644 index 0a2c9b205..000000000 --- a/src/pcm/PcmDop.hxx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2003-2018 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. - */ - -#ifndef MPD_PCM_DOP_HXX -#define MPD_PCM_DOP_HXX - -#include - -class PcmBuffer; -template struct ConstBuffer; - -/** - * Pack DSD 1 bit samples into (padded) 24 bit PCM samples for - * playback over USB, according to the DoP standard: - * http://dsd-guide.com/dop-open-standard - */ -ConstBuffer -pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels, - ConstBuffer src) noexcept; - -#endif diff --git a/src/pcm/PcmExport.cxx b/src/pcm/PcmExport.cxx deleted file mode 100644 index 7d2f18588..000000000 --- a/src/pcm/PcmExport.cxx +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2003-2018 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 "PcmExport.hxx" -#include "AudioFormat.hxx" -#include "Order.hxx" -#include "PcmPack.hxx" -#include "util/ByteReverse.hxx" -#include "util/ConstBuffer.hxx" - -#ifdef ENABLE_DSD -#include "Dsd16.hxx" -#include "Dsd32.hxx" -#include "PcmDsd.hxx" -#include "PcmDop.hxx" -#endif - -#include - -void -PcmExport::Open(SampleFormat sample_format, unsigned _channels, - Params params) noexcept -{ - assert(audio_valid_sample_format(sample_format)); - - channels = _channels; - alsa_channel_order = params.alsa_channel_order - ? sample_format - : SampleFormat::UNDEFINED; - -#ifdef ENABLE_DSD - assert((params.dsd_u16 + params.dsd_u32 + params.dop) <= 1); - assert(!params.dop || audio_valid_channel_count(_channels)); - - dsd_u16 = params.dsd_u16 && sample_format == SampleFormat::DSD; - if (dsd_u16) - /* after the conversion to DSD_U16, the DSD samples - are stuffed inside fake 16 bit samples */ - sample_format = SampleFormat::S16; - - dsd_u32 = params.dsd_u32 && sample_format == SampleFormat::DSD; - if (dsd_u32) - /* after the conversion to DSD_U32, the DSD samples - are stuffed inside fake 32 bit samples */ - sample_format = SampleFormat::S32; - - dop = params.dop && sample_format == SampleFormat::DSD; - if (dop) - /* after the conversion to DoP, the DSD - samples are stuffed inside fake 24 bit samples */ - sample_format = SampleFormat::S24_P32; -#endif - - shift8 = params.shift8 && sample_format == SampleFormat::S24_P32; - pack24 = params.pack24 && sample_format == SampleFormat::S24_P32; - - assert(!shift8 || !pack24); - - reverse_endian = 0; - if (params.reverse_endian) { - size_t sample_size = pack24 - ? 3 - : sample_format_size(sample_format); - assert(sample_size <= 0xff); - - if (sample_size > 1) - reverse_endian = sample_size; - } -} - -size_t -PcmExport::GetFrameSize(const AudioFormat &audio_format) const noexcept -{ - if (pack24) - /* packed 24 bit samples (3 bytes per sample) */ - return audio_format.channels * 3; - -#ifdef ENABLE_DSD - if (dsd_u16) - return channels * 2; - - if (dsd_u32) - return channels * 4; - - if (dop) - /* the DSD-over-USB draft says that DSD 1-bit samples - are enclosed within 24 bit samples, and MPD's - representation of 24 bit is padded to 32 bit (4 - bytes per sample) */ - return channels * 4; -#endif - - return audio_format.GetFrameSize(); -} - -unsigned -PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept -{ -#ifdef ENABLE_DSD - if (dsd_u16) - /* DSD_U16 combines two 8-bit "samples" in one 16-bit - "sample" */ - sample_rate /= 2; - - if (dsd_u32) - /* DSD_U32 combines four 8-bit "samples" in one 32-bit - "sample" */ - sample_rate /= 4; - - if (dop) - /* DoP packs two 8-bit "samples" in one 24-bit - "sample" */ - sample_rate /= 2; -#endif - - return sample_rate; -} - -unsigned -PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept -{ -#ifdef ENABLE_DSD - if (dsd_u16) - sample_rate *= 2; - - if (dsd_u32) - sample_rate *= 4; - - if (dop) - sample_rate *= 2; -#endif - - return sample_rate; -} - -ConstBuffer -PcmExport::Export(ConstBuffer data) noexcept -{ - if (alsa_channel_order != SampleFormat::UNDEFINED) - data = ToAlsaChannelOrder(order_buffer, data, - alsa_channel_order, channels); - -#ifdef ENABLE_DSD - if (dsd_u16) - data = Dsd8To16(dop_buffer, channels, - ConstBuffer::FromVoid(data)) - .ToVoid(); - - if (dsd_u32) - data = Dsd8To32(dop_buffer, channels, - ConstBuffer::FromVoid(data)) - .ToVoid(); - - if (dop) - data = pcm_dsd_to_dop(dop_buffer, channels, - ConstBuffer::FromVoid(data)) - .ToVoid(); -#endif - - if (pack24) { - const auto src = ConstBuffer::FromVoid(data); - const size_t num_samples = src.size; - const size_t dest_size = num_samples * 3; - uint8_t *dest = (uint8_t *)pack_buffer.Get(dest_size); - assert(dest != nullptr); - - pcm_pack_24(dest, src.begin(), src.end()); - - data.data = dest; - data.size = dest_size; - } else if (shift8) { - const auto src = ConstBuffer::FromVoid(data); - - uint32_t *dest = (uint32_t *)pack_buffer.Get(data.size); - data.data = dest; - - for (auto i : src) - *dest++ = i << 8; - } - - if (reverse_endian > 0) { - assert(reverse_endian >= 2); - - const auto src = ConstBuffer::FromVoid(data); - - uint8_t *dest = (uint8_t *)reverse_buffer.Get(data.size); - assert(dest != nullptr); - data.data = dest; - - reverse_bytes(dest, src.begin(), src.end(), reverse_endian); - } - - return data; -} - -size_t -PcmExport::CalcSourceSize(size_t size) const noexcept -{ - if (pack24) - /* 32 bit to 24 bit conversion (4 to 3 bytes) */ - size = (size / 3) * 4; - -#ifdef ENABLE_DSD - if (dop) - /* DoP doubles the transport size */ - size /= 2; -#endif - - return size; -} diff --git a/src/pcm/PcmExport.hxx b/src/pcm/PcmExport.hxx deleted file mode 100644 index 48da4c272..000000000 --- a/src/pcm/PcmExport.hxx +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2003-2018 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. - */ - -#ifndef PCM_EXPORT_HXX -#define PCM_EXPORT_HXX - -#include "SampleFormat.hxx" -#include "PcmBuffer.hxx" -#include "config.h" - -template struct ConstBuffer; -struct AudioFormat; - -/** - * An object that handles export of PCM samples to some instance - * outside of MPD. It has a few more options to tweak the binary - * representation which are not supported by the #PcmConvert library. - */ -class PcmExport { - /** - * This buffer is used to reorder channels. - * - * @see #alsa_channel_order - */ - PcmBuffer order_buffer; - -#ifdef ENABLE_DSD - /** - * The buffer is used to convert DSD samples to the - * DoP format. - * - * @see #dop - */ - PcmBuffer dop_buffer; -#endif - - /** - * The buffer is used to pack samples, removing padding. - * - * @see #pack24 - */ - PcmBuffer pack_buffer; - - /** - * The buffer is used to reverse the byte order. - * - * @see #reverse_endian - */ - PcmBuffer reverse_buffer; - - /** - * The number of channels. - */ - uint8_t channels; - - /** - * Convert the given buffer from FLAC channel order to ALSA - * channel order using ToAlsaChannelOrder()? - * - * If this value is SampleFormat::UNDEFINED, then no channel - * reordering is applied, otherwise this is the input sample - * format. - */ - SampleFormat alsa_channel_order; - -#ifdef ENABLE_DSD - /** - * Convert DSD (U8) to DSD_U16? - */ - bool dsd_u16; - - /** - * Convert DSD (U8) to DSD_U32? - */ - bool dsd_u32; - - /** - * Convert DSD to DSD-over-PCM (DoP)? Input format must be - * SampleFormat::DSD and output format must be - * SampleFormat::S24_P32. - */ - bool dop; -#endif - - /** - * Convert (padded) 24 bit samples to 32 bit by shifting 8 - * bits to the left? - */ - bool shift8; - - /** - * Pack 24 bit samples? - */ - bool pack24; - - /** - * Export the samples in reverse byte order? A non-zero value - * means the option is enabled and represents the size of each - * sample (2 or bigger). - */ - uint8_t reverse_endian; - -public: - struct Params { - bool alsa_channel_order = false; -#ifdef ENABLE_DSD - bool dsd_u16 = false; - bool dsd_u32 = false; - bool dop = false; -#endif - bool shift8 = false; - bool pack24 = false; - bool reverse_endian = false; - - /** - * Calculate the output sample rate, given a specific input - * sample rate. Usually, both are the same; however, with - * DSD_U32, four input bytes (= 4 * 8 bits) are combined to - * one output word (32 bits), dividing the sample rate by 4. - */ - gcc_pure - unsigned CalcOutputSampleRate(unsigned input_sample_rate) const noexcept; - - /** - * The inverse of CalcOutputSampleRate(). - */ - gcc_pure - unsigned CalcInputSampleRate(unsigned output_sample_rate) const noexcept; - }; - - /** - * Open the object. - * - * There is no "close" method. This function may be called multiple - * times to reuse the object. - * - * This function cannot fail. - * - * @param channels the number of channels; ignored unless dop is set - */ - void Open(SampleFormat sample_format, unsigned channels, - Params params) noexcept; - - /** - * Reset the filter's state, e.g. drop/flush buffers. - */ - void Reset() noexcept { - } - - /** - * Calculate the size of one output frame. - */ - gcc_pure - size_t GetFrameSize(const AudioFormat &audio_format) const noexcept; - - /** - * Export a PCM buffer. - * - * @param src the source PCM buffer - * @return the destination buffer (may be a pointer to the source buffer) - */ - ConstBuffer Export(ConstBuffer src) noexcept; - - /** - * Converts the number of consumed bytes from the pcm_export() - * destination buffer to the according number of bytes from the - * pcm_export() source buffer. - */ - gcc_pure - size_t CalcSourceSize(size_t dest_size) const noexcept; -}; - -#endif diff --git a/src/pcm/meson.build b/src/pcm/meson.build index e7ac5433b..40a3925f0 100644 --- a/src/pcm/meson.build +++ b/src/pcm/meson.build @@ -5,9 +5,9 @@ pcm_sources = [ 'SampleFormat.cxx', 'Interleave.cxx', 'PcmBuffer.cxx', - 'PcmExport.cxx', + 'Export.cxx', 'PcmConvert.cxx', - 'PcmDop.cxx', + 'Dop.cxx', 'Volume.cxx', 'Silence.cxx', 'PcmMix.cxx', -- cgit v1.2.3