output/alsa, pcm: rename "DSD over USB" to "DoP"
The standard has been renamed since the early draft that was implemented in MPD.
This commit is contained in:
parent
6e04d66a35
commit
e5a28bfd8d
|
@ -465,7 +465,7 @@ libpcm_a_SOURCES = \
|
||||||
src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
|
src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
|
||||||
src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h \
|
src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h \
|
||||||
src/pcm/PcmDsd.cxx src/pcm/PcmDsd.hxx \
|
src/pcm/PcmDsd.cxx src/pcm/PcmDsd.hxx \
|
||||||
src/pcm/PcmDsdUsb.cxx src/pcm/PcmDsdUsb.hxx \
|
src/pcm/PcmDop.cxx src/pcm/PcmDop.hxx \
|
||||||
src/pcm/Volume.cxx src/pcm/Volume.hxx \
|
src/pcm/Volume.cxx src/pcm/Volume.hxx \
|
||||||
src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx \
|
src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx \
|
||||||
src/pcm/PcmChannels.cxx src/pcm/PcmChannels.hxx \
|
src/pcm/PcmChannels.cxx src/pcm/PcmChannels.hxx \
|
||||||
|
|
1
NEWS
1
NEWS
|
@ -55,6 +55,7 @@ ver 0.19 (not yet released)
|
||||||
- shine: new encoder plugin
|
- shine: new encoder plugin
|
||||||
* output
|
* output
|
||||||
- alsa: support native DSD playback
|
- alsa: support native DSD playback
|
||||||
|
- alsa: rename "DSD over USB" to "DoP"
|
||||||
* threads:
|
* threads:
|
||||||
- the update thread runs at "idle" priority
|
- the update thread runs at "idle" priority
|
||||||
- the output thread runs at "real-time" priority
|
- the output thread runs at "real-time" priority
|
||||||
|
|
10
doc/user.xml
10
doc/user.xml
|
@ -1991,15 +1991,15 @@ systemctl start mpd.socket</programlisting>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
<varname>dsd_usb</varname>
|
<varname>dop</varname>
|
||||||
<parameter>yes|no</parameter>
|
<parameter>yes|no</parameter>
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
If set to <parameter>yes</parameter>, then DSD over
|
If set to <parameter>yes</parameter>, then DSD over
|
||||||
USB according to the <ulink
|
PCM according to the <ulink
|
||||||
url="http://www.sonore.us/DoP_openStandard_1v1.pdf">pro
|
url="http://dsd-guide.com/dop-open-standard">DoP
|
||||||
posed standard by dCS and others</ulink> is enabled. This wraps
|
standard others</ulink> is enabled. This wraps DSD
|
||||||
DSD samples in fake 24 bit PCM, and is understood by
|
samples in fake 24 bit PCM, and is understood by
|
||||||
some DSD capable products, but may be harmful to
|
some DSD capable products, but may be harmful to
|
||||||
other hardware. Therefore, the default is
|
other hardware. Therefore, the default is
|
||||||
<parameter>no</parameter> and you can enable the
|
<parameter>no</parameter> and you can enable the
|
||||||
|
|
|
@ -62,12 +62,11 @@ struct AlsaOutput {
|
||||||
bool use_mmap;
|
bool use_mmap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable DSD over USB according to the dCS suggested
|
* Enable DSD over PCM according to the DoP standard standard?
|
||||||
* standard?
|
|
||||||
*
|
*
|
||||||
* @see http://www.dcsltd.co.uk/page/assets/DSDoverUSB.pdf
|
* @see http://dsd-guide.com/dop-open-standard
|
||||||
*/
|
*/
|
||||||
bool dsd_usb;
|
bool dop;
|
||||||
|
|
||||||
/** libasound's buffer_time setting (in microseconds) */
|
/** libasound's buffer_time setting (in microseconds) */
|
||||||
unsigned int buffer_time;
|
unsigned int buffer_time;
|
||||||
|
@ -153,7 +152,9 @@ AlsaOutput::Configure(const config_param ¶m, Error &error)
|
||||||
|
|
||||||
use_mmap = param.GetBlockValue("use_mmap", false);
|
use_mmap = param.GetBlockValue("use_mmap", false);
|
||||||
|
|
||||||
dsd_usb = param.GetBlockValue("dsd_usb", false);
|
dop = param.GetBlockValue("dop", false) ||
|
||||||
|
/* legacy name from MPD 0.18 and older: */
|
||||||
|
param.GetBlockValue("dsd_usb", false);
|
||||||
|
|
||||||
buffer_time = param.GetBlockValue("buffer_time",
|
buffer_time = param.GetBlockValue("buffer_time",
|
||||||
MPD_ALSA_BUFFER_TIME_US);
|
MPD_ALSA_BUFFER_TIME_US);
|
||||||
|
@ -639,34 +640,34 @@ alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||||
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
|
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
|
||||||
Error &error)
|
Error &error)
|
||||||
{
|
{
|
||||||
assert(ad->dsd_usb);
|
assert(ad->dop);
|
||||||
assert(audio_format.format == SampleFormat::DSD);
|
assert(audio_format.format == SampleFormat::DSD);
|
||||||
|
|
||||||
/* pass 24 bit to alsa_setup() */
|
/* pass 24 bit to alsa_setup() */
|
||||||
|
|
||||||
AudioFormat usb_format = audio_format;
|
AudioFormat dop_format = audio_format;
|
||||||
usb_format.format = SampleFormat::S24_P32;
|
dop_format.format = SampleFormat::S24_P32;
|
||||||
usb_format.sample_rate /= 2;
|
dop_format.sample_rate /= 2;
|
||||||
|
|
||||||
const AudioFormat check = usb_format;
|
const AudioFormat check = dop_format;
|
||||||
|
|
||||||
if (!alsa_setup(ad, usb_format, packed_r, reverse_endian_r, error))
|
if (!alsa_setup(ad, dop_format, packed_r, reverse_endian_r, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* if the device allows only 32 bit, shift all DSD-over-USB
|
/* if the device allows only 32 bit, shift all DoP
|
||||||
samples left by 8 bit and leave the lower 8 bit cleared;
|
samples left by 8 bit and leave the lower 8 bit cleared;
|
||||||
the DSD-over-USB documentation does not specify whether
|
the DSD-over-USB documentation does not specify whether
|
||||||
this is legal, but there is anecdotical evidence that this
|
this is legal, but there is anecdotical evidence that this
|
||||||
is possible (and the only option for some devices) */
|
is possible (and the only option for some devices) */
|
||||||
*shift8_r = usb_format.format == SampleFormat::S32;
|
*shift8_r = dop_format.format == SampleFormat::S32;
|
||||||
if (usb_format.format == SampleFormat::S32)
|
if (dop_format.format == SampleFormat::S32)
|
||||||
usb_format.format = SampleFormat::S24_P32;
|
dop_format.format = SampleFormat::S24_P32;
|
||||||
|
|
||||||
if (usb_format != check) {
|
if (dop_format != check) {
|
||||||
/* no bit-perfect playback, which is required
|
/* no bit-perfect playback, which is required
|
||||||
for DSD over USB */
|
for DSD over USB */
|
||||||
error.Format(alsa_output_domain,
|
error.Format(alsa_output_domain,
|
||||||
"Failed to configure DSD-over-USB on ALSA device \"%s\"",
|
"Failed to configure DSD-over-PCM on ALSA device \"%s\"",
|
||||||
alsa_device(ad));
|
alsa_device(ad));
|
||||||
delete[] ad->silence;
|
delete[] ad->silence;
|
||||||
return false;
|
return false;
|
||||||
|
@ -681,9 +682,9 @@ alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||||
{
|
{
|
||||||
bool shift8 = false, packed, reverse_endian;
|
bool shift8 = false, packed, reverse_endian;
|
||||||
|
|
||||||
const bool dsd_usb = ad->dsd_usb &&
|
const bool dop = ad->dop &&
|
||||||
audio_format.format == SampleFormat::DSD;
|
audio_format.format == SampleFormat::DSD;
|
||||||
const bool success = dsd_usb
|
const bool success = dop
|
||||||
? alsa_setup_dsd(ad, audio_format,
|
? alsa_setup_dsd(ad, audio_format,
|
||||||
&shift8, &packed, &reverse_endian,
|
&shift8, &packed, &reverse_endian,
|
||||||
error)
|
error)
|
||||||
|
@ -694,7 +695,7 @@ alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||||
|
|
||||||
ad->pcm_export->Open(audio_format.format,
|
ad->pcm_export->Open(audio_format.format,
|
||||||
audio_format.channels,
|
audio_format.channels,
|
||||||
dsd_usb, shift8, packed, reverse_endian);
|
dop, shift8, packed, reverse_endian);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PcmDsdUsb.hxx"
|
#include "PcmDop.hxx"
|
||||||
#include "PcmBuffer.hxx"
|
#include "PcmBuffer.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
@ -27,20 +27,20 @@
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
pcm_two_dsd_to_usb_marker1(uint8_t a, uint8_t b)
|
pcm_two_dsd_to_dop_marker1(uint8_t a, uint8_t b)
|
||||||
{
|
{
|
||||||
return 0xff050000 | (a << 8) | b;
|
return 0xff050000 | (a << 8) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
pcm_two_dsd_to_usb_marker2(uint8_t a, uint8_t b)
|
pcm_two_dsd_to_dop_marker2(uint8_t a, uint8_t b)
|
||||||
{
|
{
|
||||||
return 0xfffa0000 | (a << 8) | b;
|
return 0xfffa0000 | (a << 8) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint32_t>
|
ConstBuffer<uint32_t>
|
||||||
pcm_dsd_to_usb(PcmBuffer &buffer, unsigned channels,
|
pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels,
|
||||||
ConstBuffer<uint8_t> _src)
|
ConstBuffer<uint8_t> _src)
|
||||||
{
|
{
|
||||||
assert(audio_valid_channel_count(channels));
|
assert(audio_valid_channel_count(channels));
|
||||||
|
@ -65,7 +65,7 @@ pcm_dsd_to_usb(PcmBuffer &buffer, unsigned channels,
|
||||||
/* each 24 bit sample has 16 DSD sample bits
|
/* each 24 bit sample has 16 DSD sample bits
|
||||||
plus the magic 0x05 marker */
|
plus the magic 0x05 marker */
|
||||||
|
|
||||||
*dest++ = pcm_two_dsd_to_usb_marker1(src[0], src[channels]);
|
*dest++ = pcm_two_dsd_to_dop_marker1(src[0], src[channels]);
|
||||||
|
|
||||||
/* seek the source pointer to the next
|
/* seek the source pointer to the next
|
||||||
channel */
|
channel */
|
||||||
|
@ -80,7 +80,7 @@ pcm_dsd_to_usb(PcmBuffer &buffer, unsigned channels,
|
||||||
/* each 24 bit sample has 16 DSD sample bits
|
/* each 24 bit sample has 16 DSD sample bits
|
||||||
plus the magic 0xfa marker */
|
plus the magic 0xfa marker */
|
||||||
|
|
||||||
*dest++ = pcm_two_dsd_to_usb_marker2(src[0], src[channels]);
|
*dest++ = pcm_two_dsd_to_dop_marker2(src[0], src[channels]);
|
||||||
|
|
||||||
/* seek the source pointer to the next
|
/* seek the source pointer to the next
|
||||||
channel */
|
channel */
|
|
@ -17,8 +17,8 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MPD_PCM_DSD_USB_HXX
|
#ifndef MPD_PCM_DOP_HXX
|
||||||
#define MPD_PCM_DSD_USB_HXX
|
#define MPD_PCM_DOP_HXX
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
|
||||||
|
@ -30,12 +30,11 @@ template<typename T> struct ConstBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack DSD 1 bit samples into (padded) 24 bit PCM samples for
|
* Pack DSD 1 bit samples into (padded) 24 bit PCM samples for
|
||||||
* playback over USB, according to the proposed standard by
|
* playback over USB, according to the DoP standard:
|
||||||
* dCS and others:
|
* http://dsd-guide.com/dop-open-standard
|
||||||
* http://www.sonore.us/DoP_openStandard_1v1.pdf
|
|
||||||
*/
|
*/
|
||||||
ConstBuffer<uint32_t>
|
ConstBuffer<uint32_t>
|
||||||
pcm_dsd_to_usb(PcmBuffer &buffer, unsigned channels,
|
pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels,
|
||||||
ConstBuffer<uint8_t> src);
|
ConstBuffer<uint8_t> src);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PcmExport.hxx"
|
#include "PcmExport.hxx"
|
||||||
#include "PcmDsdUsb.hxx"
|
#include "PcmDop.hxx"
|
||||||
#include "PcmPack.hxx"
|
#include "PcmPack.hxx"
|
||||||
#include "util/ByteReverse.hxx"
|
#include "util/ByteReverse.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
@ -28,15 +28,15 @@
|
||||||
|
|
||||||
void
|
void
|
||||||
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
||||||
bool _dsd_usb, bool _shift8, bool _pack, bool _reverse_endian)
|
bool _dop, bool _shift8, bool _pack, bool _reverse_endian)
|
||||||
{
|
{
|
||||||
assert(audio_valid_sample_format(sample_format));
|
assert(audio_valid_sample_format(sample_format));
|
||||||
assert(!_dsd_usb || audio_valid_channel_count(_channels));
|
assert(!_dop || audio_valid_channel_count(_channels));
|
||||||
|
|
||||||
channels = _channels;
|
channels = _channels;
|
||||||
dsd_usb = _dsd_usb && sample_format == SampleFormat::DSD;
|
dop = _dop && sample_format == SampleFormat::DSD;
|
||||||
if (dsd_usb)
|
if (dop)
|
||||||
/* after the conversion to DSD-over-USB, 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;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const
|
||||||
/* packed 24 bit samples (3 bytes per sample) */
|
/* packed 24 bit samples (3 bytes per sample) */
|
||||||
return audio_format.channels * 3;
|
return audio_format.channels * 3;
|
||||||
|
|
||||||
if (dsd_usb)
|
if (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
|
||||||
|
@ -77,8 +77,8 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const
|
||||||
ConstBuffer<void>
|
ConstBuffer<void>
|
||||||
PcmExport::Export(ConstBuffer<void> data)
|
PcmExport::Export(ConstBuffer<void> data)
|
||||||
{
|
{
|
||||||
if (dsd_usb)
|
if (dop)
|
||||||
data = pcm_dsd_to_usb(dsd_buffer, channels,
|
data = pcm_dsd_to_dop(dop_buffer, channels,
|
||||||
ConstBuffer<uint8_t>::FromVoid(data))
|
ConstBuffer<uint8_t>::FromVoid(data))
|
||||||
.ToVoid();
|
.ToVoid();
|
||||||
|
|
||||||
|
@ -125,8 +125,8 @@ PcmExport::CalcSourceSize(size_t size) const
|
||||||
/* 32 bit to 24 bit conversion (4 to 3 bytes) */
|
/* 32 bit to 24 bit conversion (4 to 3 bytes) */
|
||||||
size = (size / 3) * 4;
|
size = (size / 3) * 4;
|
||||||
|
|
||||||
if (dsd_usb)
|
if (dop)
|
||||||
/* DSD over USB doubles the transport size */
|
/* DoP doubles the transport size */
|
||||||
size /= 2;
|
size /= 2;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
|
|
@ -35,11 +35,11 @@ template<typename T> struct ConstBuffer;
|
||||||
struct PcmExport {
|
struct PcmExport {
|
||||||
/**
|
/**
|
||||||
* The buffer is used to convert DSD samples to the
|
* The buffer is used to convert DSD samples to the
|
||||||
* DSD-over-USB format.
|
* DoP format.
|
||||||
*
|
*
|
||||||
* @see #dsd_usb
|
* @see #dop
|
||||||
*/
|
*/
|
||||||
PcmBuffer dsd_buffer;
|
PcmBuffer dop_buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The buffer is used to pack samples, removing padding.
|
* The buffer is used to pack samples, removing padding.
|
||||||
|
@ -61,11 +61,11 @@ struct PcmExport {
|
||||||
uint8_t channels;
|
uint8_t channels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD to DSD-over-USB? Input format must be
|
* Convert DSD to DSD-over-PCM (DoP)? Input format must be
|
||||||
* SampleFormat::DSD and output format must be
|
* SampleFormat::DSD and output format must be
|
||||||
* SampleFormat::S24_P32.
|
* SampleFormat::S24_P32.
|
||||||
*/
|
*/
|
||||||
bool dsd_usb;
|
bool dop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert (padded) 24 bit samples to 32 bit by shifting 8
|
* Convert (padded) 24 bit samples to 32 bit by shifting 8
|
||||||
|
@ -93,10 +93,10 @@ struct PcmExport {
|
||||||
*
|
*
|
||||||
* This function cannot fail.
|
* This function cannot fail.
|
||||||
*
|
*
|
||||||
* @param channels the number of channels; ignored unless dsd_usb is set
|
* @param channels the number of channels; ignored unless dop is set
|
||||||
*/
|
*/
|
||||||
void Open(SampleFormat sample_format, unsigned channels,
|
void Open(SampleFormat sample_format, unsigned channels,
|
||||||
bool dsd_usb, bool shift8, bool pack, bool reverse_endian);
|
bool dop, bool shift8, bool pack, bool reverse_endian);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the size of one output frame.
|
* Calculate the size of one output frame.
|
||||||
|
|
|
@ -108,14 +108,14 @@ class PcmExportTest : public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(TestShift8);
|
CPPUNIT_TEST(TestShift8);
|
||||||
CPPUNIT_TEST(TestPack24);
|
CPPUNIT_TEST(TestPack24);
|
||||||
CPPUNIT_TEST(TestReverseEndian);
|
CPPUNIT_TEST(TestReverseEndian);
|
||||||
CPPUNIT_TEST(TestDsdUsb);
|
CPPUNIT_TEST(TestDop);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void TestShift8();
|
void TestShift8();
|
||||||
void TestPack24();
|
void TestPack24();
|
||||||
void TestReverseEndian();
|
void TestReverseEndian();
|
||||||
void TestDsdUsb();
|
void TestDop();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -106,7 +106,7 @@ PcmExportTest::TestReverseEndian()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PcmExportTest::TestDsdUsb()
|
PcmExportTest::TestDop()
|
||||||
{
|
{
|
||||||
static constexpr uint8_t src[] = {
|
static constexpr uint8_t src[] = {
|
||||||
0x01, 0x23, 0x45, 0x67,
|
0x01, 0x23, 0x45, 0x67,
|
||||||
|
|
Loading…
Reference in New Issue