[alsa-devel] [PATCH 1/2] ALSA: add DSD formats
This patch adds two formats for Direct Stream Digital (DSD), a pulse-density encoding format which is described here: https://en.wikipedia.org/wiki/Direct_Stream_Digital
DSD operates on 2.8, 5.6 or 11.2MHz sample rates and as a 1-bit stream. In order to provide a compatibility way for pushing DSD samples through ordinary PCM channels, the "DoP open Standard" was invented. See http://www.dsd-guide.com for a copy of the documentation.
The two new types added by this patch describe streams that are capable of handling DSD samples in DOP format as 8-bit or in 16-bit (or at a x8 or x16 data rate, respectively).
DSD itself specifies samples in *bit*, while DOP and ALSA handle them as *bytes*. Hence, a factor of 8 or 16 has to be applied for the sample rare configuration, according to the following table:
configured hardware 352.8kHz 705.6KHz 1411.2KHz <---- sample rate
8-bit 2.8MHz 5.6MHz 11.2MHz 16-bit 5.6MHz 11.2MHz
`-----------------------------------' actual DSD sample rates
Signed-off-by: Daniel Mack zonque@gmail.com --- include/sound/pcm.h | 2 ++ include/uapi/sound/asound.h | 4 +++- sound/core/pcm.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index aa7b0a8..d957046 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -181,6 +181,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B) #define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40) #define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U8 _SNDRV_PCM_FMTBIT(DSD_DOP_U8) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U16 _SNDRV_PCM_FMTBIT(DSD_DOP_U16)
#ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1774a5c..eb9eda8 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ #define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B +#define SNDRV_PCM_FORMAT_DSD_DOP_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD DOP format (x8) */ +#define SNDRV_PCM_FORMAT_DSD_DOP_U16 ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD DOP format (x16) */ +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_DOP_U16
#ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 578327e..578a761 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -209,6 +209,8 @@ static char *snd_pcm_format_names[] = { FORMAT(G723_24_1B), FORMAT(G723_40), FORMAT(G723_40_1B), + FORMAT(DSD_DOP_U8), + FORMAT(DSD_DOP_U16), };
const char *snd_pcm_format_name(snd_pcm_format_t format)
Unfortunately, none of the UAC standards provides a way to identify DSD (Direct Stream Digital) formats. Hence, this patch adds a quirks handler to identify USB interfaces that are capable of handling DSD.
That quirks handler can augment the already parsed formats bit-field, typically by any of the new SNDRV_PCM_FMTBIT_DSD_DOP_{U8_U16}, and it currently does so for USB devices matching the 'Playback Design' vendor id.
Signed-off-by: Daniel Mack zonque@gmail.com --- sound/usb/format.c | 3 +++ sound/usb/quirks.c | 23 +++++++++++++++++++++++ sound/usb/quirks.h | 4 ++++ 3 files changed, 30 insertions(+)
diff --git a/sound/usb/format.c b/sound/usb/format.c index a695caf..a73d67a 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -136,6 +136,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n", chip->dev->devnum, fp->iface, fp->altsetting, format); } + + pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes); + return pcm_formats; }
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a2ac004..2fcc984 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -905,3 +905,26 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, mdelay(20); }
+/* + * snd_usb_interface_dsd_format_quirks() is called from format.c to + * augment the PCM format bit-field for DSD types. The UAC standards + * don't have a designated bit field to denote DSD-capable interfaces, + * hence all hardware that is known to support this format has to be + * listed here. + */ +u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + struct audioformat *fp, + unsigned int sample_bytes) +{ + if ((le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) && + fp->altsetting > 1) { + switch (sample_bytes) { + case 1: + return SNDRV_PCM_FMTBIT_DSD_DOP_U8; + case 2: + return SNDRV_PCM_FMTBIT_DSD_DOP_U16; + } + } + + return 0; +} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..f10d00e 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -30,4 +30,8 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + struct audioformat *fp, + unsigned int sample_bytes); + #endif /* __USBAUDIO_QUIRKS_H */
Unfortunately, none of the UAC standards provides a way to identify DSD (Direct Stream Digital) formats. Hence, this patch adds a quirks handler to identify USB interfaces that are capable of handling DSD.
That quirks handler can augment the already parsed formats bit-field, typically by any of the new SNDRV_PCM_FMTBIT_DSD_DOP_{U8_U16}, and it currently does so for USB devices matching the 'Playback Design' vendor id.
Signed-off-by: Daniel Mack zonque@gmail.com --- sound/usb/format.c | 3 +++ sound/usb/quirks.c | 23 +++++++++++++++++++++++ sound/usb/quirks.h | 4 ++++ 3 files changed, 30 insertions(+)
diff --git a/sound/usb/format.c b/sound/usb/format.c index a695caf..a73d67a 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -136,6 +136,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n", chip->dev->devnum, fp->iface, fp->altsetting, format); } + + pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes); + return pcm_formats; }
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a2ac004..2fcc984 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -905,3 +905,26 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, mdelay(20); }
+/* + * snd_usb_interface_dsd_format_quirks() is called from format.c to + * augment the PCM format bit-field for DSD types. The UAC standards + * don't have a designated bit field to denote DSD-capable interfaces, + * hence all hardware that is known to support this format has to be + * listed here. + */ +u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + struct audioformat *fp, + unsigned int sample_bytes) +{ + if ((le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) && + fp->altsetting > 1) { + switch (sample_bytes) { + case 1: + return SNDRV_PCM_FMTBIT_DSD_DOP_U8; + case 2: + return SNDRV_PCM_FMTBIT_DSD_DOP_U16; + } + } + + return 0; +} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..f10d00e 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -30,4 +30,8 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + struct audioformat *fp, + unsigned int sample_bytes); + #endif /* __USBAUDIO_QUIRKS_H */
On 06.04.2013 13:44, Daniel Mack wrote:
Unfortunately, none of the UAC standards provides a way to identify DSD (Direct Stream Digital) formats. Hence, this patch adds a quirks handler to identify USB interfaces that are capable of handling DSD.
That quirks handler can augment the already parsed formats bit-field, typically by any of the new SNDRV_PCM_FMTBIT_DSD_DOP_{U8_U16}, and it currently does so for USB devices matching the 'Playback Design' vendor id.
Sorry - this identical message got sent twice unintentionally. Please ignore one of the two ...
Daniel
Signed-off-by: Daniel Mack zonque@gmail.com
sound/usb/format.c | 3 +++ sound/usb/quirks.c | 23 +++++++++++++++++++++++ sound/usb/quirks.h | 4 ++++ 3 files changed, 30 insertions(+)
diff --git a/sound/usb/format.c b/sound/usb/format.c index a695caf..a73d67a 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -136,6 +136,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n", chip->dev->devnum, fp->iface, fp->altsetting, format); }
- pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);
- return pcm_formats;
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a2ac004..2fcc984 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -905,3 +905,26 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, mdelay(20); }
+/*
- snd_usb_interface_dsd_format_quirks() is called from format.c to
- augment the PCM format bit-field for DSD types. The UAC standards
- don't have a designated bit field to denote DSD-capable interfaces,
- hence all hardware that is known to support this format has to be
- listed here.
- */
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes)
+{
- if ((le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) &&
fp->altsetting > 1) {
switch (sample_bytes) {
case 1:
return SNDRV_PCM_FMTBIT_DSD_DOP_U8;
case 2:
return SNDRV_PCM_FMTBIT_DSD_DOP_U16;
}
- }
- return 0;
+} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..f10d00e 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -30,4 +30,8 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
+u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes);
#endif /* __USBAUDIO_QUIRKS_H */
On 04/06/2013 02:44 PM, Daniel Mack wrote:
+#define SNDRV_PCM_FMTBIT_DSD_DOP_U8 _SNDRV_PCM_FMTBIT(DSD_DOP_U8) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U16 _SNDRV_PCM_FMTBIT(DSD_DOP_U16)
No, this is not good, DoP always has the 8-bit marker in the MSB and has to be either 24-bit or longer word. One byte marker and two bytes of payload, padded with one byte of zeros if payload is 32-bit dword.
On 06.04.2013 19:53, Jussi Laako wrote:
On 04/06/2013 02:44 PM, Daniel Mack wrote:
+#define SNDRV_PCM_FMTBIT_DSD_DOP_U8 _SNDRV_PCM_FMTBIT(DSD_DOP_U8) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U16 _SNDRV_PCM_FMTBIT(DSD_DOP_U16)
No, this is not good, DoP always has the 8-bit marker in the MSB and has to be either 24-bit or longer word. One byte marker and two bytes of payload, padded with one byte of zeros if payload is 32-bit dword.
Well, the idea was to denote the fact that transport goes in multiple of 8 or 16 bits, which can then be interpreted by the calculation of the actual sample rate. But I'm fine with anything else. What name would you pick, assuming that you're fine with the general approach?
Thanks, Daniel
On 04/06/2013 08:59 PM, Daniel Mack wrote:
On 06.04.2013 19:53, Jussi Laako wrote:
On 04/06/2013 02:44 PM, Daniel Mack wrote:
+#define SNDRV_PCM_FMTBIT_DSD_DOP_U8 _SNDRV_PCM_FMTBIT(DSD_DOP_U8) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U16 _SNDRV_PCM_FMTBIT(DSD_DOP_U16)
Well, the idea was to denote the fact that transport goes in multiple of 8 or 16 bits, which can then be interpreted by the calculation of the actual sample rate. But I'm fine with anything else. What name would you pick, assuming that you're fine with the general approach?
I would just leave out the DOP part and call it SNDRV_PCM_FMTBIT_DSD_U8 (8 DSD samples per unit) and SDNRV_PCM_FMTBIT_DSD_U16 (16 DSD samples per unit). This way it is agnostic to the fact if driver actually implements DoP or something else when talking to the actual hardware. It assumes all the bits in the unit to be valid DSD samples without any DoP marker byte stuff. If driver implements DoP inside, it shouldn't be visible outside. If application implements DoP it will anyway pick a traditional PCM sample format for the purpose.
It could also have SNDRV_PCM_FMTBIT_DSD_U32 which is suitable for PCI/PCIe and many USB cases. Helps on alignment requirements...
For example SNDRV_PCM_FMTBIT_DSD_U8 and ALSA sample rate of 352800 -> DSD sample rate of 2822400. Or SDNRV_PCM_FMTBIT_DSD_U16 and 176400 -> DSD sample rate of 2822400.
- Jussi
On 04/06/2013 02:44 PM, Daniel Mack wrote:
configured hardware 352.8kHz 705.6KHz 1411.2KHz <---- sample rate
8-bit 2.8MHz 5.6MHz 11.2MHz 16-bit 5.6MHz 11.2MHz
`-----------------------------------' actual DSD sample rates
This looks fine, I would just put a comment somewhere like "oldest bit is in LSB" or "oldest bit is in MSB". Then for the U16 rest is about question of byte endianess for hw vs sw...
Of course, from decoding point of view oldest-in-LSB is easiest since it becomes just "y = x & 1; x >>= 1;" loop, while for encoding oldest-in-MSB is easiest since it's "x |= y; x <<= 1;"
At Sat, 6 Apr 2013 13:44:51 +0200, Daniel Mack wrote:
This patch adds two formats for Direct Stream Digital (DSD), a pulse-density encoding format which is described here: https://en.wikipedia.org/wiki/Direct_Stream_Digital
DSD operates on 2.8, 5.6 or 11.2MHz sample rates and as a 1-bit stream. In order to provide a compatibility way for pushing DSD samples through ordinary PCM channels, the "DoP open Standard" was invented. See http://www.dsd-guide.com for a copy of the documentation.
The two new types added by this patch describe streams that are capable of handling DSD samples in DOP format as 8-bit or in 16-bit (or at a x8 or x16 data rate, respectively).
DSD itself specifies samples in *bit*, while DOP and ALSA handle them as *bytes*. Hence, a factor of 8 or 16 has to be applied for the sample rare configuration, according to the following table:
configured hardware 352.8kHz 705.6KHz 1411.2KHz <---- sample rate
8-bit 2.8MHz 5.6MHz 11.2MHz 16-bit 5.6MHz 11.2MHz
`-----------------------------------' actual DSD sample rates
Signed-off-by: Daniel Mack zonque@gmail.com
include/sound/pcm.h | 2 ++ include/uapi/sound/asound.h | 4 +++- sound/core/pcm.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index aa7b0a8..d957046 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -181,6 +181,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B) #define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40) #define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U8 _SNDRV_PCM_FMTBIT(DSD_DOP_U8) +#define SNDRV_PCM_FMTBIT_DSD_DOP_U16 _SNDRV_PCM_FMTBIT(DSD_DOP_U16)
#ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1774a5c..eb9eda8 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ #define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B +#define SNDRV_PCM_FORMAT_DSD_DOP_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD DOP format (x8) */ +#define SNDRV_PCM_FORMAT_DSD_DOP_U16 ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD DOP format (x16) */
What about endianess? I suppose it's limited only to little-endian? If so, write it clearly in comments.
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_DOP_U16
#ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 578327e..578a761 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -209,6 +209,8 @@ static char *snd_pcm_format_names[] = { FORMAT(G723_24_1B), FORMAT(G723_40), FORMAT(G723_40_1B),
- FORMAT(DSD_DOP_U8),
- FORMAT(DSD_DOP_U16),
};
const char *snd_pcm_format_name(snd_pcm_format_t format)
Please update pcm_formats[] table in soud/core/pcm_misc.c, too.
thanks,
Takashi
participants (3)
-
Daniel Mack
-
Jussi Laako
-
Takashi Iwai