From 28e07e900f397bb2146a02b166cbc00e8ad40a5d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 Jun 2019 22:20:28 +0200 Subject: [PATCH] pcm/Export: convert the DSD bools to an enum These options are exclusive. --- src/lib/alsa/HwSetup.cxx | 7 +- src/output/plugins/AlsaOutputPlugin.cxx | 6 +- src/output/plugins/OSXOutputPlugin.cxx | 6 +- src/pcm/Export.cxx | 99 +++++++++++++++++++------ src/pcm/Export.hxx | 42 ++++++----- test/test_pcm_export.cxx | 6 +- 6 files changed, 113 insertions(+), 53 deletions(-) diff --git a/src/lib/alsa/HwSetup.cxx b/src/lib/alsa/HwSetup.cxx index e36d78084..a405f6bc1 100644 --- a/src/lib/alsa/HwSetup.cxx +++ b/src/lib/alsa/HwSetup.cxx @@ -95,8 +95,7 @@ TryFormatDsd(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, #if defined(ENABLE_DSD) && defined(HAVE_ALSA_DSD_U32) if (err == 0) { - params.dsd_u16 = false; - params.dsd_u32 = false; + params.dsd_mode = PcmExport::DsdMode::NONE; } if (err == -EINVAL && fmt == SND_PCM_FORMAT_DSD_U8) { @@ -106,7 +105,7 @@ TryFormatDsd(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, : SND_PCM_FORMAT_DSD_U32_BE; err = TryFormatOrByteSwap(pcm, hwparams, fmt, params); if (err == 0) - params.dsd_u32 = true; + params.dsd_mode = PcmExport::DsdMode::U32; else fmt = SND_PCM_FORMAT_DSD_U8; } @@ -118,7 +117,7 @@ TryFormatDsd(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, : SND_PCM_FORMAT_DSD_U16_BE; err = TryFormatOrByteSwap(pcm, hwparams, fmt, params); if (err == 0) - params.dsd_u16 = true; + params.dsd_mode = PcmExport::DsdMode::U16; else fmt = SND_PCM_FORMAT_DSD_U8; } diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 13dad8a56..8b16134b4 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -558,12 +558,12 @@ AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params ¶ms std::exception_ptr dop_error; if (dop && audio_format.format == SampleFormat::DSD) { try { - params.dop = true; + params.dsd_mode = PcmExport::DsdMode::DOP; SetupDop(audio_format, params); return; } catch (...) { dop_error = std::current_exception(); - params.dop = false; + params.dsd_mode = PcmExport::DsdMode::NONE; } } @@ -663,7 +663,7 @@ AlsaOutput::Open(AudioFormat &audio_format) snd_pcm_nonblock(pcm, 1); #ifdef ENABLE_DSD - if (params.dop) + if (params.dsd_mode == PcmExport::DsdMode::DOP) FormatDebug(alsa_output_domain, "DoP (DSD over PCM) enabled"); #endif diff --git a/src/output/plugins/OSXOutputPlugin.cxx b/src/output/plugins/OSXOutputPlugin.cxx index 46cb3e98f..f20600d92 100644 --- a/src/output/plugins/OSXOutputPlugin.cxx +++ b/src/output/plugins/OSXOutputPlugin.cxx @@ -787,7 +787,7 @@ OSXOutput::Open(AudioFormat &audio_format) #ifdef ENABLE_DSD if (dop && audio_format.format == SampleFormat::DSD) { asbd.mBitsPerChannel = 24; - params.dop = true; + params.dsd_mode = PcmExport::DsdMode::DOP; asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate); asbd.mBytesPerPacket = 4 * audio_format.channels; @@ -802,14 +802,14 @@ OSXOutput::Open(AudioFormat &audio_format) #ifdef ENABLE_DSD if(audio_format.format == SampleFormat::DSD && sample_rate != asbd.mSampleRate) { // fall back to PCM in case sample_rate cannot be synchronized - params.dop = false; + params.dsd_mode = PcmExport::DsdMode::NONE; audio_format.format = SampleFormat::S32; asbd.mBitsPerChannel = 32; asbd.mBytesPerPacket = audio_format.GetFrameSize(); asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate); asbd.mBytesPerFrame = asbd.mBytesPerPacket; } - dop_enabled = params.dop; + dop_enabled = params.dsd_mode == PcmExport::DsdMode::DOP; #endif OSStatus status = diff --git a/src/pcm/Export.cxx b/src/pcm/Export.cxx index fb77f43f8..7dcaebe16 100644 --- a/src/pcm/Export.cxx +++ b/src/pcm/Export.cxx @@ -45,28 +45,36 @@ PcmExport::Open(SampleFormat sample_format, unsigned _channels, : SampleFormat::UNDEFINED; #ifdef ENABLE_DSD - assert((params.dsd_u16 + params.dsd_u32 + params.dop) <= 1); - assert(!params.dop || audio_valid_channel_count(_channels)); + assert(params.dsd_mode != DsdMode::DOP || + audio_valid_channel_count(_channels)); - dsd_u16 = params.dsd_u16 && sample_format == SampleFormat::DSD; - if (dsd_u16) + dsd_mode = sample_format == SampleFormat::DSD + ? params.dsd_mode + : DsdMode::NONE; + + switch (dsd_mode) { + case DsdMode::NONE: + break; + + case DsdMode::U16: /* after the conversion to DSD_U16, the DSD samples are stuffed inside fake 16 bit samples */ sample_format = SampleFormat::S16; + break; - dsd_u32 = params.dsd_u32 && sample_format == SampleFormat::DSD; - if (dsd_u32) + case DsdMode::U32: /* after the conversion to DSD_U32, the DSD samples are stuffed inside fake 32 bit samples */ sample_format = SampleFormat::S32; + break; - dop = params.dop && sample_format == SampleFormat::DSD; - if (dop) { + case DsdMode::DOP: dop_converter.Open(_channels); /* after the conversion to DoP, the DSD samples are stuffed inside fake 24 bit samples */ sample_format = SampleFormat::S24_P32; + break; } #endif @@ -91,8 +99,16 @@ void PcmExport::Reset() noexcept { #ifdef ENABLE_DSD - if (dop) + switch (dsd_mode) { + case DsdMode::NONE: + case DsdMode::U16: + case DsdMode::U32: + break; + + case DsdMode::DOP: dop_converter.Reset(); + break; + } #endif } @@ -104,18 +120,23 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const noexcept return audio_format.channels * 3; #ifdef ENABLE_DSD - if (dsd_u16) + switch (dsd_mode) { + case DsdMode::NONE: + break; + + case DsdMode::U16: return channels * 2; - if (dsd_u32) + case DsdMode::U32: return channels * 4; - if (dop) + case DsdMode::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(); @@ -125,20 +146,28 @@ unsigned PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept { #ifdef ENABLE_DSD - if (dsd_u16) + switch (dsd_mode) { + case DsdMode::NONE: + break; + + case DsdMode::U16: /* DSD_U16 combines two 8-bit "samples" in one 16-bit "sample" */ sample_rate /= 2; + break; - if (dsd_u32) + case DsdMode::U32: /* DSD_U32 combines four 8-bit "samples" in one 32-bit "sample" */ sample_rate /= 4; + break; - if (dop) + case DsdMode::DOP: /* DoP packs two 8-bit "samples" in one 24-bit "sample" */ sample_rate /= 2; + break; + } #endif return sample_rate; @@ -148,14 +177,22 @@ unsigned PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept { #ifdef ENABLE_DSD - if (dsd_u16) - sample_rate *= 2; + switch (dsd_mode) { + case DsdMode::NONE: + break; - if (dsd_u32) + case DsdMode::U16: + sample_rate *= 2; + break; + + case DsdMode::U32: sample_rate *= 4; + break; - if (dop) + case DsdMode::DOP: sample_rate *= 2; + break; + } #endif return sample_rate; @@ -169,19 +206,27 @@ PcmExport::Export(ConstBuffer data) noexcept alsa_channel_order, channels); #ifdef ENABLE_DSD - if (dsd_u16) + switch (dsd_mode) { + case DsdMode::NONE: + break; + + case DsdMode::U16: data = Dsd8To16(dsd_buffer, channels, ConstBuffer::FromVoid(data)) .ToVoid(); + break; - if (dsd_u32) + case DsdMode::U32: data = Dsd8To32(dsd_buffer, channels, ConstBuffer::FromVoid(data)) .ToVoid(); + break; - if (dop) + case DsdMode::DOP: data = dop_converter.Convert(ConstBuffer::FromVoid(data)) .ToVoid(); + break; + } #endif if (pack24) { @@ -228,9 +273,17 @@ PcmExport::CalcSourceSize(size_t size) const noexcept size = (size / 3) * 4; #ifdef ENABLE_DSD - if (dop) + switch (dsd_mode) { + case DsdMode::NONE: + case DsdMode::U16: + case DsdMode::U32: + break; + + case DsdMode::DOP: /* DoP doubles the transport size */ size /= 2; + break; + } #endif return size; diff --git a/src/pcm/Export.hxx b/src/pcm/Export.hxx index 91c50e2dc..416e2351c 100644 --- a/src/pcm/Export.hxx +++ b/src/pcm/Export.hxx @@ -28,6 +28,8 @@ #include "Dop.hxx" #endif +#include + template struct ConstBuffer; struct AudioFormat; @@ -88,22 +90,30 @@ class PcmExport { SampleFormat alsa_channel_order; #ifdef ENABLE_DSD - /** - * Convert DSD (U8) to DSD_U16? - */ - bool dsd_u16; +public: + enum class DsdMode : uint8_t { + NONE, - /** - * Convert DSD (U8) to DSD_U32? - */ - bool dsd_u32; + /** + * Convert DSD (U8) to DSD_U16? + */ + U16, - /** - * Convert DSD to DSD-over-PCM (DoP)? Input format must be - * SampleFormat::DSD and output format must be - * SampleFormat::S24_P32. - */ - bool dop; + /** + * Convert DSD (U8) to DSD_U32? + */ + U32, + + /** + * Convert DSD to DSD-over-PCM (DoP)? Input format + * must be SampleFormat::DSD and output format must be + * SampleFormat::S24_P32. + */ + DOP, + }; + +private: + DsdMode dsd_mode; #endif /** @@ -128,9 +138,7 @@ public: struct Params { bool alsa_channel_order = false; #ifdef ENABLE_DSD - bool dsd_u16 = false; - bool dsd_u32 = false; - bool dop = false; + DsdMode dsd_mode = DsdMode::NONE; #endif bool shift8 = false; bool pack24 = false; diff --git a/test/test_pcm_export.cxx b/test/test_pcm_export.cxx index 9411bc580..67df4a2b8 100644 --- a/test/test_pcm_export.cxx +++ b/test/test_pcm_export.cxx @@ -141,7 +141,7 @@ TEST(PcmTest, ExportDsdU16) }; PcmExport::Params params; - params.dsd_u16 = true; + params.dsd_mode = PcmExport::DsdMode::U16; EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u); EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u); @@ -171,7 +171,7 @@ TEST(PcmTest, ExportDsdU32) }; PcmExport::Params params; - params.dsd_u32 = true; + params.dsd_mode = PcmExport::DsdMode::U32; EXPECT_EQ(params.CalcOutputSampleRate(705600u), 176400u); EXPECT_EQ(params.CalcInputSampleRate(176400u), 705600u); @@ -199,7 +199,7 @@ TEST(PcmTest, ExportDop) }; PcmExport::Params params; - params.dop = true; + params.dsd_mode = PcmExport::DsdMode::DOP; EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u); EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u);