From 25164969932590894671895944f30743d344e541 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 1 Mar 2012 00:25:08 +0100
Subject: audio_format: add DSD sample format

Basic support for Direct Stream Digital.  No conversion yet, and no
decoder/output plugin support.
---
 src/audio_format.c              |  6 ++++++
 src/audio_format.h              | 19 +++++++++++++++++++
 src/audio_parser.c              | 12 ++++++++++++
 src/decoder/flac_pcm.c          |  2 ++
 src/output/alsa_output_plugin.c |  2 ++
 src/output/oss_output_plugin.c  |  2 ++
 src/pcm_byteswap.c              |  2 ++
 src/pcm_convert.c               |  2 ++
 src/pcm_format.c                |  8 ++++++++
 src/pcm_mix.c                   |  4 ++++
 src/pcm_volume.c                |  2 ++
 11 files changed, 61 insertions(+)

diff --git a/src/audio_format.c b/src/audio_format.c
index 8c40457ec..c9ee27fa1 100644
--- a/src/audio_format.c
+++ b/src/audio_format.c
@@ -71,6 +71,12 @@ sample_format_to_string(enum sample_format format)
 
 	case SAMPLE_FORMAT_FLOAT:
 		return "f";
+
+	case SAMPLE_FORMAT_DSD:
+		return "dsd";
+
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
+		return "dsdl";
 	}
 
 	/* unreachable */
diff --git a/src/audio_format.h b/src/audio_format.h
index 4f7dbfb1a..2c86b70b9 100644
--- a/src/audio_format.h
+++ b/src/audio_format.h
@@ -49,6 +49,18 @@ enum sample_format {
 	 * range is -1.0f to +1.0f.
 	 */
 	SAMPLE_FORMAT_FLOAT,
+
+	/**
+	 * Direct Stream Digital.  1-bit samples; each frame has one
+	 * byte (8 samples) per channel.
+	 */
+	SAMPLE_FORMAT_DSD,
+
+	/**
+	 * Same as #SAMPLE_FORMAT_DSD, but the least significant bit
+	 * comes first.
+	 */
+	SAMPLE_FORMAT_DSD_LSBFIRST,
 };
 
 static const unsigned MAX_CHANNELS = 8;
@@ -175,6 +187,8 @@ audio_valid_sample_format(enum sample_format format)
 	case SAMPLE_FORMAT_S24_P32:
 	case SAMPLE_FORMAT_S32:
 	case SAMPLE_FORMAT_FLOAT:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		return true;
 
 	case SAMPLE_FORMAT_UNDEFINED:
@@ -251,6 +265,11 @@ sample_format_size(enum sample_format format)
 	case SAMPLE_FORMAT_FLOAT:
 		return 4;
 
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
+		/* each frame has 8 samples per channel */
+		return 1;
+
 	case SAMPLE_FORMAT_UNDEFINED:
 		return 0;
 	}
diff --git a/src/audio_parser.c b/src/audio_parser.c
index 8875239e1..7061e0e00 100644
--- a/src/audio_parser.c
+++ b/src/audio_parser.c
@@ -87,6 +87,18 @@ parse_sample_format(const char *src, bool mask,
 		return true;
 	}
 
