pcm/Export: convert the DSD bools to an enum

These options are exclusive.
This commit is contained in:
Max Kellermann 2019-06-17 22:20:28 +02:00
parent c75dc4a647
commit 28e07e900f
6 changed files with 113 additions and 53 deletions

View File

@ -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;
}

View File

@ -558,12 +558,12 @@ AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params
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

View File

@ -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 =

View File

@ -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<void> 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<uint8_t>::FromVoid(data))
.ToVoid();
break;
if (dsd_u32)
case DsdMode::U32:
data = Dsd8To32(dsd_buffer, channels,
ConstBuffer<uint8_t>::FromVoid(data))
.ToVoid();
break;
if (dop)
case DsdMode::DOP:
data = dop_converter.Convert(ConstBuffer<uint8_t>::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;

View File

@ -28,6 +28,8 @@
#include "Dop.hxx"
#endif
#include <stdint.h>
template<typename T> 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;

View File

@ -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);