aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2012-03-27 01:01:16 +0200
committerMax Kellermann <max@duempel.org>2012-03-27 01:22:50 +0200
commitddd4f675a2d42b0c8156e03bf3e93f39df2fe609 (patch)
tree248c44242b11e721eeb03fcb74c601fd12fdec39 /src
parentd271dd2cce79d1473f43f7ad7e6815b74617dfe3 (diff)
downloadmpd-ddd4f675a2d42b0c8156e03bf3e93f39df2fe609.tar.gz
mpd-ddd4f675a2d42b0c8156e03bf3e93f39df2fe609.tar.xz
mpd-ddd4f675a2d42b0c8156e03bf3e93f39df2fe609.zip
pcm_export: implement 24 to 32 bit conversion
For 32 bit DSD-over-USB support.
Diffstat (limited to 'src')
-rw-r--r--src/output/alsa_output_plugin.c2
-rw-r--r--src/output/oss_output_plugin.c2
-rw-r--r--src/pcm_export.c18
-rw-r--r--src/pcm_export.h8
4 files changed, 26 insertions, 4 deletions
diff --git a/src/output/alsa_output_plugin.c b/src/output/alsa_output_plugin.c
index 00ddbfb5c..c9dd1ee1b 100644
--- a/src/output/alsa_output_plugin.c
+++ b/src/output/alsa_output_plugin.c
@@ -634,7 +634,7 @@ alsa_setup_or_dsd(struct alsa_data *ad, struct audio_format *audio_format,
pcm_export_open(&ad->export,
audio_format->format, audio_format->channels,
- dsd_usb, packed, reverse_endian);
+ dsd_usb, false, packed, reverse_endian);
return true;
}
diff --git a/src/output/oss_output_plugin.c b/src/output/oss_output_plugin.c
index 85bdc37dc..f59ee3b92 100644
--- a/src/output/oss_output_plugin.c
+++ b/src/output/oss_output_plugin.c
@@ -540,7 +540,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
*oss_format_r = oss_format;
#ifdef AFMT_S24_PACKED
- pcm_export_open(export, sample_format, 0, false,
+ pcm_export_open(export, sample_format, 0, false, false,
oss_format == AFMT_S24_PACKED,
oss_format == AFMT_S24_PACKED &&
G_BYTE_ORDER != G_LITTLE_ENDIAN);
diff --git a/src/pcm_export.c b/src/pcm_export.c
index 66ed6d351..dbd9f2e8e 100644
--- a/src/pcm_export.c
+++ b/src/pcm_export.c
@@ -41,7 +41,7 @@ void pcm_export_deinit(struct pcm_export_state *state)
void
pcm_export_open(struct pcm_export_state *state,
enum sample_format sample_format, unsigned channels,
- bool dsd_usb, bool pack, bool reverse_endian)
+ bool dsd_usb, bool shift8, bool pack, bool reverse_endian)
{
assert(audio_valid_sample_format(sample_format));
assert(!dsd_usb || audio_valid_channel_count(channels));
@@ -53,8 +53,11 @@ pcm_export_open(struct pcm_export_state *state,
samples are stuffed inside fake 24 bit samples */
sample_format = SAMPLE_FORMAT_S24_P32;
+ state->shift8 = shift8 && sample_format == SAMPLE_FORMAT_S24_P32;
state->pack24 = pack && (sample_format == SAMPLE_FORMAT_S24_P32 || sample_format == SAMPLE_FORMAT_DSD_OVER_USB);
+ assert(!state->shift8 || !state->pack24);
+
state->reverse_endian = 0;
if (reverse_endian) {
size_t sample_size = state->pack24
@@ -90,8 +93,21 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size,
data = dest;
size = dest_size;
+ } else if (state->shift8) {
+ assert(size % 4 == 0);
+
+ const uint8_t *src8 = data, *src_end8 = src8 + size;
+ const uint32_t *src = (const uint32_t *)src8;
+ const uint32_t *const src_end = (const uint32_t *)src_end8;
+
+ uint32_t *dest = pcm_buffer_get(&state->pack_buffer, size);
+ data = dest;
+
+ while (src < src_end)
+ *dest++ = *src++ << 8;
}
+
if (state->reverse_endian > 0) {
assert(state->reverse_endian >= 2);
diff --git a/src/pcm_export.h b/src/pcm_export.h
index c132c7169..418dcdfa3 100644
--- a/src/pcm_export.h
+++ b/src/pcm_export.h
@@ -69,6 +69,12 @@ struct pcm_export_state {
bool dsd_usb;
/**
+ * Convert (padded) 24 bit samples to 32 bit by shifting 8
+ * bits to the left?
+ */
+ bool shift8;
+
+ /**
* Pack 24 bit samples?
*/
bool pack24;
@@ -106,7 +112,7 @@ pcm_export_deinit(struct pcm_export_state *state);
void
pcm_export_open(struct pcm_export_state *state,
enum sample_format sample_format, unsigned channels,
- bool dsd_usb, bool pack, bool reverse_endian);
+ bool dsd_usb, bool shift8, bool pack, bool reverse_endian);
/**
* Export a PCM buffer.