+	if (memcmp(src, "dsd", 3) == 0) {
+		if (src[3] == 'l') {
+			*sample_format_r = SAMPLE_FORMAT_DSD_LSBFIRST;
+			*endptr_r = src + 4;
+		} else {
+			*sample_format_r = SAMPLE_FORMAT_DSD;
+			*endptr_r = src + 3;
+		}
+
+		return true;
+	}
+
 	value = strtoul(src, &endptr, 10);
 	if (endptr == src) {
 		g_set_error(error_r, audio_parser_quark(), 0,
diff --git a/src/decoder/flac_pcm.c b/src/decoder/flac_pcm.c
index c479ebfd4..4d35b118e 100644
--- a/src/decoder/flac_pcm.c
+++ b/src/decoder/flac_pcm.c
@@ -103,6 +103,8 @@ flac_convert(void *dest,
 
 	case SAMPLE_FORMAT_S24:
 	case SAMPLE_FORMAT_FLOAT:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 	case SAMPLE_FORMAT_UNDEFINED:
 		/* unreachable */
 		assert(false);
diff --git a/src/output/alsa_output_plugin.c b/src/output/alsa_output_plugin.c
index f939ba5b4..58f73d67d 100644
--- a/src/output/alsa_output_plugin.c
+++ b/src/output/alsa_output_plugin.c
@@ -194,6 +194,8 @@ get_bitformat(enum sample_format sample_format)
 {
 	switch (sample_format) {
 	case SAMPLE_FORMAT_UNDEFINED:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		return SND_PCM_FORMAT_UNKNOWN;
 
 	case SAMPLE_FORMAT_S8:
diff --git a/src/output/oss_output_plugin.c b/src/output/oss_output_plugin.c
index 46505873b..b2b491c9c 100644
--- a/src/output/oss_output_plugin.c
+++ b/src/output/oss_output_plugin.c
@@ -396,6 +396,8 @@ sample_format_to_oss(enum sample_format format)
 	switch (format) {
 	case SAMPLE_FORMAT_UNDEFINED:
 	case SAMPLE_FORMAT_FLOAT:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		return AFMT_QUERY;
 
 	case SAMPLE_FORMAT_S8:
diff --git a/src/pcm_byteswap.c b/src/pcm_byteswap.c
index a1315c475..741c6510f 100644
--- a/src/pcm_byteswap.c
+++ b/src/pcm_byteswap.c
@@ -74,6 +74,8 @@ pcm_byteswap(struct pcm_buffer *buffer, enum sample_format format,
 		return NULL;
 
 	case SAMPLE_FORMAT_S8:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		return src;
 
 	case SAMPLE_FORMAT_S16:
diff --git a/src/pcm_convert.c b/src/pcm_convert.c
index a3b3bb446..0c4e19b9c 100644
--- a/src/pcm_convert.c
+++ b/src/pcm_convert.c
@@ -77,6 +77,8 @@ pcm_convert_channels(struct pcm_buffer *buffer, enum sample_format format,
 	case SAMPLE_FORMAT_S8:
 	case SAMPLE_FORMAT_S24:
 	case SAMPLE_FORMAT_FLOAT:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		g_set_error(error_r, pcm_convert_quark(), 0,
 			    "Channel conversion not implemented for format '%s'",
 			    sample_format_to_string(format));
diff --git a/src/pcm_format.c b/src/pcm_format.c
index a20d8bb8d..c7cf910ed 100644
--- a/src/pcm_format.c
+++ b/src/pcm_format.c
@@ -147,6 +147,8 @@ pcm_convert_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither,
 
 	switch (src_format) {
 	case SAMPLE_FORMAT_UNDEFINED:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		break;
 
 	case SAMPLE_FORMAT_S8:
@@ -265,6 +267,8 @@ pcm_convert_to_24(struct pcm_buffer *buffer,
 
 	switch (src_format) {
 	case SAMPLE_FORMAT_UNDEFINED:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		break;
 
 	case SAMPLE_FORMAT_S8:
@@ -389,6 +393,8 @@ pcm_convert_to_32(struct pcm_buffer *buffer,
 
 	switch (src_format) {
 	case SAMPLE_FORMAT_UNDEFINED:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		break;
 
 	case SAMPLE_FORMAT_S8:
@@ -524,6 +530,8 @@ pcm_convert_to_float(struct pcm_buffer *buffer,
 {
 	switch (src_format) {
 	case SAMPLE_FORMAT_UNDEFINED:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		break;
 
 	case SAMPLE_FORMAT_S8:
diff --git a/src/pcm_mix.c b/src/pcm_mix.c
index 9f76d568f..84bb5526d 100644
--- a/src/pcm_mix.c
+++ b/src/pcm_mix.c
@@ -120,6 +120,8 @@ pcm_add_vol(void *buffer1, const void *buffer2, size_t size,
 	switch (format) {
 	case SAMPLE_FORMAT_UNDEFINED:
 	case SAMPLE_FORMAT_S24:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		/* not implemented */
 		return false;
 
@@ -229,6 +231,8 @@ pcm_add(void *buffer1, const void *buffer2, size_t size,
 	switch (format) {
 	case SAMPLE_FORMAT_UNDEFINED:
 	case SAMPLE_FORMAT_S24:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		/* not implemented */
 		return false;
 
diff --git a/src/pcm_volume.c b/src/pcm_volume.c
index de4bda6c9..d8da570aa 100644
--- a/src/pcm_volume.c
+++ b/src/pcm_volume.c
@@ -159,6 +159,8 @@ pcm_volume(void *buffer, size_t length,
 	switch (format) {
 	case SAMPLE_FORMAT_UNDEFINED:
 	case SAMPLE_FORMAT_S24:
+	case SAMPLE_FORMAT_DSD:
+	case SAMPLE_FORMAT_DSD_LSBFIRST:
 		/* not implemented */
 		return false;
 
-- 
cgit v1.2.3