Attached patch is a *pre* version of v4 of the patch to add support for
DSF files. Fixing the white space warnings was fairly easy after
switching editors and using the supplied git commands.
I changed the struct comments, hopefully now correct (modeled after a
version of a supported doxygen style and also used in other mpd code).
I have a hard time fixing the reported indentation issues, I do like
neat code but with the width limit, my code style and my desire (try) to
use meaningful names I don't succeed in coming up with acceptable
indentation.
Comments and pointers welcome. I'll take a last stab at it.
Jurgen
diff --git a/doc/user.xml b/doc/user.xml
index cd36528..46d9c11 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -782,7 +782,7 @@ systemctl start mpd.socket/programlisting
titlevarnamedsdiff/varname/title
para
- Decodes DFF files containing DSDIFF data (e.g. SACD rips).
+ Decodes DFF and DSF files containing DSDIFF data (e.g. SACD rips).
/para
informaltable
diff --git a/src/decoder/dsdiff_decoder_plugin.c b/src/decoder/dsdiff_decoder_plugin.c
index ae42002..db05ad0 100644
--- a/src/decoder/dsdiff_decoder_plugin.c
+++ b/src/decoder/dsdiff_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * 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
@@ -19,9 +19,12 @@
/* \file
*
- * This plugin decodes DSDIFF data (SACD) embedded in DFF files. It
- * was modeled after the specification found here:
+ * This plugin decodes DSDIFF data (SACD) embedded in DFF and DSF files.
+ * The DFF code was modeled after the specification found here:
* http://www.sonicstudio.com/pdf/dsd/DSDIFF_1.5_Spec.pdf
+ *
+ * The DSF code was created using the specification found here:
+ * http://dsd-guide.com/sonys-dsf-file-format-spec
*/
#include config.h
@@ -53,10 +56,57 @@ struct dsdiff_chunk_header {
struct dsdiff_metadata {
unsigned sample_rate, channels;
+ bool fileisdff;
+ bool bitreverse;
+ uint64_t chunk_size;
};
static bool lsbitfirst;
+
+struct dsdiff_header_dsf {
+ /** DSF header id: DSD */
+ struct dsdiff_id id;
+ /** DSD chunk size, including id = 28 */
+ uint32_t size_low, size_high;
+ /** Total file size */
+ uint32_t fsize_low, fsize_high;
+ /** Pointer to id3v2 metadata, should be at the end of the file */
+ uint32_t pmeta_low, pmeta_high;
+};
+/** DSF file fmt chunk */
+struct dsdiff_dsf_fmt_chunk {
+
+ /** id: fmt */
+ struct dsdiff_id id;
+ /** fmt chunk size, including id, normally 52 */
+ uint32_t size_low, size_high;
+ /** Version of this format = 1 */
+ uint32_t version;
+ /** 0: DSD raw */
+ uint32_t formatid;
+ /** Channel Type, 1 = mono, 2 = stereo, 3 = 3 channels, etc */
+ uint32_t channeltype;
+ /** Channel number, 1 = mono, 2 = stereo, ... 6 = 6 channels */
+ uint32_t channelnum;
+ /** Sample frequency: 2822400, 5644800 */
+ uint32_t sample_freq;
+ /** Bits per sample 1 or 8 */
+ uint32_t bitssample;
+ /** Sample count per channel in bytes */
+ uint32_t scnt_low, scnt_high;
+ /** Block size per channel = 4096 */
+ uint32_t block_size;
+ /** Reserved, should be all zero */
+ uint32_t reserved;
+};
+
+struct dsdiff_dsf_data_chunk {
+ struct dsdiff_id id;
+ /** data chunk size, includes header (id+size) */
+ uint32_t size_low, size_high;
+};
+
static bool
dsdiff_init(const struct config_param *param)
{
@@ -224,7 +274,7 @@ dsdiff_read_prop_snd(struct decoder *decoder, struct input_stream *is,
return false;
if (!dsdiff_id_equals(type, DSD ))
-/* only uincompressed DSD audio data
+/* only uncompressed DSD audio data
is implemented */
return false;
} else {
@@ -274,28 +324,107 @@ dsdiff_read_metadata(struct decoder *decoder, struct input_stream *is,
struct dsdiff_header header;
if (!dsdiff_read(decoder, is, header, sizeof(header)) ||
!dsdiff_id_equals(header.id, FRM8) ||
- !dsdiff_id_equals(header.format, DSD ))
+ !dsdiff_id_equals(header.format, DSD )) {
+
+ /* It's not a DFF file, check if it is a DSF file */
+ if (!dsdiff_skip_to(decoder, is, 0)) /* Reset to beginning
+ of the stream */
+ return false;
+
+ uint64_t chunk_size;
+ struct dsdiff_header_dsf dsfheader;
+ if (!dsdiff_read(decoder, is, dsfheader, sizeof(dsfheader)) ||
+ !dsdiff_id_equals(header.id, DSD ))
+ return false;
+
+ chunk_size = (((uint64_t)GUINT32_FROM_LE(dsfheader.size_high)) 32) |
+ ((uint64_t)GUINT32_FROM_LE(dsfheader.size_low));
+
+ if (sizeof(dsfheader) != chunk_size)
return false;
- while (true) {
- if (!dsdiff_read_chunk_header(decoder, is, chunk_header))
+ /* Read the 'fmt ' chunk of the DSF file */
+ struct dsdiff_dsf_fmt_chunk dsf_fmt_chunk;
+ if (!dsdiff_read(decoder, is, dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) ||
+ !dsdiff_id_equals(dsf_fmt_chunk.id, fmt ))
return false;
- if