aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2012-03-01 00:57:33 +0100
committerMax Kellermann <max@duempel.org>2012-03-01 02:00:12 +0100
commitc9c57af5f7995946007a029c1d21f7bc6834f1d0 (patch)
treee9d81bcb9a41142d3703db447f8343e02c8d7adc /src
parent25164969932590894671895944f30743d344e541 (diff)
pcm_convert: support the DSD format
Diffstat (limited to 'src')
-rw-r--r--src/pcm_convert.c27
-rw-r--r--src/pcm_convert.h3
-rw-r--r--src/pcm_dsd.c85
-rw-r--r--src/pcm_dsd.h52
4 files changed, 167 insertions, 0 deletions
diff --git a/src/pcm_convert.c b/src/pcm_convert.c
index 0c4e19b9..62e36899 100644
--- a/src/pcm_convert.c
+++ b/src/pcm_convert.c
@@ -38,6 +38,7 @@ void pcm_convert_init(struct pcm_convert_state *state)
{
memset(state, 0, sizeof(*state));
+ pcm_dsd_init(&state->dsd);
pcm_resample_init(&state->resample);
pcm_dither_24_init(&state->dither);
@@ -49,6 +50,7 @@ void pcm_convert_init(struct pcm_convert_state *state)
void pcm_convert_deinit(struct pcm_convert_state *state)
{
+ pcm_dsd_deinit(&state->dsd);
pcm_resample_deinit(&state->resample);
pcm_buffer_deinit(&state->format_buffer);
@@ -60,6 +62,7 @@ void pcm_convert_deinit(struct pcm_convert_state *state)
void
pcm_convert_reset(struct pcm_convert_state *state)
{
+ pcm_dsd_reset(&state->dsd);
pcm_resample_reset(&state->resample);
}
@@ -403,6 +406,30 @@ pcm_convert(struct pcm_convert_state *state,
}
}
+ struct audio_format float_format;
+ if (src_format->format == SAMPLE_FORMAT_DSD ||
+ src_format->format == SAMPLE_FORMAT_DSD_LSBFIRST) {
+ size_t f_size;
+ const bool lsbfirst =
+ src_format->format == SAMPLE_FORMAT_DSD_LSBFIRST;
+ const float *f = pcm_dsd_to_float(&state->dsd,
+ src_format->channels,
+ lsbfirst, src, src_size,
+ &f_size);
+ if (f == NULL) {
+ g_set_error_literal(error_r, pcm_convert_quark(), 0,
+ "DSD to PCM conversion failed");
+ return NULL;
+ }
+
+ float_format = *src_format;
+ float_format.format = SAMPLE_FORMAT_FLOAT;
+
+ src_format = &float_format;
+ src = f;
+ src_size = f_size;
+ }
+
switch (dest_format->format) {
case SAMPLE_FORMAT_S16:
return pcm_convert_16(state,
diff --git a/src/pcm_convert.h b/src/pcm_convert.h
index 41a9f938..0a0f8568 100644
--- a/src/pcm_convert.h
+++ b/src/pcm_convert.h
@@ -20,6 +20,7 @@
#ifndef PCM_CONVERT_H
#define PCM_CONVERT_H
+#include "pcm_dsd.h"
#include "pcm_resample.h"
#include "pcm_dither.h"
#include "pcm_buffer.h"
@@ -32,6 +33,8 @@ struct audio_format;
* conversions.
*/
struct pcm_convert_state {
+ struct pcm_dsd dsd;
+
struct pcm_resample_state resample;
struct pcm_dither dither;
diff --git a/src/pcm_dsd.c b/src/pcm_dsd.c
new file mode 100644
index 00000000..76266b4c
--- /dev/null
+++ b/src/pcm_dsd.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "pcm_dsd.h"
+#include "dsd2pcm/dsd2pcm.h"
+
+#include <glib.h>
+#include <string.h>
+
+void
+pcm_dsd_init(struct pcm_dsd *dsd)
+{
+ pcm_buffer_init(&dsd->buffer);
+
+ memset(dsd->dsd2pcm, 0, sizeof(dsd->dsd2pcm));
+}
+
+void
+pcm_dsd_deinit(struct pcm_dsd *dsd)
+{
+ pcm_buffer_deinit(&dsd->buffer);
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(dsd->dsd2pcm); ++i)
+ if (dsd->dsd2pcm[i] != NULL)
+ dsd2pcm_destroy(dsd->dsd2pcm[i]);
+}
+
+void
+pcm_dsd_reset(struct pcm_dsd *dsd)
+{
+ for (unsigned i = 0; i < G_N_ELEMENTS(dsd->dsd2pcm); ++i)
+ if (dsd->dsd2pcm[i] != NULL)
+ dsd2pcm_reset(dsd->dsd2pcm[i]);
+}
+
+const float *
+pcm_dsd_to_float(struct pcm_dsd *dsd, unsigned channels, bool lsbfirst,
+ const uint8_t *src, size_t src_size,
+ size_t *dest_size_r)
+{
+ assert(dsd != NULL);
+ assert(src != NULL);
+ assert(src_size > 0);
+ assert(src_size % channels == 0);
+ assert(channels <= G_N_ELEMENTS(dsd->dsd2pcm));
+
+ const unsigned num_samples = src_size;
+ const unsigned num_frames = src_size / channels;
+
+ float *dest;
+ const size_t dest_size = num_samples * sizeof(*dest);
+ *dest_size_r = dest_size;
+ dest = pcm_buffer_get(&dsd->buffer, dest_size);
+
+ for (unsigned c = 0; c < channels; ++c) {
+ if (dsd->dsd2pcm[c] == NULL) {
+ dsd->dsd2pcm[c] = dsd2pcm_init();
+ if (dsd->dsd2pcm[c] == NULL)
+ return NULL;
+ }
+
+ dsd2pcm_translate(dsd->dsd2pcm[c], num_frames,
+ src + c, channels,
+ lsbfirst, dest + c, channels);
+ }
+
+ return dest;
+}
diff --git a/src/pcm_dsd.h b/src/pcm_dsd.h
new file mode 100644
index 00000000..85c2455a
--- /dev/null
+++ b/src/pcm_dsd.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PCM_DSD_H
+#define MPD_PCM_DSD_H
+
+#include "check.h"
+#include "pcm_buffer.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * Wrapper for the dsd2pcm library.
+ */
+struct pcm_dsd {
+ struct pcm_buffer buffer;
+
+ struct dsd2pcm_ctx_s *dsd2pcm[32];
+};
+
+void
+pcm_dsd_init(struct pcm_dsd *dsd);
+
+void
+pcm_dsd_deinit(struct pcm_dsd *dsd);
+
+void
+pcm_dsd_reset(struct pcm_dsd *dsd);
+
+const float *
+pcm_dsd_to_float(struct pcm_dsd *dsd, unsigned channels, bool lsbfirst,
+ const uint8_t *src, size_t src_size,
+ size_t *dest_size_r);
+
+#endif