pcm/Export: convert the DSD bools to an enum
These options are exclusive.
This commit is contained in:
parent
c75dc4a647
commit
28e07e900f
@ -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 defined(ENABLE_DSD) && defined(HAVE_ALSA_DSD_U32)
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
params.dsd_u16 = false;
|
params.dsd_mode = PcmExport::DsdMode::NONE;
|
||||||
params.dsd_u32 = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == -EINVAL && fmt == SND_PCM_FORMAT_DSD_U8) {
|
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;
|
: SND_PCM_FORMAT_DSD_U32_BE;
|
||||||
err = TryFormatOrByteSwap(pcm, hwparams, fmt, params);
|
err = TryFormatOrByteSwap(pcm, hwparams, fmt, params);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
params.dsd_u32 = true;
|
params.dsd_mode = PcmExport::DsdMode::U32;
|
||||||
else
|
else
|
||||||
fmt = SND_PCM_FORMAT_DSD_U8;
|
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;
|
: SND_PCM_FORMAT_DSD_U16_BE;
|
||||||
err = TryFormatOrByteSwap(pcm, hwparams, fmt, params);
|
err = TryFormatOrByteSwap(pcm, hwparams, fmt, params);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
params.dsd_u16 = true;
|
params.dsd_mode = PcmExport::DsdMode::U16;
|
||||||
else
|
else
|
||||||
fmt = SND_PCM_FORMAT_DSD_U8;
|
fmt = SND_PCM_FORMAT_DSD_U8;
|
||||||
}
|
}
|
||||||
|
@ -558,12 +558,12 @@ AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params ¶ms
|
|||||||
std::exception_ptr dop_error;
|
std::exception_ptr dop_error;
|
||||||
if (dop && audio_format.format == SampleFormat::DSD) {
|
if (dop && audio_format.format == SampleFormat::DSD) {
|
||||||
try {
|
try {
|
||||||
params.dop = true;
|
params.dsd_mode = PcmExport::DsdMode::DOP;
|
||||||
SetupDop(audio_format, params);
|
SetupDop(audio_format, params);
|
||||||
return;
|
return;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
dop_error = std::current_exception();
|
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);
|
snd_pcm_nonblock(pcm, 1);
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (params.dop)
|
if (params.dsd_mode == PcmExport::DsdMode::DOP)
|
||||||
FormatDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
|
FormatDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -787,7 +787,7 @@ OSXOutput::Open(AudioFormat &audio_format)
|
|||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (dop && audio_format.format == SampleFormat::DSD) {
|
if (dop && audio_format.format == SampleFormat::DSD) {
|
||||||
asbd.mBitsPerChannel = 24;
|
asbd.mBitsPerChannel = 24;
|
||||||
params.dop = true;
|
params.dsd_mode = PcmExport::DsdMode::DOP;
|
||||||
asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate);
|
asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate);
|
||||||
asbd.mBytesPerPacket = 4 * audio_format.channels;
|
asbd.mBytesPerPacket = 4 * audio_format.channels;
|
||||||
|
|
||||||
@ -802,14 +802,14 @@ OSXOutput::Open(AudioFormat &audio_format)
|
|||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if(audio_format.format == SampleFormat::DSD && sample_rate != asbd.mSampleRate) { // fall back to PCM in case sample_rate cannot be synchronized
|
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;
|
audio_format.format = SampleFormat::S32;
|
||||||
asbd.mBitsPerChannel = 32;
|
asbd.mBitsPerChannel = 32;
|
||||||
asbd.mBytesPerPacket = audio_format.GetFrameSize();
|
asbd.mBytesPerPacket = audio_format.GetFrameSize();
|
||||||
asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate);
|
asbd.mSampleRate = params.CalcOutputSampleRate(audio_format.sample_rate);
|
||||||
asbd.mBytesPerFrame = asbd.mBytesPerPacket;
|
asbd.mBytesPerFrame = asbd.mBytesPerPacket;
|
||||||
}
|
}
|
||||||
dop_enabled = params.dop;
|
dop_enabled = params.dsd_mode == PcmExport::DsdMode::DOP;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OSStatus status =
|
OSStatus status =
|
||||||
|
@ -45,28 +45,36 @@ PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
|||||||
: SampleFormat::UNDEFINED;
|
: SampleFormat::UNDEFINED;
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
assert((params.dsd_u16 + params.dsd_u32 + params.dop) <= 1);
|
assert(params.dsd_mode != DsdMode::DOP ||
|
||||||
assert(!params.dop || audio_valid_channel_count(_channels));
|
audio_valid_channel_count(_channels));
|
||||||
|
|
||||||
dsd_u16 = params.dsd_u16 && sample_format == SampleFormat::DSD;
|
dsd_mode = sample_format == SampleFormat::DSD
|
||||||
if (dsd_u16)
|
? params.dsd_mode
|
||||||
|
: DsdMode::NONE;
|
||||||
|
|
||||||
|
switch (dsd_mode) {
|
||||||
|
case DsdMode::NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DsdMode::U16:
|
||||||
/* after the conversion to DSD_U16, the DSD samples
|
/* after the conversion to DSD_U16, the DSD samples
|
||||||
are stuffed inside fake 16 bit samples */
|
are stuffed inside fake 16 bit samples */
|
||||||
sample_format = SampleFormat::S16;
|
sample_format = SampleFormat::S16;
|
||||||
|
break;
|
||||||
|
|
||||||
dsd_u32 = params.dsd_u32 && sample_format == SampleFormat::DSD;
|
case DsdMode::U32:
|
||||||
if (dsd_u32)
|
|
||||||
/* after the conversion to DSD_U32, the DSD samples
|
/* after the conversion to DSD_U32, the DSD samples
|
||||||
are stuffed inside fake 32 bit samples */
|
are stuffed inside fake 32 bit samples */
|
||||||
sample_format = SampleFormat::S32;
|
sample_format = SampleFormat::S32;
|
||||||
|
break;
|
||||||
|
|
||||||
dop = params.dop && sample_format == SampleFormat::DSD;
|
case DsdMode::DOP:
|
||||||
if (dop) {
|
|
||||||
dop_converter.Open(_channels);
|
dop_converter.Open(_channels);
|
||||||
|
|
||||||
/* after the conversion to DoP, the DSD
|
/* after the conversion to DoP, the DSD
|
||||||
samples are stuffed inside fake 24 bit samples */
|
samples are stuffed inside fake 24 bit samples */
|
||||||
sample_format = SampleFormat::S24_P32;
|
sample_format = SampleFormat::S24_P32;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -91,8 +99,16 @@ void
|
|||||||
PcmExport::Reset() noexcept
|
PcmExport::Reset() noexcept
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (dop)
|
switch (dsd_mode) {
|
||||||
|
case DsdMode::NONE:
|
||||||
|
case DsdMode::U16:
|
||||||
|
case DsdMode::U32:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DsdMode::DOP:
|
||||||
dop_converter.Reset();
|
dop_converter.Reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,18 +120,23 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const noexcept
|
|||||||
return audio_format.channels * 3;
|
return audio_format.channels * 3;
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (dsd_u16)
|
switch (dsd_mode) {
|
||||||
|
case DsdMode::NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DsdMode::U16:
|
||||||
return channels * 2;
|
return channels * 2;
|
||||||
|
|
||||||
if (dsd_u32)
|
case DsdMode::U32:
|
||||||
return channels * 4;
|
return channels * 4;
|
||||||
|
|
||||||
if (dop)
|
case DsdMode::DOP:
|
||||||
/* the DSD-over-USB draft says that DSD 1-bit samples
|
/* the DSD-over-USB draft says that DSD 1-bit samples
|
||||||
are enclosed within 24 bit samples, and MPD's
|
are enclosed within 24 bit samples, and MPD's
|
||||||
representation of 24 bit is padded to 32 bit (4
|
representation of 24 bit is padded to 32 bit (4
|
||||||
bytes per sample) */
|
bytes per sample) */
|
||||||
return channels * 4;
|
return channels * 4;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return audio_format.GetFrameSize();
|
return audio_format.GetFrameSize();
|
||||||
@ -125,20 +146,28 @@ unsigned
|
|||||||
PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept
|
PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DSD
|
#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
|
/* DSD_U16 combines two 8-bit "samples" in one 16-bit
|
||||||
"sample" */
|
"sample" */
|
||||||
sample_rate /= 2;
|
sample_rate /= 2;
|
||||||
|
break;
|
||||||
|
|
||||||
if (dsd_u32)
|
case DsdMode::U32:
|
||||||
/* DSD_U32 combines four 8-bit "samples" in one 32-bit
|
/* DSD_U32 combines four 8-bit "samples" in one 32-bit
|
||||||
"sample" */
|
"sample" */
|
||||||
sample_rate /= 4;
|
sample_rate /= 4;
|
||||||
|
break;
|
||||||
|
|
||||||
if (dop)
|
case DsdMode::DOP:
|
||||||
/* DoP packs two 8-bit "samples" in one 24-bit
|
/* DoP packs two 8-bit "samples" in one 24-bit
|
||||||
"sample" */
|
"sample" */
|
||||||
sample_rate /= 2;
|
sample_rate /= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return sample_rate;
|
return sample_rate;
|
||||||
@ -148,14 +177,22 @@ unsigned
|
|||||||
PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept
|
PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (dsd_u16)
|
switch (dsd_mode) {
|
||||||
sample_rate *= 2;
|
case DsdMode::NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
if (dsd_u32)
|
case DsdMode::U16:
|
||||||
|
sample_rate *= 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DsdMode::U32:
|
||||||
sample_rate *= 4;
|
sample_rate *= 4;
|
||||||
|
break;
|
||||||
|
|
||||||
if (dop)
|
case DsdMode::DOP:
|
||||||
sample_rate *= 2;
|
sample_rate *= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return sample_rate;
|
return sample_rate;
|
||||||
@ -169,19 +206,27 @@ PcmExport::Export(ConstBuffer<void> data) noexcept
|
|||||||
alsa_channel_order, channels);
|
alsa_channel_order, channels);
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (dsd_u16)
|
switch (dsd_mode) {
|
||||||
|
case DsdMode::NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DsdMode::U16:
|
||||||
data = Dsd8To16(dsd_buffer, channels,
|
data = Dsd8To16(dsd_buffer, channels,
|
||||||
ConstBuffer<uint8_t>::FromVoid(data))
|
ConstBuffer<uint8_t>::FromVoid(data))
|
||||||
.ToVoid();
|
.ToVoid();
|
||||||
|
break;
|
||||||
|
|
||||||
if (dsd_u32)
|
case DsdMode::U32:
|
||||||
data = Dsd8To32(dsd_buffer, channels,
|
data = Dsd8To32(dsd_buffer, channels,
|
||||||
ConstBuffer<uint8_t>::FromVoid(data))
|
ConstBuffer<uint8_t>::FromVoid(data))
|
||||||
.ToVoid();
|
.ToVoid();
|
||||||
|
break;
|
||||||
|
|
||||||
if (dop)
|
case DsdMode::DOP:
|
||||||
data = dop_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
|
data = dop_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
|
||||||
.ToVoid();
|
.ToVoid();
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pack24) {
|
if (pack24) {
|
||||||
@ -228,9 +273,17 @@ PcmExport::CalcSourceSize(size_t size) const noexcept
|
|||||||
size = (size / 3) * 4;
|
size = (size / 3) * 4;
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#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 */
|
/* DoP doubles the transport size */
|
||||||
size /= 2;
|
size /= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include "Dop.hxx"
|
#include "Dop.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
template<typename T> struct ConstBuffer;
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
|
|
||||||
@ -88,22 +90,30 @@ class PcmExport {
|
|||||||
SampleFormat alsa_channel_order;
|
SampleFormat alsa_channel_order;
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
|
public:
|
||||||
|
enum class DsdMode : uint8_t {
|
||||||
|
NONE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD (U8) to DSD_U16?
|
* Convert DSD (U8) to DSD_U16?
|
||||||
*/
|
*/
|
||||||
bool dsd_u16;
|
U16,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD (U8) to DSD_U32?
|
* Convert DSD (U8) to DSD_U32?
|
||||||
*/
|
*/
|
||||||
bool dsd_u32;
|
U32,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD to DSD-over-PCM (DoP)? Input format must be
|
* Convert DSD to DSD-over-PCM (DoP)? Input format
|
||||||
* SampleFormat::DSD and output format must be
|
* must be SampleFormat::DSD and output format must be
|
||||||
* SampleFormat::S24_P32.
|
* SampleFormat::S24_P32.
|
||||||
*/
|
*/
|
||||||
bool dop;
|
DOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
DsdMode dsd_mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,9 +138,7 @@ public:
|
|||||||
struct Params {
|
struct Params {
|
||||||
bool alsa_channel_order = false;
|
bool alsa_channel_order = false;
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
bool dsd_u16 = false;
|
DsdMode dsd_mode = DsdMode::NONE;
|
||||||
bool dsd_u32 = false;
|
|
||||||
bool dop = false;
|
|
||||||
#endif
|
#endif
|
||||||
bool shift8 = false;
|
bool shift8 = false;
|
||||||
bool pack24 = false;
|
bool pack24 = false;
|
||||||
|
@ -141,7 +141,7 @@ TEST(PcmTest, ExportDsdU16)
|
|||||||
};
|
};
|
||||||
|
|
||||||
PcmExport::Params params;
|
PcmExport::Params params;
|
||||||
params.dsd_u16 = true;
|
params.dsd_mode = PcmExport::DsdMode::U16;
|
||||||
|
|
||||||
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u);
|
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u);
|
||||||
EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u);
|
EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u);
|
||||||
@ -171,7 +171,7 @@ TEST(PcmTest, ExportDsdU32)
|
|||||||
};
|
};
|
||||||
|
|
||||||
PcmExport::Params params;
|
PcmExport::Params params;
|
||||||
params.dsd_u32 = true;
|
params.dsd_mode = PcmExport::DsdMode::U32;
|
||||||
|
|
||||||
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 176400u);
|
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 176400u);
|
||||||
EXPECT_EQ(params.CalcInputSampleRate(176400u), 705600u);
|
EXPECT_EQ(params.CalcInputSampleRate(176400u), 705600u);
|
||||||
@ -199,7 +199,7 @@ TEST(PcmTest, ExportDop)
|
|||||||
};
|
};
|
||||||
|
|
||||||
PcmExport::Params params;
|
PcmExport::Params params;
|
||||||
params.dop = true;
|
params.dsd_mode = PcmExport::DsdMode::DOP;
|
||||||
|
|
||||||
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u);
|
EXPECT_EQ(params.CalcOutputSampleRate(705600u), 352800u);
|
||||||
EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u);
|
EXPECT_EQ(params.CalcInputSampleRate(352800u), 705600u);
|
||||||
|
Loading…
Reference in New Issue
Block a user